2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, version 3 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this program. If not, see
16 # <http://www.gnu.org/licenses/>.
19 from copy import deepcopy
20 from datetime import datetime
21 from importlib import import_module
22 from string import ascii_letters
23 from string import digits
24 from string import printable
25 from string import whitespace
27 from unittest import TestCase
29 from hypothesis import assume
30 from hypothesis import given
31 from hypothesis import settings
32 from hypothesis.strategies import binary
33 from hypothesis.strategies import booleans
34 from hypothesis.strategies import composite
35 from hypothesis.strategies import data as data_strategy
36 from hypothesis.strategies import datetimes
37 from hypothesis.strategies import dictionaries
38 from hypothesis.strategies import integers
39 from hypothesis.strategies import just
40 from hypothesis.strategies import lists
41 from hypothesis.strategies import none
42 from hypothesis.strategies import one_of
43 from hypothesis.strategies import permutations
44 from hypothesis.strategies import sampled_from
45 from hypothesis.strategies import sets
46 from hypothesis.strategies import text
47 from hypothesis.strategies import tuples
48 from six import assertRaisesRegex
49 from six import binary_type
50 from six import byte2int
51 from six import indexbytes
52 from six import int2byte
53 from six import iterbytes
55 from six import text_type
56 from six import unichr as six_unichr
57 from six.moves.cPickle import dumps as pickle_dumps
58 from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto
59 from six.moves.cPickle import loads as pickle_loads
61 from pyderasn import _pp
62 from pyderasn import abs_decode_path
63 from pyderasn import Any
64 from pyderasn import BitString
65 from pyderasn import BMPString
66 from pyderasn import Boolean
67 from pyderasn import BoundsError
68 from pyderasn import Choice
69 from pyderasn import DecodeError
70 from pyderasn import DecodePathDefBy
71 from pyderasn import Enumerated
72 from pyderasn import EOC
73 from pyderasn import EOC_LEN
74 from pyderasn import ExceedingData
75 from pyderasn import GeneralizedTime
76 from pyderasn import GeneralString
77 from pyderasn import GraphicString
78 from pyderasn import hexdec
79 from pyderasn import hexenc
80 from pyderasn import IA5String
81 from pyderasn import Integer
82 from pyderasn import InvalidLength
83 from pyderasn import InvalidOID
84 from pyderasn import InvalidValueType
85 from pyderasn import len_decode
86 from pyderasn import len_encode
87 from pyderasn import LEN_YYMMDDHHMMSSZ
88 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
89 from pyderasn import LEN_YYYYMMDDHHMMSSZ
90 from pyderasn import LENINDEF
91 from pyderasn import LenIndefForm
92 from pyderasn import NotEnoughData
93 from pyderasn import Null
94 from pyderasn import NumericString
95 from pyderasn import ObjectIdentifier
96 from pyderasn import ObjNotReady
97 from pyderasn import ObjUnknown
98 from pyderasn import OctetString
99 from pyderasn import pp_console_row
100 from pyderasn import pprint
101 from pyderasn import PrintableString
102 from pyderasn import Sequence
103 from pyderasn import SequenceOf
104 from pyderasn import Set
105 from pyderasn import SetOf
106 from pyderasn import tag_ctxc
107 from pyderasn import tag_ctxp
108 from pyderasn import tag_decode
109 from pyderasn import tag_encode
110 from pyderasn import tag_strip
111 from pyderasn import TagClassApplication
112 from pyderasn import TagClassContext
113 from pyderasn import TagClassPrivate
114 from pyderasn import TagClassUniversal
115 from pyderasn import TagFormConstructed
116 from pyderasn import TagFormPrimitive
117 from pyderasn import TagMismatch
118 from pyderasn import TeletexString
119 from pyderasn import UniversalString
120 from pyderasn import UTCTime
121 from pyderasn import UTF8String
122 from pyderasn import VideotexString
123 from pyderasn import VisibleString
126 settings.register_profile("local", settings(
129 settings.load_profile("local")
130 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
132 tag_classes = sampled_from((
138 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
139 decode_path_strat = lists(integers(), max_size=3).map(
140 lambda decode_path: tuple(str(dp) for dp in decode_path)
142 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
145 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
147 self_module = import_module(__name__)
150 def register_class(klass):
151 klassname = klass.__name__ + str(time()).replace(".", "")
152 klass.__name__ = klassname
153 klass.__qualname__ = klassname
154 setattr(self_module, klassname, klass)
157 def assert_exceeding_data(self, call, junk):
159 with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)):
163 class TestHex(TestCase):
165 def test_symmetric(self, data):
166 self.assertEqual(hexdec(hexenc(data)), data)
169 class TestTagCoder(TestCase):
170 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
174 integers(min_value=0, max_value=30),
177 def test_short(self, klass, form, num, junk):
178 raw = tag_encode(klass=klass, form=form, num=num)
179 self.assertEqual(tag_decode(raw), (klass, form, num))
180 self.assertEqual(len(raw), 1)
182 byte2int(tag_encode(klass=klass, form=form, num=0)),
183 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
185 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
186 self.assertSequenceEqual(stripped.tobytes(), raw)
187 self.assertEqual(tlen, len(raw))
188 self.assertSequenceEqual(tail, junk)
190 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
194 integers(min_value=31),
197 def test_long(self, klass, form, num, junk):
198 raw = tag_encode(klass=klass, form=form, num=num)
199 self.assertEqual(tag_decode(raw), (klass, form, num))
200 self.assertGreater(len(raw), 1)
202 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
205 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
206 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
207 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
208 self.assertSequenceEqual(stripped.tobytes(), raw)
209 self.assertEqual(tlen, len(raw))
210 self.assertSequenceEqual(tail, junk)
212 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
213 @given(integers(min_value=31))
214 def test_unfinished_tag(self, num):
215 raw = bytearray(tag_encode(num=num))
216 for i in range(1, len(raw)):
218 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
219 tag_strip(bytes(raw))
221 def test_go_vectors_valid(self):
222 for data, (eklass, etag, elen, eform) in (
223 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
224 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
225 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
226 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
227 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
228 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
229 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
230 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
231 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
232 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
234 tag, _, len_encoded = tag_strip(memoryview(data))
235 klass, form, num = tag_decode(tag)
236 _len, _, tail = len_decode(len_encoded)
237 self.assertSequenceEqual(tail, b"")
238 self.assertEqual(klass, eklass)
239 self.assertEqual(num, etag)
240 self.assertEqual(_len, elen)
241 self.assertEqual(form, eform)
243 def test_go_vectors_invalid(self):
251 with self.assertRaises(DecodeError):
252 _, _, len_encoded = tag_strip(memoryview(data))
253 len_decode(len_encoded)
256 integers(min_value=0, max_value=127),
257 integers(min_value=0, max_value=2),
259 def test_long_instead_of_short(self, l, dummy_num):
260 octets = (b"\x00" * dummy_num) + int2byte(l)
261 octets = int2byte((dummy_num + 1) | 0x80) + octets
262 with self.assertRaises(DecodeError):
266 class TestLenCoder(TestCase):
267 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
269 integers(min_value=0, max_value=127),
272 def test_short(self, l, junk):
273 raw = len_encode(l) + junk
274 decoded, llen, tail = len_decode(memoryview(raw))
275 self.assertEqual(decoded, l)
276 self.assertEqual(llen, 1)
277 self.assertEqual(len(raw), 1 + len(junk))
278 self.assertEqual(tail.tobytes(), junk)
280 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
282 integers(min_value=128),
285 def test_long(self, l, junk):
286 raw = len_encode(l) + junk
287 decoded, llen, tail = len_decode(memoryview(raw))
288 self.assertEqual(decoded, l)
289 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
290 self.assertEqual(llen, len(raw) - len(junk))
291 self.assertNotEqual(indexbytes(raw, 1), 0)
292 self.assertSequenceEqual(tail.tobytes(), junk)
294 def test_empty(self):
295 with self.assertRaises(NotEnoughData):
298 @given(integers(min_value=128))
299 def test_stripped(self, _len):
300 with self.assertRaises(NotEnoughData):
301 len_decode(len_encode(_len)[:-1])
304 text_printable = text(alphabet=printable, min_size=1)
308 def text_letters(draw):
309 result = draw(text(alphabet=ascii_letters, min_size=1))
311 result = result.encode("ascii")
315 class CommonMixin(object):
316 def test_tag_default(self):
317 obj = self.base_klass()
318 self.assertEqual(obj.tag, obj.tag_default)
320 def test_simultaneous_impl_expl(self):
321 with self.assertRaises(ValueError):
322 self.base_klass(impl=b"whatever", expl=b"whenever")
324 @given(binary(min_size=1), integers(), integers(), integers())
325 def test_decoded(self, impl, offset, llen, vlen):
326 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
327 self.assertEqual(obj.offset, offset)
328 self.assertEqual(obj.llen, llen)
329 self.assertEqual(obj.vlen, vlen)
330 self.assertEqual(obj.tlen, len(impl))
331 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
333 @given(binary(min_size=1))
334 def test_impl_inherited(self, impl_tag):
335 class Inherited(self.base_klass):
338 self.assertSequenceEqual(obj.impl, impl_tag)
339 self.assertFalse(obj.expled)
342 def test_expl_inherited(self, expl_tag):
343 class Inherited(self.base_klass):
346 self.assertSequenceEqual(obj.expl, expl_tag)
347 self.assertTrue(obj.expled)
349 def assert_copied_basic_fields(self, obj, obj_copied):
350 self.assertEqual(obj, obj_copied)
351 self.assertSequenceEqual(obj.tag, obj_copied.tag)
352 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
353 self.assertEqual(obj.default, obj_copied.default)
354 self.assertEqual(obj.optional, obj_copied.optional)
355 self.assertEqual(obj.offset, obj_copied.offset)
356 self.assertEqual(obj.llen, obj_copied.llen)
357 self.assertEqual(obj.vlen, obj_copied.vlen)
361 def boolean_values_strategy(draw, do_expl=False):
362 value = draw(one_of(none(), booleans()))
366 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
368 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
369 default = draw(one_of(none(), booleans()))
370 optional = draw(one_of(none(), booleans()))
372 draw(integers(min_value=0)),
373 draw(integers(min_value=0)),
374 draw(integers(min_value=0)),
376 return (value, impl, expl, default, optional, _decoded)
379 class BooleanInherited(Boolean):
383 class TestBoolean(CommonMixin, TestCase):
386 def test_invalid_value_type(self):
387 with self.assertRaises(InvalidValueType) as err:
392 def test_optional(self, optional):
393 obj = Boolean(default=Boolean(False), optional=optional)
394 self.assertTrue(obj.optional)
397 def test_ready(self, value):
399 self.assertFalse(obj.ready)
402 pprint(obj, big_blobs=True, with_decode_path=True)
403 with self.assertRaises(ObjNotReady) as err:
407 self.assertTrue(obj.ready)
410 pprint(obj, big_blobs=True, with_decode_path=True)
412 @given(booleans(), booleans(), binary(), binary())
413 def test_comparison(self, value1, value2, tag1, tag2):
414 for klass in (Boolean, BooleanInherited):
417 self.assertEqual(obj1 == obj2, value1 == value2)
418 self.assertEqual(obj1 != obj2, value1 != value2)
419 self.assertEqual(obj1 == bool(obj2), value1 == value2)
420 obj1 = klass(value1, impl=tag1)
421 obj2 = klass(value1, impl=tag2)
422 self.assertEqual(obj1 == obj2, tag1 == tag2)
423 self.assertEqual(obj1 != obj2, tag1 != tag2)
425 @given(data_strategy())
426 def test_call(self, d):
427 for klass in (Boolean, BooleanInherited):
435 ) = d.draw(boolean_values_strategy())
441 optional_initial or False,
451 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
452 obj = obj_initial(value, impl, expl, default, optional)
454 value_expected = default if value is None else value
456 default_initial if value_expected is None
459 self.assertEqual(obj, value_expected)
460 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
461 self.assertEqual(obj.expl_tag, expl or expl_initial)
464 default_initial if default is None else default,
466 if obj.default is None:
467 optional = optional_initial if optional is None else optional
468 optional = False if optional is None else optional
471 self.assertEqual(obj.optional, optional)
473 @given(boolean_values_strategy())
474 def test_copy(self, values):
475 for klass in (Boolean, BooleanInherited):
477 for copy_func in copy_funcs:
478 obj_copied = copy_func(obj)
479 self.assert_copied_basic_fields(obj, obj_copied)
483 integers(min_value=1).map(tag_encode),
485 def test_stripped(self, value, tag_impl):
486 obj = Boolean(value, impl=tag_impl)
487 with self.assertRaises(NotEnoughData):
488 obj.decode(obj.encode()[:-1])
492 integers(min_value=1).map(tag_ctxc),
494 def test_stripped_expl(self, value, tag_expl):
495 obj = Boolean(value, expl=tag_expl)
496 with self.assertRaises(NotEnoughData):
497 obj.decode(obj.encode()[:-1])
500 integers(min_value=31),
501 integers(min_value=0),
504 def test_bad_tag(self, tag, offset, decode_path):
505 with self.assertRaises(DecodeError) as err:
507 tag_encode(tag)[:-1],
509 decode_path=decode_path,
512 self.assertEqual(err.exception.offset, offset)
513 self.assertEqual(err.exception.decode_path, decode_path)
516 integers(min_value=31),
517 integers(min_value=0),
520 def test_bad_expl_tag(self, tag, offset, decode_path):
521 with self.assertRaises(DecodeError) as err:
522 Boolean(expl=Boolean.tag_default).decode(
523 tag_encode(tag)[:-1],
525 decode_path=decode_path,
528 self.assertEqual(err.exception.offset, offset)
529 self.assertEqual(err.exception.decode_path, decode_path)
532 integers(min_value=128),
533 integers(min_value=0),
536 def test_bad_len(self, l, offset, decode_path):
537 with self.assertRaises(DecodeError) as err:
539 Boolean.tag_default + len_encode(l)[:-1],
541 decode_path=decode_path,
544 self.assertEqual(err.exception.offset, offset)
545 self.assertEqual(err.exception.decode_path, decode_path)
548 integers(min_value=128),
549 integers(min_value=0),
552 def test_bad_expl_len(self, l, offset, decode_path):
553 with self.assertRaises(DecodeError) as err:
554 Boolean(expl=Boolean.tag_default).decode(
555 Boolean.tag_default + len_encode(l)[:-1],
557 decode_path=decode_path,
560 self.assertEqual(err.exception.offset, offset)
561 self.assertEqual(err.exception.decode_path, decode_path)
563 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
565 boolean_values_strategy(),
567 integers(min_value=1).map(tag_ctxc),
568 integers(min_value=0),
571 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
572 for klass in (Boolean, BooleanInherited):
573 _, _, _, default, optional, _decoded = values
582 pprint(obj, big_blobs=True, with_decode_path=True)
583 self.assertFalse(obj.expled)
584 obj_encoded = obj.encode()
585 obj_expled = obj(value, expl=tag_expl)
586 self.assertTrue(obj_expled.expled)
588 list(obj_expled.pps())
589 pprint(obj_expled, big_blobs=True, with_decode_path=True)
590 obj_expled_encoded = obj_expled.encode()
591 ctx_copied = deepcopy(ctx_dummy)
592 obj_decoded, tail = obj_expled.decode(
593 obj_expled_encoded + tail_junk,
597 self.assertDictEqual(ctx_copied, ctx_dummy)
599 list(obj_decoded.pps())
600 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
601 self.assertEqual(tail, tail_junk)
602 self.assertEqual(obj_decoded, obj_expled)
603 self.assertNotEqual(obj_decoded, obj)
604 self.assertEqual(bool(obj_decoded), bool(obj_expled))
605 self.assertEqual(bool(obj_decoded), bool(obj))
606 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
607 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
608 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
610 obj_decoded.expl_llen,
611 len(len_encode(len(obj_encoded))),
613 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
614 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
617 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
619 self.assertEqual(obj_decoded.expl_offset, offset)
620 assert_exceeding_data(
622 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
626 @given(integers(min_value=2))
627 def test_invalid_len(self, l):
628 with self.assertRaises(InvalidLength):
629 Boolean().decode(b"".join((
635 @given(integers(min_value=0 + 1, max_value=255 - 1))
636 def test_ber_value(self, value):
637 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
638 Boolean().decode(b"".join((
643 obj, _ = Boolean().decode(
651 self.assertTrue(bool(obj))
652 self.assertTrue(obj.ber_encoded)
653 self.assertFalse(obj.lenindef)
654 self.assertTrue(obj.bered)
656 self.assertTrue(obj.ber_encoded)
657 self.assertFalse(obj.lenindef)
658 self.assertTrue(obj.bered)
661 integers(min_value=1).map(tag_ctxc),
662 binary().filter(lambda x: not x.startswith(EOC)),
664 def test_ber_expl_no_eoc(self, expl, junk):
665 encoded = expl + LENINDEF + Boolean(False).encode()
666 with self.assertRaises(LenIndefForm):
667 Boolean(expl=expl).decode(encoded + junk)
668 with assertRaisesRegex(self, DecodeError, "no EOC"):
669 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
670 obj, tail = Boolean(expl=expl).decode(
671 encoded + EOC + junk,
674 self.assertTrue(obj.expl_lenindef)
675 self.assertFalse(obj.lenindef)
676 self.assertFalse(obj.ber_encoded)
677 self.assertTrue(obj.bered)
679 self.assertTrue(obj.expl_lenindef)
680 self.assertFalse(obj.lenindef)
681 self.assertFalse(obj.ber_encoded)
682 self.assertTrue(obj.bered)
683 self.assertSequenceEqual(tail, junk)
686 pprint(obj, big_blobs=True, with_decode_path=True)
689 integers(min_value=1).map(tag_ctxc),
696 def test_ber_expl(self, expl, values):
702 Boolean(value).encode() +
705 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
707 class SeqOf(SequenceOf):
708 schema = Boolean(expl=expl)
709 with self.assertRaises(LenIndefForm):
710 SeqOf().decode(encoded)
711 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
712 self.assertSequenceEqual(tail, b"")
713 self.assertSequenceEqual([bool(v) for v in seqof], values)
729 len(expl) + 1 + 3 + EOC_LEN,
740 pprint(seqof, big_blobs=True, with_decode_path=True)
744 def integer_values_strategy(draw, do_expl=False):
745 bound_min, value, default, bound_max = sorted(draw(sets(
754 _specs = draw(sets(text_letters()))
757 min_size=len(_specs),
758 max_size=len(_specs),
760 _specs = list(zip(_specs, values))
763 bounds = (bound_min, bound_max)
767 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
769 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
772 optional = draw(one_of(none(), booleans()))
774 draw(integers(min_value=0)),
775 draw(integers(min_value=0)),
776 draw(integers(min_value=0)),
778 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
781 class IntegerInherited(Integer):
785 class TestInteger(CommonMixin, TestCase):
788 def test_invalid_value_type(self):
789 with self.assertRaises(InvalidValueType) as err:
793 @given(sets(text_letters(), min_size=2))
794 def test_unknown_name(self, names_input):
795 missing = names_input.pop()
798 schema = [(n, 123) for n in names_input]
799 with self.assertRaises(ObjUnknown) as err:
803 @given(sets(text_letters(), min_size=2))
804 def test_known_name(self, names_input):
806 schema = [(n, 123) for n in names_input]
807 Int(names_input.pop())
810 def test_optional(self, optional):
811 obj = Integer(default=Integer(0), optional=optional)
812 self.assertTrue(obj.optional)
815 def test_ready(self, value):
817 self.assertFalse(obj.ready)
820 pprint(obj, big_blobs=True, with_decode_path=True)
821 with self.assertRaises(ObjNotReady) as err:
825 self.assertTrue(obj.ready)
828 pprint(obj, big_blobs=True, with_decode_path=True)
831 @given(integers(), integers(), binary(), binary())
832 def test_comparison(self, value1, value2, tag1, tag2):
833 for klass in (Integer, IntegerInherited):
836 self.assertEqual(obj1 == obj2, value1 == value2)
837 self.assertEqual(obj1 != obj2, value1 != value2)
838 self.assertEqual(obj1 == int(obj2), value1 == value2)
839 obj1 = klass(value1, impl=tag1)
840 obj2 = klass(value1, impl=tag2)
841 self.assertEqual(obj1 == obj2, tag1 == tag2)
842 self.assertEqual(obj1 != obj2, tag1 != tag2)
844 @given(lists(integers()))
845 def test_sorted_works(self, values):
846 self.assertSequenceEqual(
847 [int(v) for v in sorted(Integer(v) for v in values)],
851 @given(data_strategy())
852 def test_named(self, d):
853 names_input = list(d.draw(sets(text_letters(), min_size=1)))
854 values_input = list(d.draw(sets(
856 min_size=len(names_input),
857 max_size=len(names_input),
859 chosen_name = d.draw(sampled_from(names_input))
860 names_input = dict(zip(names_input, values_input))
864 _int = Int(chosen_name)
865 self.assertEqual(_int.named, chosen_name)
866 self.assertEqual(int(_int), names_input[chosen_name])
868 @given(integers(), integers(min_value=0), integers(min_value=0))
869 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
870 value = bound_min + value_delta
871 bound_max = value + bound_delta
872 Integer(value=value, bounds=(bound_min, bound_max))
874 @given(sets(integers(), min_size=3, max_size=3))
875 def test_bounds_unsatisfied(self, values):
876 values = sorted(values)
877 with self.assertRaises(BoundsError) as err:
878 Integer(value=values[0], bounds=(values[1], values[2]))
880 with assertRaisesRegex(self, DecodeError, "bounds") as err:
881 Integer(bounds=(values[1], values[2])).decode(
882 Integer(values[0]).encode()
885 with self.assertRaises(BoundsError) as err:
886 Integer(value=values[2], bounds=(values[0], values[1]))
888 with assertRaisesRegex(self, DecodeError, "bounds") as err:
889 Integer(bounds=(values[0], values[1])).decode(
890 Integer(values[2]).encode()
894 @given(data_strategy())
895 def test_call(self, d):
896 for klass in (Integer, IntegerInherited):
906 ) = d.draw(integer_values_strategy())
913 optional_initial or False,
926 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
927 if (default is None) and (obj_initial.default is not None):
931 (value is not None) and
932 (bounds_initial is not None) and
933 not (bounds_initial[0] <= value <= bounds_initial[1])
938 (default is not None) and
939 (bounds_initial is not None) and
940 not (bounds_initial[0] <= default <= bounds_initial[1])
943 obj = obj_initial(value, bounds, impl, expl, default, optional)
945 value_expected = default if value is None else value
947 default_initial if value_expected is None
950 self.assertEqual(obj, value_expected)
951 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
952 self.assertEqual(obj.expl_tag, expl or expl_initial)
955 default_initial if default is None else default,
957 if obj.default is None:
958 optional = optional_initial if optional is None else optional
959 optional = False if optional is None else optional
962 self.assertEqual(obj.optional, optional)
964 (obj._bound_min, obj._bound_max),
965 bounds or bounds_initial or (float("-inf"), float("+inf")),
969 {} if _specs_initial is None else dict(_specs_initial),
972 @given(integer_values_strategy())
973 def test_copy(self, values):
974 for klass in (Integer, IntegerInherited):
976 for copy_func in copy_funcs:
977 obj_copied = copy_func(obj)
978 self.assert_copied_basic_fields(obj, obj_copied)
979 self.assertEqual(obj.specs, obj_copied.specs)
980 self.assertEqual(obj._bound_min, obj_copied._bound_min)
981 self.assertEqual(obj._bound_max, obj_copied._bound_max)
982 self.assertEqual(obj._value, obj_copied._value)
986 integers(min_value=1).map(tag_encode),
988 def test_stripped(self, value, tag_impl):
989 obj = Integer(value, impl=tag_impl)
990 with self.assertRaises(NotEnoughData):
991 obj.decode(obj.encode()[:-1])
995 integers(min_value=1).map(tag_ctxc),
997 def test_stripped_expl(self, value, tag_expl):
998 obj = Integer(value, expl=tag_expl)
999 with self.assertRaises(NotEnoughData):
1000 obj.decode(obj.encode()[:-1])
1002 def test_zero_len(self):
1003 with self.assertRaises(NotEnoughData):
1004 Integer().decode(b"".join((
1005 Integer.tag_default,
1010 integers(min_value=31),
1011 integers(min_value=0),
1014 def test_bad_tag(self, tag, offset, decode_path):
1015 with self.assertRaises(DecodeError) as err:
1017 tag_encode(tag)[:-1],
1019 decode_path=decode_path,
1022 self.assertEqual(err.exception.offset, offset)
1023 self.assertEqual(err.exception.decode_path, decode_path)
1026 integers(min_value=128),
1027 integers(min_value=0),
1030 def test_bad_len(self, l, offset, decode_path):
1031 with self.assertRaises(DecodeError) as err:
1033 Integer.tag_default + len_encode(l)[:-1],
1035 decode_path=decode_path,
1038 self.assertEqual(err.exception.offset, offset)
1039 self.assertEqual(err.exception.decode_path, decode_path)
1042 sets(integers(), min_size=2, max_size=2),
1043 integers(min_value=0),
1046 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1047 value, bound_min = list(sorted(ints))
1050 bounds = (bound_min, bound_min)
1051 with self.assertRaises(DecodeError) as err:
1053 Integer(value).encode(),
1055 decode_path=decode_path,
1058 self.assertEqual(err.exception.offset, offset)
1059 self.assertEqual(err.exception.decode_path, decode_path)
1061 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1063 integer_values_strategy(),
1065 integers(min_value=1).map(tag_ctxc),
1066 integers(min_value=0),
1069 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1070 for klass in (Integer, IntegerInherited):
1071 _, _, _, _, default, optional, _, _decoded = values
1080 pprint(obj, big_blobs=True, with_decode_path=True)
1081 self.assertFalse(obj.expled)
1082 obj_encoded = obj.encode()
1083 obj_expled = obj(value, expl=tag_expl)
1084 self.assertTrue(obj_expled.expled)
1086 list(obj_expled.pps())
1087 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1088 obj_expled_encoded = obj_expled.encode()
1089 ctx_copied = deepcopy(ctx_dummy)
1090 obj_decoded, tail = obj_expled.decode(
1091 obj_expled_encoded + tail_junk,
1095 self.assertDictEqual(ctx_copied, ctx_dummy)
1097 list(obj_decoded.pps())
1098 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1099 self.assertEqual(tail, tail_junk)
1100 self.assertEqual(obj_decoded, obj_expled)
1101 self.assertNotEqual(obj_decoded, obj)
1102 self.assertEqual(int(obj_decoded), int(obj_expled))
1103 self.assertEqual(int(obj_decoded), int(obj))
1104 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1105 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1106 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1108 obj_decoded.expl_llen,
1109 len(len_encode(len(obj_encoded))),
1111 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1112 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1115 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1117 self.assertEqual(obj_decoded.expl_offset, offset)
1118 assert_exceeding_data(
1120 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1124 def test_go_vectors_valid(self):
1125 for data, expect in ((
1129 (b"\xff\x7f", -129),
1133 (b"\xff\x00", -256),
1137 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1138 (b"\x80\x00\x00\x00", -2147483648),
1141 Integer().decode(b"".join((
1142 Integer.tag_default,
1143 len_encode(len(data)),
1149 def test_go_vectors_invalid(self):
1154 with self.assertRaises(DecodeError):
1155 Integer().decode(b"".join((
1156 Integer.tag_default,
1157 len_encode(len(data)),
1163 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1166 if draw(booleans()):
1167 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1169 integers(min_value=0, max_value=255),
1170 min_size=len(schema),
1171 max_size=len(schema),
1173 schema = list(zip(schema, bits))
1175 def _value(value_required):
1176 if not value_required and draw(booleans()):
1178 generation_choice = 0
1180 generation_choice = draw(sampled_from((1, 2, 3)))
1181 if generation_choice == 1 or draw(booleans()):
1182 return "'%s'B" % "".join(draw(lists(
1183 sampled_from(("0", "1")),
1184 max_size=len(schema),
1186 if generation_choice == 2 or draw(booleans()):
1187 return draw(binary(max_size=len(schema) // 8))
1188 if generation_choice == 3 or draw(booleans()):
1189 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1191 value = _value(value_required)
1192 default = _value(value_required=False)
1196 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1198 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1199 optional = draw(one_of(none(), booleans()))
1201 draw(integers(min_value=0)),
1202 draw(integers(min_value=0)),
1203 draw(integers(min_value=0)),
1205 return (schema, value, impl, expl, default, optional, _decoded)
1208 class BitStringInherited(BitString):
1212 class TestBitString(CommonMixin, TestCase):
1213 base_klass = BitString
1215 @given(lists(booleans()))
1216 def test_b_encoding(self, bits):
1217 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1218 self.assertEqual(obj.bit_len, len(bits))
1219 self.assertSequenceEqual(list(obj), bits)
1220 for i, bit in enumerate(bits):
1221 self.assertEqual(obj[i], bit)
1223 @given(lists(booleans()))
1224 def test_out_of_bounds_bits(self, bits):
1225 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1226 for i in range(len(bits), len(bits) * 2):
1227 self.assertFalse(obj[i])
1229 def test_bad_b_encoding(self):
1230 with self.assertRaises(ValueError):
1231 BitString("'010120101'B")
1234 integers(min_value=1, max_value=255),
1235 integers(min_value=1, max_value=255),
1237 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1238 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1239 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1240 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1242 class BS(BitString):
1243 schema = (("whatever", 0),)
1244 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1245 self.assertEqual(obj.bit_len, leading_zeros + 1)
1246 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1248 def test_zero_len(self):
1249 with self.assertRaises(NotEnoughData):
1250 BitString().decode(b"".join((
1251 BitString.tag_default,
1255 def test_invalid_value_type(self):
1256 with self.assertRaises(InvalidValueType) as err:
1259 with self.assertRaises(InvalidValueType) as err:
1263 def test_obj_unknown(self):
1264 with self.assertRaises(ObjUnknown) as err:
1265 BitString(b"whatever")["whenever"]
1268 def test_get_invalid_type(self):
1269 with self.assertRaises(InvalidValueType) as err:
1270 BitString(b"whatever")[(1, 2, 3)]
1273 @given(data_strategy())
1274 def test_unknown_name(self, d):
1275 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1276 missing = _schema.pop()
1278 class BS(BitString):
1279 schema = [(n, i) for i, n in enumerate(_schema)]
1280 with self.assertRaises(ObjUnknown) as err:
1285 def test_optional(self, optional):
1286 obj = BitString(default=BitString(b""), optional=optional)
1287 self.assertTrue(obj.optional)
1290 def test_ready(self, value):
1292 self.assertFalse(obj.ready)
1295 pprint(obj, big_blobs=True, with_decode_path=True)
1296 with self.assertRaises(ObjNotReady) as err:
1299 obj = BitString(value)
1300 self.assertTrue(obj.ready)
1303 pprint(obj, big_blobs=True, with_decode_path=True)
1306 tuples(integers(min_value=0), binary()),
1307 tuples(integers(min_value=0), binary()),
1311 def test_comparison(self, value1, value2, tag1, tag2):
1312 for klass in (BitString, BitStringInherited):
1313 obj1 = klass(value1)
1314 obj2 = klass(value2)
1315 self.assertEqual(obj1 == obj2, value1 == value2)
1316 self.assertEqual(obj1 != obj2, value1 != value2)
1317 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1318 obj1 = klass(value1, impl=tag1)
1319 obj2 = klass(value1, impl=tag2)
1320 self.assertEqual(obj1 == obj2, tag1 == tag2)
1321 self.assertEqual(obj1 != obj2, tag1 != tag2)
1323 @given(data_strategy())
1324 def test_call(self, d):
1325 for klass in (BitString, BitStringInherited):
1334 ) = d.draw(bit_string_values_strategy())
1337 schema = schema_initial
1339 value=value_initial,
1342 default=default_initial,
1343 optional=optional_initial or False,
1344 _decoded=_decoded_initial,
1354 ) = d.draw(bit_string_values_strategy(
1355 schema=schema_initial,
1356 do_expl=impl_initial is None,
1365 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1366 self.assertEqual(obj.expl_tag, expl or expl_initial)
1367 if obj.default is None:
1368 optional = optional_initial if optional is None else optional
1369 optional = False if optional is None else optional
1372 self.assertEqual(obj.optional, optional)
1373 self.assertEqual(obj.specs, obj_initial.specs)
1375 @given(bit_string_values_strategy())
1376 def test_copy(self, values):
1377 for klass in (BitString, BitStringInherited):
1378 _schema, value, impl, expl, default, optional, _decoded = values
1388 optional=optional or False,
1391 for copy_func in copy_funcs:
1392 obj_copied = copy_func(obj)
1393 self.assert_copied_basic_fields(obj, obj_copied)
1394 self.assertEqual(obj.specs, obj_copied.specs)
1395 self.assertEqual(obj._value, obj_copied._value)
1399 integers(min_value=1).map(tag_encode),
1401 def test_stripped(self, value, tag_impl):
1402 obj = BitString(value, impl=tag_impl)
1403 with self.assertRaises(NotEnoughData):
1404 obj.decode(obj.encode()[:-1])
1408 integers(min_value=1).map(tag_ctxc),
1410 def test_stripped_expl(self, value, tag_expl):
1411 obj = BitString(value, expl=tag_expl)
1412 with self.assertRaises(NotEnoughData):
1413 obj.decode(obj.encode()[:-1])
1416 integers(min_value=31),
1417 integers(min_value=0),
1420 def test_bad_tag(self, tag, offset, decode_path):
1421 with self.assertRaises(DecodeError) as err:
1423 tag_encode(tag)[:-1],
1425 decode_path=decode_path,
1428 self.assertEqual(err.exception.offset, offset)
1429 self.assertEqual(err.exception.decode_path, decode_path)
1432 integers(min_value=128),
1433 integers(min_value=0),
1436 def test_bad_len(self, l, offset, decode_path):
1437 with self.assertRaises(DecodeError) as err:
1439 BitString.tag_default + len_encode(l)[:-1],
1441 decode_path=decode_path,
1444 self.assertEqual(err.exception.offset, offset)
1445 self.assertEqual(err.exception.decode_path, decode_path)
1447 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1448 @given(data_strategy())
1449 def test_symmetric(self, d):
1458 ) = d.draw(bit_string_values_strategy(value_required=True))
1459 tail_junk = d.draw(binary(max_size=5))
1460 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1461 offset = d.draw(integers(min_value=0))
1462 for klass in (BitString, BitStringInherited):
1473 pprint(obj, big_blobs=True, with_decode_path=True)
1474 self.assertFalse(obj.expled)
1475 obj_encoded = obj.encode()
1476 obj_expled = obj(value, expl=tag_expl)
1477 self.assertTrue(obj_expled.expled)
1479 list(obj_expled.pps())
1480 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1481 obj_expled_encoded = obj_expled.encode()
1482 ctx_copied = deepcopy(ctx_dummy)
1483 obj_decoded, tail = obj_expled.decode(
1484 obj_expled_encoded + tail_junk,
1488 self.assertDictEqual(ctx_copied, ctx_dummy)
1490 list(obj_decoded.pps())
1491 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1492 self.assertEqual(tail, tail_junk)
1493 self.assertEqual(obj_decoded, obj_expled)
1494 self.assertNotEqual(obj_decoded, obj)
1495 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1496 self.assertEqual(bytes(obj_decoded), bytes(obj))
1497 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1498 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1499 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1501 obj_decoded.expl_llen,
1502 len(len_encode(len(obj_encoded))),
1504 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1505 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1508 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1510 self.assertEqual(obj_decoded.expl_offset, offset)
1511 if isinstance(value, tuple):
1512 self.assertSetEqual(set(value), set(obj_decoded.named))
1515 assert_exceeding_data(
1517 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1521 @given(integers(min_value=1, max_value=255))
1522 def test_bad_zero_value(self, pad_size):
1523 with self.assertRaises(DecodeError):
1524 BitString().decode(b"".join((
1525 BitString.tag_default,
1530 def test_go_vectors_invalid(self):
1536 with self.assertRaises(DecodeError):
1537 BitString().decode(b"".join((
1538 BitString.tag_default,
1543 def test_go_vectors_valid(self):
1544 obj, _ = BitString().decode(b"".join((
1545 BitString.tag_default,
1549 self.assertEqual(bytes(obj), b"")
1550 self.assertEqual(obj.bit_len, 0)
1552 obj, _ = BitString().decode(b"".join((
1553 BitString.tag_default,
1557 self.assertEqual(bytes(obj), b"\x00")
1558 self.assertEqual(obj.bit_len, 1)
1560 obj = BitString((16, b"\x82\x40"))
1561 self.assertTrue(obj[0])
1562 self.assertFalse(obj[1])
1563 self.assertTrue(obj[6])
1564 self.assertTrue(obj[9])
1565 self.assertFalse(obj[17])
1568 integers(min_value=1, max_value=30),
1571 binary(min_size=1, max_size=5),
1573 binary(min_size=1, max_size=5),
1581 lists(booleans(), min_size=1),
1584 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1585 def chunk_constructed(contents):
1587 tag_encode(form=TagFormConstructed, num=3) +
1589 b"".join(BitString(content).encode() for content in contents) +
1593 payload_expected = b""
1594 bit_len_expected = 0
1595 for chunk_input in chunk_inputs:
1596 if isinstance(chunk_input, binary_type):
1597 chunks.append(BitString(chunk_input).encode())
1598 payload_expected += chunk_input
1599 bit_len_expected += len(chunk_input) * 8
1601 chunks.append(chunk_constructed(chunk_input))
1602 payload = b"".join(chunk_input)
1603 payload_expected += payload
1604 bit_len_expected += len(payload) * 8
1605 chunk_last = BitString("'%s'B" % "".join(
1606 "1" if bit else "0" for bit in chunk_last_bits
1608 payload_expected += bytes(chunk_last)
1609 bit_len_expected += chunk_last.bit_len
1610 encoded_indefinite = (
1611 tag_encode(form=TagFormConstructed, num=impl) +
1614 chunk_last.encode() +
1617 encoded_definite = (
1618 tag_encode(form=TagFormConstructed, num=impl) +
1619 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1623 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1624 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1625 for lenindef_expected, encoded in (
1626 (True, encoded_indefinite),
1627 (False, encoded_definite),
1629 obj, tail = BitString(impl=tag_encode(impl)).decode(
1631 ctx={"bered": True},
1633 self.assertSequenceEqual(tail, junk)
1634 self.assertEqual(obj.bit_len, bit_len_expected)
1635 self.assertSequenceEqual(bytes(obj), payload_expected)
1636 self.assertTrue(obj.ber_encoded)
1637 self.assertEqual(obj.lenindef, lenindef_expected)
1638 self.assertTrue(obj.bered)
1640 self.assertTrue(obj.ber_encoded)
1641 self.assertEqual(obj.lenindef, lenindef_expected)
1642 self.assertTrue(obj.bered)
1643 self.assertEqual(len(encoded), obj.tlvlen)
1646 integers(min_value=0),
1649 def test_ber_definite_too_short(self, offset, decode_path):
1650 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1652 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1654 decode_path=decode_path,
1655 ctx={"bered": True},
1657 self.assertEqual(err.exception.decode_path, decode_path)
1658 self.assertEqual(err.exception.offset, offset)
1661 integers(min_value=0),
1664 def test_ber_definite_no_data(self, offset, decode_path):
1665 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1667 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1669 decode_path=decode_path,
1670 ctx={"bered": True},
1672 self.assertEqual(err.exception.decode_path, decode_path)
1673 self.assertEqual(err.exception.offset, offset)
1676 integers(min_value=0),
1678 integers(min_value=1, max_value=3),
1680 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1681 bs = BitString(b"data").encode()
1682 with self.assertRaises(NotEnoughData) as err:
1684 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1686 decode_path=decode_path,
1687 ctx={"bered": True},
1689 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1690 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1693 integers(min_value=0),
1695 integers(min_value=1, max_value=3),
1697 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1698 bs = BitString(b"data").encode()
1699 bs_longer = BitString(b"data-longer").encode()
1700 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1703 tag_encode(3, form=TagFormConstructed) +
1704 len_encode((chunks + 1) * len(bs)) +
1709 decode_path=decode_path,
1710 ctx={"bered": True},
1712 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1713 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1716 integers(min_value=0),
1719 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1720 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1722 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1724 decode_path=decode_path,
1725 ctx={"bered": True},
1727 self.assertEqual(err.exception.decode_path, decode_path)
1728 self.assertEqual(err.exception.offset, offset)
1730 @given(data_strategy())
1731 def test_ber_indefinite_not_multiple(self, d):
1732 bs_short = BitString("'A'H").encode()
1733 bs_full = BitString("'AA'H").encode()
1734 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1735 chunks.append(bs_short)
1736 d.draw(permutations(chunks))
1737 chunks.append(bs_short)
1738 offset = d.draw(integers(min_value=0))
1739 decode_path = d.draw(decode_path_strat)
1740 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1743 tag_encode(3, form=TagFormConstructed) +
1749 decode_path=decode_path,
1750 ctx={"bered": True},
1753 err.exception.decode_path,
1754 decode_path + (str(chunks.index(bs_short)),),
1757 err.exception.offset,
1758 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1761 def test_x690_vector(self):
1762 vector = BitString("'0A3B5F291CD'H")
1763 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1764 self.assertSequenceEqual(tail, b"")
1765 self.assertEqual(obj, vector)
1766 obj, tail = BitString().decode(
1767 hexdec("23800303000A3B0305045F291CD00000"),
1768 ctx={"bered": True},
1770 self.assertSequenceEqual(tail, b"")
1771 self.assertEqual(obj, vector)
1772 self.assertTrue(obj.ber_encoded)
1773 self.assertTrue(obj.lenindef)
1774 self.assertTrue(obj.bered)
1776 self.assertTrue(obj.ber_encoded)
1777 self.assertTrue(obj.lenindef)
1778 self.assertTrue(obj.bered)
1782 def octet_string_values_strategy(draw, do_expl=False):
1783 bound_min, bound_max = sorted(draw(sets(
1784 integers(min_value=0, max_value=1 << 7),
1788 value = draw(one_of(
1790 binary(min_size=bound_min, max_size=bound_max),
1792 default = draw(one_of(
1794 binary(min_size=bound_min, max_size=bound_max),
1797 if draw(booleans()):
1798 bounds = (bound_min, bound_max)
1802 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1804 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1805 optional = draw(one_of(none(), booleans()))
1807 draw(integers(min_value=0)),
1808 draw(integers(min_value=0)),
1809 draw(integers(min_value=0)),
1811 return (value, bounds, impl, expl, default, optional, _decoded)
1814 class OctetStringInherited(OctetString):
1818 class TestOctetString(CommonMixin, TestCase):
1819 base_klass = OctetString
1821 def test_invalid_value_type(self):
1822 with self.assertRaises(InvalidValueType) as err:
1823 OctetString(text_type(123))
1827 def test_optional(self, optional):
1828 obj = OctetString(default=OctetString(b""), optional=optional)
1829 self.assertTrue(obj.optional)
1832 def test_ready(self, value):
1834 self.assertFalse(obj.ready)
1837 pprint(obj, big_blobs=True, with_decode_path=True)
1838 with self.assertRaises(ObjNotReady) as err:
1841 obj = OctetString(value)
1842 self.assertTrue(obj.ready)
1845 pprint(obj, big_blobs=True, with_decode_path=True)
1847 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1848 def test_comparison(self, value1, value2, tag1, tag2):
1849 for klass in (OctetString, OctetStringInherited):
1850 obj1 = klass(value1)
1851 obj2 = klass(value2)
1852 self.assertEqual(obj1 == obj2, value1 == value2)
1853 self.assertEqual(obj1 != obj2, value1 != value2)
1854 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1855 obj1 = klass(value1, impl=tag1)
1856 obj2 = klass(value1, impl=tag2)
1857 self.assertEqual(obj1 == obj2, tag1 == tag2)
1858 self.assertEqual(obj1 != obj2, tag1 != tag2)
1860 @given(lists(binary()))
1861 def test_sorted_works(self, values):
1862 self.assertSequenceEqual(
1863 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1867 @given(data_strategy())
1868 def test_bounds_satisfied(self, d):
1869 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1870 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1871 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1872 OctetString(value=value, bounds=(bound_min, bound_max))
1874 @given(data_strategy())
1875 def test_bounds_unsatisfied(self, d):
1876 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1877 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1878 value = d.draw(binary(max_size=bound_min - 1))
1879 with self.assertRaises(BoundsError) as err:
1880 OctetString(value=value, bounds=(bound_min, bound_max))
1882 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1883 OctetString(bounds=(bound_min, bound_max)).decode(
1884 OctetString(value).encode()
1887 value = d.draw(binary(min_size=bound_max + 1))
1888 with self.assertRaises(BoundsError) as err:
1889 OctetString(value=value, bounds=(bound_min, bound_max))
1891 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1892 OctetString(bounds=(bound_min, bound_max)).decode(
1893 OctetString(value).encode()
1897 @given(data_strategy())
1898 def test_call(self, d):
1899 for klass in (OctetString, OctetStringInherited):
1908 ) = d.draw(octet_string_values_strategy())
1909 obj_initial = klass(
1915 optional_initial or False,
1926 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1927 if (default is None) and (obj_initial.default is not None):
1930 (bounds is None) and
1931 (value is not None) and
1932 (bounds_initial is not None) and
1933 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1937 (bounds is None) and
1938 (default is not None) and
1939 (bounds_initial is not None) and
1940 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1943 obj = obj_initial(value, bounds, impl, expl, default, optional)
1945 value_expected = default if value is None else value
1947 default_initial if value_expected is None
1950 self.assertEqual(obj, value_expected)
1951 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1952 self.assertEqual(obj.expl_tag, expl or expl_initial)
1955 default_initial if default is None else default,
1957 if obj.default is None:
1958 optional = optional_initial if optional is None else optional
1959 optional = False if optional is None else optional
1962 self.assertEqual(obj.optional, optional)
1964 (obj._bound_min, obj._bound_max),
1965 bounds or bounds_initial or (0, float("+inf")),
1968 @given(octet_string_values_strategy())
1969 def test_copy(self, values):
1970 for klass in (OctetString, OctetStringInherited):
1971 obj = klass(*values)
1972 for copy_func in copy_funcs:
1973 obj_copied = copy_func(obj)
1974 self.assert_copied_basic_fields(obj, obj_copied)
1975 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1976 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1977 self.assertEqual(obj._value, obj_copied._value)
1981 integers(min_value=1).map(tag_encode),
1983 def test_stripped(self, value, tag_impl):
1984 obj = OctetString(value, impl=tag_impl)
1985 with self.assertRaises(NotEnoughData):
1986 obj.decode(obj.encode()[:-1])
1990 integers(min_value=1).map(tag_ctxc),
1992 def test_stripped_expl(self, value, tag_expl):
1993 obj = OctetString(value, expl=tag_expl)
1994 with self.assertRaises(NotEnoughData):
1995 obj.decode(obj.encode()[:-1])
1998 integers(min_value=31),
1999 integers(min_value=0),
2002 def test_bad_tag(self, tag, offset, decode_path):
2003 with self.assertRaises(DecodeError) as err:
2004 OctetString().decode(
2005 tag_encode(tag)[:-1],
2007 decode_path=decode_path,
2010 self.assertEqual(err.exception.offset, offset)
2011 self.assertEqual(err.exception.decode_path, decode_path)
2014 integers(min_value=128),
2015 integers(min_value=0),
2018 def test_bad_len(self, l, offset, decode_path):
2019 with self.assertRaises(DecodeError) as err:
2020 OctetString().decode(
2021 OctetString.tag_default + len_encode(l)[:-1],
2023 decode_path=decode_path,
2026 self.assertEqual(err.exception.offset, offset)
2027 self.assertEqual(err.exception.decode_path, decode_path)
2030 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2031 integers(min_value=0),
2034 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2035 value, bound_min = list(sorted(ints))
2037 class String(OctetString):
2038 bounds = (bound_min, bound_min)
2039 with self.assertRaises(DecodeError) as err:
2041 OctetString(b"\x00" * value).encode(),
2043 decode_path=decode_path,
2046 self.assertEqual(err.exception.offset, offset)
2047 self.assertEqual(err.exception.decode_path, decode_path)
2049 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2051 octet_string_values_strategy(),
2053 integers(min_value=1).map(tag_ctxc),
2054 integers(min_value=0),
2057 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2058 for klass in (OctetString, OctetStringInherited):
2059 _, _, _, _, default, optional, _decoded = values
2068 pprint(obj, big_blobs=True, with_decode_path=True)
2069 self.assertFalse(obj.expled)
2070 obj_encoded = obj.encode()
2071 obj_expled = obj(value, expl=tag_expl)
2072 self.assertTrue(obj_expled.expled)
2074 list(obj_expled.pps())
2075 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2076 obj_expled_encoded = obj_expled.encode()
2077 ctx_copied = deepcopy(ctx_dummy)
2078 obj_decoded, tail = obj_expled.decode(
2079 obj_expled_encoded + tail_junk,
2083 self.assertDictEqual(ctx_copied, ctx_dummy)
2085 list(obj_decoded.pps())
2086 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2087 self.assertEqual(tail, tail_junk)
2088 self.assertEqual(obj_decoded, obj_expled)
2089 self.assertNotEqual(obj_decoded, obj)
2090 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2091 self.assertEqual(bytes(obj_decoded), bytes(obj))
2092 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2093 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2094 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2096 obj_decoded.expl_llen,
2097 len(len_encode(len(obj_encoded))),
2099 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2100 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2103 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2105 self.assertEqual(obj_decoded.expl_offset, offset)
2106 assert_exceeding_data(
2108 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2113 integers(min_value=1, max_value=30),
2116 binary(min_size=1, max_size=5),
2118 binary(min_size=1, max_size=5),
2128 def test_constructed(self, impl, chunk_inputs, junk):
2129 def chunk_constructed(contents):
2131 tag_encode(form=TagFormConstructed, num=4) +
2133 b"".join(OctetString(content).encode() for content in contents) +
2137 payload_expected = b""
2138 for chunk_input in chunk_inputs:
2139 if isinstance(chunk_input, binary_type):
2140 chunks.append(OctetString(chunk_input).encode())
2141 payload_expected += chunk_input
2143 chunks.append(chunk_constructed(chunk_input))
2144 payload = b"".join(chunk_input)
2145 payload_expected += payload
2146 encoded_indefinite = (
2147 tag_encode(form=TagFormConstructed, num=impl) +
2152 encoded_definite = (
2153 tag_encode(form=TagFormConstructed, num=impl) +
2154 len_encode(len(b"".join(chunks))) +
2157 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2158 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2159 for lenindef_expected, encoded in (
2160 (True, encoded_indefinite),
2161 (False, encoded_definite),
2163 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2165 ctx={"bered": True},
2167 self.assertSequenceEqual(tail, junk)
2168 self.assertSequenceEqual(bytes(obj), payload_expected)
2169 self.assertTrue(obj.ber_encoded)
2170 self.assertEqual(obj.lenindef, lenindef_expected)
2171 self.assertTrue(obj.bered)
2173 self.assertTrue(obj.ber_encoded)
2174 self.assertEqual(obj.lenindef, lenindef_expected)
2175 self.assertTrue(obj.bered)
2176 self.assertEqual(len(encoded), obj.tlvlen)
2179 integers(min_value=0),
2182 def test_ber_definite_too_short(self, offset, decode_path):
2183 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2184 OctetString().decode(
2185 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2187 decode_path=decode_path,
2188 ctx={"bered": True},
2190 self.assertEqual(err.exception.decode_path, decode_path)
2191 self.assertEqual(err.exception.offset, offset)
2194 integers(min_value=0),
2196 integers(min_value=1, max_value=3),
2198 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2199 bs = OctetString(b"data").encode()
2200 with self.assertRaises(NotEnoughData) as err:
2201 OctetString().decode(
2202 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2204 decode_path=decode_path,
2205 ctx={"bered": True},
2207 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2208 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2211 integers(min_value=0),
2213 integers(min_value=1, max_value=3),
2215 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2216 bs = OctetString(b"data").encode()
2217 bs_longer = OctetString(b"data-longer").encode()
2218 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2219 OctetString().decode(
2221 tag_encode(4, form=TagFormConstructed) +
2222 len_encode((chunks + 1) * len(bs)) +
2227 decode_path=decode_path,
2228 ctx={"bered": True},
2230 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2231 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2235 def null_values_strategy(draw, do_expl=False):
2239 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2241 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2242 optional = draw(one_of(none(), booleans()))
2244 draw(integers(min_value=0)),
2245 draw(integers(min_value=0)),
2246 draw(integers(min_value=0)),
2248 return (impl, expl, optional, _decoded)
2251 class NullInherited(Null):
2255 class TestNull(CommonMixin, TestCase):
2258 def test_ready(self):
2260 self.assertTrue(obj.ready)
2263 pprint(obj, big_blobs=True, with_decode_path=True)
2265 @given(binary(), binary())
2266 def test_comparison(self, tag1, tag2):
2267 for klass in (Null, NullInherited):
2268 obj1 = klass(impl=tag1)
2269 obj2 = klass(impl=tag2)
2270 self.assertEqual(obj1 == obj2, tag1 == tag2)
2271 self.assertEqual(obj1 != obj2, tag1 != tag2)
2272 self.assertNotEqual(obj1, tag2)
2274 @given(data_strategy())
2275 def test_call(self, d):
2276 for klass in (Null, NullInherited):
2282 ) = d.draw(null_values_strategy())
2283 obj_initial = klass(
2286 optional=optional_initial or False,
2287 _decoded=_decoded_initial,
2294 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2295 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2296 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2297 self.assertEqual(obj.expl_tag, expl or expl_initial)
2298 optional = optional_initial if optional is None else optional
2299 optional = False if optional is None else optional
2300 self.assertEqual(obj.optional, optional)
2302 @given(null_values_strategy())
2303 def test_copy(self, values):
2304 for klass in (Null, NullInherited):
2305 impl, expl, optional, _decoded = values
2309 optional=optional or False,
2312 for copy_func in copy_funcs:
2313 obj_copied = copy_func(obj)
2314 self.assert_copied_basic_fields(obj, obj_copied)
2316 @given(integers(min_value=1).map(tag_encode))
2317 def test_stripped(self, tag_impl):
2318 obj = Null(impl=tag_impl)
2319 with self.assertRaises(NotEnoughData):
2320 obj.decode(obj.encode()[:-1])
2322 @given(integers(min_value=1).map(tag_ctxc))
2323 def test_stripped_expl(self, tag_expl):
2324 obj = Null(expl=tag_expl)
2325 with self.assertRaises(NotEnoughData):
2326 obj.decode(obj.encode()[:-1])
2329 integers(min_value=31),
2330 integers(min_value=0),
2333 def test_bad_tag(self, tag, offset, decode_path):
2334 with self.assertRaises(DecodeError) as err:
2336 tag_encode(tag)[:-1],
2338 decode_path=decode_path,
2341 self.assertEqual(err.exception.offset, offset)
2342 self.assertEqual(err.exception.decode_path, decode_path)
2345 integers(min_value=128),
2346 integers(min_value=0),
2349 def test_bad_len(self, l, offset, decode_path):
2350 with self.assertRaises(DecodeError) as err:
2352 Null.tag_default + len_encode(l)[:-1],
2354 decode_path=decode_path,
2357 self.assertEqual(err.exception.offset, offset)
2358 self.assertEqual(err.exception.decode_path, decode_path)
2360 @given(binary(min_size=1))
2361 def test_tag_mismatch(self, impl):
2362 assume(impl != Null.tag_default)
2363 with self.assertRaises(TagMismatch):
2364 Null(impl=impl).decode(Null().encode())
2367 null_values_strategy(),
2368 integers(min_value=1).map(tag_ctxc),
2369 integers(min_value=0),
2372 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2373 for klass in (Null, NullInherited):
2374 _, _, optional, _decoded = values
2375 obj = klass(optional=optional, _decoded=_decoded)
2378 pprint(obj, big_blobs=True, with_decode_path=True)
2379 self.assertFalse(obj.expled)
2380 obj_encoded = obj.encode()
2381 obj_expled = obj(expl=tag_expl)
2382 self.assertTrue(obj_expled.expled)
2384 list(obj_expled.pps())
2385 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2386 obj_expled_encoded = obj_expled.encode()
2387 ctx_copied = deepcopy(ctx_dummy)
2388 obj_decoded, tail = obj_expled.decode(
2389 obj_expled_encoded + tail_junk,
2393 self.assertDictEqual(ctx_copied, ctx_dummy)
2395 list(obj_decoded.pps())
2396 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2397 self.assertEqual(tail, tail_junk)
2398 self.assertEqual(obj_decoded, obj_expled)
2399 self.assertNotEqual(obj_decoded, obj)
2400 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2401 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2402 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2404 obj_decoded.expl_llen,
2405 len(len_encode(len(obj_encoded))),
2407 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2408 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2411 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2413 self.assertEqual(obj_decoded.expl_offset, offset)
2414 assert_exceeding_data(
2416 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2420 @given(integers(min_value=1))
2421 def test_invalid_len(self, l):
2422 with self.assertRaises(InvalidLength):
2423 Null().decode(b"".join((
2430 def oid_strategy(draw):
2431 first_arc = draw(integers(min_value=0, max_value=2))
2433 if first_arc in (0, 1):
2434 second_arc = draw(integers(min_value=0, max_value=39))
2436 second_arc = draw(integers(min_value=0))
2437 other_arcs = draw(lists(integers(min_value=0)))
2438 return tuple([first_arc, second_arc] + other_arcs)
2442 def oid_values_strategy(draw, do_expl=False):
2443 value = draw(one_of(none(), oid_strategy()))
2447 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2449 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2450 default = draw(one_of(none(), oid_strategy()))
2451 optional = draw(one_of(none(), booleans()))
2453 draw(integers(min_value=0)),
2454 draw(integers(min_value=0)),
2455 draw(integers(min_value=0)),
2457 return (value, impl, expl, default, optional, _decoded)
2460 class ObjectIdentifierInherited(ObjectIdentifier):
2464 class TestObjectIdentifier(CommonMixin, TestCase):
2465 base_klass = ObjectIdentifier
2467 def test_invalid_value_type(self):
2468 with self.assertRaises(InvalidValueType) as err:
2469 ObjectIdentifier(123)
2473 def test_optional(self, optional):
2474 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2475 self.assertTrue(obj.optional)
2477 @given(oid_strategy())
2478 def test_ready(self, value):
2479 obj = ObjectIdentifier()
2480 self.assertFalse(obj.ready)
2483 pprint(obj, big_blobs=True, with_decode_path=True)
2484 with self.assertRaises(ObjNotReady) as err:
2487 obj = ObjectIdentifier(value)
2488 self.assertTrue(obj.ready)
2489 self.assertFalse(obj.ber_encoded)
2492 pprint(obj, big_blobs=True, with_decode_path=True)
2495 @given(oid_strategy(), oid_strategy(), binary(), binary())
2496 def test_comparison(self, value1, value2, tag1, tag2):
2497 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2498 obj1 = klass(value1)
2499 obj2 = klass(value2)
2500 self.assertEqual(obj1 == obj2, value1 == value2)
2501 self.assertEqual(obj1 != obj2, value1 != value2)
2502 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2503 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2504 obj1 = klass(value1, impl=tag1)
2505 obj2 = klass(value1, impl=tag2)
2506 self.assertEqual(obj1 == obj2, tag1 == tag2)
2507 self.assertEqual(obj1 != obj2, tag1 != tag2)
2509 @given(lists(oid_strategy()))
2510 def test_sorted_works(self, values):
2511 self.assertSequenceEqual(
2512 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2516 @given(data_strategy())
2517 def test_call(self, d):
2518 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2526 ) = d.draw(oid_values_strategy())
2527 obj_initial = klass(
2528 value=value_initial,
2531 default=default_initial,
2532 optional=optional_initial or False,
2533 _decoded=_decoded_initial,
2542 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2551 value_expected = default if value is None else value
2553 default_initial if value_expected is None
2556 self.assertEqual(obj, value_expected)
2557 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2558 self.assertEqual(obj.expl_tag, expl or expl_initial)
2561 default_initial if default is None else default,
2563 if obj.default is None:
2564 optional = optional_initial if optional is None else optional
2565 optional = False if optional is None else optional
2568 self.assertEqual(obj.optional, optional)
2570 @given(oid_values_strategy())
2571 def test_copy(self, values):
2572 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2589 for copy_func in copy_funcs:
2590 obj_copied = copy_func(obj)
2591 self.assert_copied_basic_fields(obj, obj_copied)
2592 self.assertEqual(obj._value, obj_copied._value)
2594 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2597 integers(min_value=1).map(tag_encode),
2599 def test_stripped(self, value, tag_impl):
2600 obj = ObjectIdentifier(value, impl=tag_impl)
2601 with self.assertRaises(NotEnoughData):
2602 obj.decode(obj.encode()[:-1])
2606 integers(min_value=1).map(tag_ctxc),
2608 def test_stripped_expl(self, value, tag_expl):
2609 obj = ObjectIdentifier(value, expl=tag_expl)
2610 with self.assertRaises(NotEnoughData):
2611 obj.decode(obj.encode()[:-1])
2614 integers(min_value=31),
2615 integers(min_value=0),
2618 def test_bad_tag(self, tag, offset, decode_path):
2619 with self.assertRaises(DecodeError) as err:
2620 ObjectIdentifier().decode(
2621 tag_encode(tag)[:-1],
2623 decode_path=decode_path,
2626 self.assertEqual(err.exception.offset, offset)
2627 self.assertEqual(err.exception.decode_path, decode_path)
2630 integers(min_value=128),
2631 integers(min_value=0),
2634 def test_bad_len(self, l, offset, decode_path):
2635 with self.assertRaises(DecodeError) as err:
2636 ObjectIdentifier().decode(
2637 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2639 decode_path=decode_path,
2642 self.assertEqual(err.exception.offset, offset)
2643 self.assertEqual(err.exception.decode_path, decode_path)
2645 def test_zero_oid(self):
2646 with self.assertRaises(NotEnoughData):
2647 ObjectIdentifier().decode(
2648 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2651 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2652 @given(oid_strategy())
2653 def test_unfinished_oid(self, value):
2654 assume(list(value)[-1] > 255)
2655 obj_encoded = ObjectIdentifier(value).encode()
2656 obj, _ = ObjectIdentifier().decode(obj_encoded)
2657 data = obj_encoded[obj.tlen + obj.llen:-1]
2659 ObjectIdentifier.tag_default,
2660 len_encode(len(data)),
2663 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2666 @given(integers(min_value=0))
2667 def test_invalid_short(self, value):
2668 with self.assertRaises(InvalidOID):
2669 ObjectIdentifier((value,))
2670 with self.assertRaises(InvalidOID):
2671 ObjectIdentifier("%d" % value)
2673 @given(integers(min_value=3), integers(min_value=0))
2674 def test_invalid_first_arc(self, first_arc, second_arc):
2675 with self.assertRaises(InvalidOID):
2676 ObjectIdentifier((first_arc, second_arc))
2677 with self.assertRaises(InvalidOID):
2678 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2680 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2681 def test_invalid_second_arc(self, first_arc, second_arc):
2682 with self.assertRaises(InvalidOID):
2683 ObjectIdentifier((first_arc, second_arc))
2684 with self.assertRaises(InvalidOID):
2685 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2687 @given(text(alphabet=ascii_letters + ".", min_size=1))
2688 def test_junk(self, oid):
2689 with self.assertRaises(InvalidOID):
2690 ObjectIdentifier(oid)
2692 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2693 @given(oid_strategy())
2694 def test_validness(self, oid):
2695 obj = ObjectIdentifier(oid)
2696 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2699 pprint(obj, big_blobs=True, with_decode_path=True)
2701 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2703 oid_values_strategy(),
2705 integers(min_value=1).map(tag_ctxc),
2706 integers(min_value=0),
2709 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2710 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2711 _, _, _, default, optional, _decoded = values
2720 pprint(obj, big_blobs=True, with_decode_path=True)
2721 self.assertFalse(obj.expled)
2722 obj_encoded = obj.encode()
2723 obj_expled = obj(value, expl=tag_expl)
2724 self.assertTrue(obj_expled.expled)
2726 list(obj_expled.pps())
2727 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2728 obj_expled_encoded = obj_expled.encode()
2729 ctx_copied = deepcopy(ctx_dummy)
2730 obj_decoded, tail = obj_expled.decode(
2731 obj_expled_encoded + tail_junk,
2735 self.assertDictEqual(ctx_copied, ctx_dummy)
2737 list(obj_decoded.pps())
2738 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2739 self.assertEqual(tail, tail_junk)
2740 self.assertEqual(obj_decoded, obj_expled)
2741 self.assertNotEqual(obj_decoded, obj)
2742 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2743 self.assertEqual(tuple(obj_decoded), tuple(obj))
2744 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2745 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2746 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2748 obj_decoded.expl_llen,
2749 len(len_encode(len(obj_encoded))),
2751 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2752 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2755 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2757 self.assertEqual(obj_decoded.expl_offset, offset)
2758 assert_exceeding_data(
2760 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2765 oid_strategy().map(ObjectIdentifier),
2766 oid_strategy().map(ObjectIdentifier),
2768 def test_add(self, oid1, oid2):
2769 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2770 for oid_to_add in (oid2, tuple(oid2)):
2771 self.assertEqual(oid1 + oid_to_add, oid_expect)
2772 with self.assertRaises(InvalidValueType):
2775 def test_go_vectors_valid(self):
2776 for data, expect in (
2778 (b"\x55\x02", (2, 5, 2)),
2779 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2780 (b"\x81\x34\x03", (2, 100, 3)),
2783 ObjectIdentifier().decode(b"".join((
2784 ObjectIdentifier.tag_default,
2785 len_encode(len(data)),
2791 def test_go_vectors_invalid(self):
2792 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2793 with self.assertRaises(DecodeError):
2794 ObjectIdentifier().decode(b"".join((
2795 Integer.tag_default,
2796 len_encode(len(data)),
2800 def test_x690_vector(self):
2802 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2803 ObjectIdentifier((2, 999, 3)),
2806 def test_nonnormalized_first_arc(self):
2808 ObjectIdentifier.tag_default +
2811 ObjectIdentifier((1, 0)).encode()[-1:]
2813 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2814 self.assertTrue(obj.ber_encoded)
2815 self.assertTrue(obj.bered)
2817 self.assertTrue(obj.ber_encoded)
2818 self.assertTrue(obj.bered)
2819 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2820 ObjectIdentifier().decode(tampered)
2822 @given(data_strategy())
2823 def test_nonnormalized_arcs(self, d):
2824 arcs = d.draw(lists(
2825 integers(min_value=0, max_value=100),
2829 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2830 _, _, lv = tag_strip(dered)
2831 _, _, v = len_decode(lv)
2832 v_no_first_arc = v[1:]
2833 idx_for_tamper = d.draw(integers(
2835 max_value=len(v_no_first_arc) - 1,
2837 tampered = list(bytearray(v_no_first_arc))
2838 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2839 tampered.insert(idx_for_tamper, 0x80)
2840 tampered = bytes(bytearray(tampered))
2842 ObjectIdentifier.tag_default +
2843 len_encode(len(tampered)) +
2846 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2847 self.assertTrue(obj.ber_encoded)
2848 self.assertTrue(obj.bered)
2850 self.assertTrue(obj.ber_encoded)
2851 self.assertTrue(obj.bered)
2852 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2853 ObjectIdentifier().decode(tampered)
2857 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2859 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2860 values = list(draw(sets(
2862 min_size=len(schema),
2863 max_size=len(schema),
2865 schema = list(zip(schema, values))
2866 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2870 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2872 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2873 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2874 optional = draw(one_of(none(), booleans()))
2876 draw(integers(min_value=0)),
2877 draw(integers(min_value=0)),
2878 draw(integers(min_value=0)),
2880 return (schema, value, impl, expl, default, optional, _decoded)
2883 class TestEnumerated(CommonMixin, TestCase):
2884 class EWhatever(Enumerated):
2885 schema = (("whatever", 0),)
2887 base_klass = EWhatever
2889 def test_schema_required(self):
2890 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2893 def test_invalid_value_type(self):
2894 with self.assertRaises(InvalidValueType) as err:
2895 self.base_klass((1, 2))
2898 @given(sets(text_letters(), min_size=2))
2899 def test_unknown_name(self, schema_input):
2900 missing = schema_input.pop()
2902 class E(Enumerated):
2903 schema = [(n, 123) for n in schema_input]
2904 with self.assertRaises(ObjUnknown) as err:
2909 sets(text_letters(), min_size=2),
2910 sets(integers(), min_size=2),
2912 def test_unknown_value(self, schema_input, values_input):
2914 missing_value = values_input.pop()
2915 _input = list(zip(schema_input, values_input))
2917 class E(Enumerated):
2919 with self.assertRaises(DecodeError) as err:
2924 def test_optional(self, optional):
2925 obj = self.base_klass(default="whatever", optional=optional)
2926 self.assertTrue(obj.optional)
2928 def test_ready(self):
2929 obj = self.base_klass()
2930 self.assertFalse(obj.ready)
2933 pprint(obj, big_blobs=True, with_decode_path=True)
2934 with self.assertRaises(ObjNotReady) as err:
2937 obj = self.base_klass("whatever")
2938 self.assertTrue(obj.ready)
2941 pprint(obj, big_blobs=True, with_decode_path=True)
2943 @given(integers(), integers(), binary(), binary())
2944 def test_comparison(self, value1, value2, tag1, tag2):
2945 class E(Enumerated):
2947 ("whatever0", value1),
2948 ("whatever1", value2),
2951 class EInherited(E):
2953 for klass in (E, EInherited):
2954 obj1 = klass(value1)
2955 obj2 = klass(value2)
2956 self.assertEqual(obj1 == obj2, value1 == value2)
2957 self.assertEqual(obj1 != obj2, value1 != value2)
2958 self.assertEqual(obj1 == int(obj2), value1 == value2)
2959 obj1 = klass(value1, impl=tag1)
2960 obj2 = klass(value1, impl=tag2)
2961 self.assertEqual(obj1 == obj2, tag1 == tag2)
2962 self.assertEqual(obj1 != obj2, tag1 != tag2)
2964 @given(data_strategy())
2965 def test_call(self, d):
2974 ) = d.draw(enumerated_values_strategy())
2976 class E(Enumerated):
2977 schema = schema_initial
2979 value=value_initial,
2982 default=default_initial,
2983 optional=optional_initial or False,
2984 _decoded=_decoded_initial,
2994 ) = d.draw(enumerated_values_strategy(
2995 schema=schema_initial,
2996 do_expl=impl_initial is None,
3006 value_expected = default if value is None else value
3008 default_initial if value_expected is None
3013 dict(schema_initial).get(value_expected, value_expected),
3015 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3016 self.assertEqual(obj.expl_tag, expl or expl_initial)
3019 default_initial if default is None else default,
3021 if obj.default is None:
3022 optional = optional_initial if optional is None else optional
3023 optional = False if optional is None else optional
3026 self.assertEqual(obj.optional, optional)
3027 self.assertEqual(obj.specs, dict(schema_initial))
3029 @given(enumerated_values_strategy())
3030 def test_copy(self, values):
3031 schema_input, value, impl, expl, default, optional, _decoded = values
3033 class E(Enumerated):
3034 schema = schema_input
3044 for copy_func in copy_funcs:
3045 obj_copied = copy_func(obj)
3046 self.assert_copied_basic_fields(obj, obj_copied)
3047 self.assertEqual(obj.specs, obj_copied.specs)
3049 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3050 @given(data_strategy())
3051 def test_symmetric(self, d):
3052 schema_input, _, _, _, default, optional, _decoded = d.draw(
3053 enumerated_values_strategy(),
3055 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3056 offset = d.draw(integers(min_value=0))
3057 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3058 tail_junk = d.draw(binary(max_size=5))
3060 class E(Enumerated):
3061 schema = schema_input
3070 pprint(obj, big_blobs=True, with_decode_path=True)
3071 self.assertFalse(obj.expled)
3072 obj_encoded = obj.encode()
3073 obj_expled = obj(value, expl=tag_expl)
3074 self.assertTrue(obj_expled.expled)
3076 list(obj_expled.pps())
3077 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3078 obj_expled_encoded = obj_expled.encode()
3079 ctx_copied = deepcopy(ctx_dummy)
3080 obj_decoded, tail = obj_expled.decode(
3081 obj_expled_encoded + tail_junk,
3085 self.assertDictEqual(ctx_copied, ctx_dummy)
3087 list(obj_decoded.pps())
3088 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3089 self.assertEqual(tail, tail_junk)
3090 self.assertEqual(obj_decoded, obj_expled)
3091 self.assertNotEqual(obj_decoded, obj)
3092 self.assertEqual(int(obj_decoded), int(obj_expled))
3093 self.assertEqual(int(obj_decoded), int(obj))
3094 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3095 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3096 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3098 obj_decoded.expl_llen,
3099 len(len_encode(len(obj_encoded))),
3101 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3102 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3105 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3107 self.assertEqual(obj_decoded.expl_offset, offset)
3108 assert_exceeding_data(
3110 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3116 def string_values_strategy(draw, alphabet, do_expl=False):
3117 bound_min, bound_max = sorted(draw(sets(
3118 integers(min_value=0, max_value=1 << 7),
3122 value = draw(one_of(
3124 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3126 default = draw(one_of(
3128 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3131 if draw(booleans()):
3132 bounds = (bound_min, bound_max)
3136 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3138 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3139 optional = draw(one_of(none(), booleans()))
3141 draw(integers(min_value=0)),
3142 draw(integers(min_value=0)),
3143 draw(integers(min_value=0)),
3145 return (value, bounds, impl, expl, default, optional, _decoded)
3148 class StringMixin(object):
3149 def test_invalid_value_type(self):
3150 with self.assertRaises(InvalidValueType) as err:
3151 self.base_klass((1, 2))
3154 def text_alphabet(self):
3155 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3156 return printable + whitespace
3160 def test_optional(self, optional):
3161 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3162 self.assertTrue(obj.optional)
3164 @given(data_strategy())
3165 def test_ready(self, d):
3166 obj = self.base_klass()
3167 self.assertFalse(obj.ready)
3170 pprint(obj, big_blobs=True, with_decode_path=True)
3172 with self.assertRaises(ObjNotReady) as err:
3175 value = d.draw(text(alphabet=self.text_alphabet()))
3176 obj = self.base_klass(value)
3177 self.assertTrue(obj.ready)
3180 pprint(obj, big_blobs=True, with_decode_path=True)
3183 @given(data_strategy())
3184 def test_comparison(self, d):
3185 value1 = d.draw(text(alphabet=self.text_alphabet()))
3186 value2 = d.draw(text(alphabet=self.text_alphabet()))
3187 tag1 = d.draw(binary(min_size=1))
3188 tag2 = d.draw(binary(min_size=1))
3189 obj1 = self.base_klass(value1)
3190 obj2 = self.base_klass(value2)
3191 self.assertEqual(obj1 == obj2, value1 == value2)
3192 self.assertEqual(obj1 != obj2, value1 != value2)
3193 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3194 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3195 obj1 = self.base_klass(value1, impl=tag1)
3196 obj2 = self.base_klass(value1, impl=tag2)
3197 self.assertEqual(obj1 == obj2, tag1 == tag2)
3198 self.assertEqual(obj1 != obj2, tag1 != tag2)
3200 @given(data_strategy())
3201 def test_bounds_satisfied(self, d):
3202 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3203 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3204 value = d.draw(text(
3205 alphabet=self.text_alphabet(),
3209 self.base_klass(value=value, bounds=(bound_min, bound_max))
3211 @given(data_strategy())
3212 def test_bounds_unsatisfied(self, d):
3213 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3214 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3215 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3216 with self.assertRaises(BoundsError) as err:
3217 self.base_klass(value=value, bounds=(bound_min, bound_max))
3219 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3220 self.base_klass(bounds=(bound_min, bound_max)).decode(
3221 self.base_klass(value).encode()
3224 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3225 with self.assertRaises(BoundsError) as err:
3226 self.base_klass(value=value, bounds=(bound_min, bound_max))
3228 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3229 self.base_klass(bounds=(bound_min, bound_max)).decode(
3230 self.base_klass(value).encode()
3234 @given(data_strategy())
3235 def test_call(self, d):
3244 ) = d.draw(string_values_strategy(self.text_alphabet()))
3245 obj_initial = self.base_klass(
3251 optional_initial or False,
3262 ) = d.draw(string_values_strategy(
3263 self.text_alphabet(),
3264 do_expl=impl_initial is None,
3266 if (default is None) and (obj_initial.default is not None):
3269 (bounds is None) and
3270 (value is not None) and
3271 (bounds_initial is not None) and
3272 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3276 (bounds is None) and
3277 (default is not None) and
3278 (bounds_initial is not None) and
3279 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3282 obj = obj_initial(value, bounds, impl, expl, default, optional)
3284 value_expected = default if value is None else value
3286 default_initial if value_expected is None
3289 self.assertEqual(obj, value_expected)
3290 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3291 self.assertEqual(obj.expl_tag, expl or expl_initial)
3294 default_initial if default is None else default,
3296 if obj.default is None:
3297 optional = optional_initial if optional is None else optional
3298 optional = False if optional is None else optional
3301 self.assertEqual(obj.optional, optional)
3303 (obj._bound_min, obj._bound_max),
3304 bounds or bounds_initial or (0, float("+inf")),
3307 @given(data_strategy())
3308 def test_copy(self, d):
3309 values = d.draw(string_values_strategy(self.text_alphabet()))
3310 obj = self.base_klass(*values)
3311 for copy_func in copy_funcs:
3312 obj_copied = copy_func(obj)
3313 self.assert_copied_basic_fields(obj, obj_copied)
3314 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3315 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3316 self.assertEqual(obj._value, obj_copied._value)
3318 @given(data_strategy())
3319 def test_stripped(self, d):
3320 value = d.draw(text(alphabet=self.text_alphabet()))
3321 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3322 obj = self.base_klass(value, impl=tag_impl)
3323 with self.assertRaises(NotEnoughData):
3324 obj.decode(obj.encode()[:-1])
3326 @given(data_strategy())
3327 def test_stripped_expl(self, d):
3328 value = d.draw(text(alphabet=self.text_alphabet()))
3329 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3330 obj = self.base_klass(value, expl=tag_expl)
3331 with self.assertRaises(NotEnoughData):
3332 obj.decode(obj.encode()[:-1])
3335 integers(min_value=31),
3336 integers(min_value=0),
3339 def test_bad_tag(self, tag, offset, decode_path):
3340 with self.assertRaises(DecodeError) as err:
3341 self.base_klass().decode(
3342 tag_encode(tag)[:-1],
3344 decode_path=decode_path,
3347 self.assertEqual(err.exception.offset, offset)
3348 self.assertEqual(err.exception.decode_path, decode_path)
3351 integers(min_value=128),
3352 integers(min_value=0),
3355 def test_bad_len(self, l, offset, decode_path):
3356 with self.assertRaises(DecodeError) as err:
3357 self.base_klass().decode(
3358 self.base_klass.tag_default + len_encode(l)[:-1],
3360 decode_path=decode_path,
3363 self.assertEqual(err.exception.offset, offset)
3364 self.assertEqual(err.exception.decode_path, decode_path)
3367 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3368 integers(min_value=0),
3371 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3372 value, bound_min = list(sorted(ints))
3374 class String(self.base_klass):
3375 # Multiply this value by four, to satisfy UTF-32 bounds
3376 # (4 bytes per character) validation
3377 bounds = (bound_min * 4, bound_min * 4)
3378 with self.assertRaises(DecodeError) as err:
3380 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3382 decode_path=decode_path,
3385 self.assertEqual(err.exception.offset, offset)
3386 self.assertEqual(err.exception.decode_path, decode_path)
3388 @given(data_strategy())
3389 def test_symmetric(self, d):
3390 values = d.draw(string_values_strategy(self.text_alphabet()))
3391 value = d.draw(text(alphabet=self.text_alphabet()))
3392 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3393 offset = d.draw(integers(min_value=0))
3394 tail_junk = d.draw(binary(max_size=5))
3395 _, _, _, _, default, optional, _decoded = values
3396 obj = self.base_klass(
3404 pprint(obj, big_blobs=True, with_decode_path=True)
3405 self.assertFalse(obj.expled)
3406 obj_encoded = obj.encode()
3407 obj_expled = obj(value, expl=tag_expl)
3408 self.assertTrue(obj_expled.expled)
3410 list(obj_expled.pps())
3411 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3412 obj_expled_encoded = obj_expled.encode()
3413 ctx_copied = deepcopy(ctx_dummy)
3414 obj_decoded, tail = obj_expled.decode(
3415 obj_expled_encoded + tail_junk,
3419 self.assertDictEqual(ctx_copied, ctx_dummy)
3421 list(obj_decoded.pps())
3422 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3423 self.assertEqual(tail, tail_junk)
3424 self.assertEqual(obj_decoded, obj_expled)
3425 self.assertNotEqual(obj_decoded, obj)
3426 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3427 self.assertEqual(bytes(obj_decoded), bytes(obj))
3428 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3429 self.assertEqual(text_type(obj_decoded), text_type(obj))
3430 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3431 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3432 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3434 obj_decoded.expl_llen,
3435 len(len_encode(len(obj_encoded))),
3437 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3438 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3441 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3443 self.assertEqual(obj_decoded.expl_offset, offset)
3444 assert_exceeding_data(
3446 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3451 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3452 base_klass = UTF8String
3455 cyrillic_letters = text(
3456 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3462 class UnicodeDecodeErrorMixin(object):
3463 @given(cyrillic_letters)
3464 def test_unicode_decode_error(self, cyrillic_text):
3465 with self.assertRaises(DecodeError):
3466 self.base_klass(cyrillic_text)
3469 class TestNumericString(StringMixin, CommonMixin, TestCase):
3470 base_klass = NumericString
3472 def text_alphabet(self):
3475 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3476 def test_non_numeric(self, non_numeric_text):
3477 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3478 self.base_klass(non_numeric_text)
3481 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3482 integers(min_value=0),
3485 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3486 value, bound_min = list(sorted(ints))
3488 class String(self.base_klass):
3489 bounds = (bound_min, bound_min)
3490 with self.assertRaises(DecodeError) as err:
3492 self.base_klass(b"1" * value).encode(),
3494 decode_path=decode_path,
3497 self.assertEqual(err.exception.offset, offset)
3498 self.assertEqual(err.exception.decode_path, decode_path)
3501 class TestPrintableString(
3502 UnicodeDecodeErrorMixin,
3507 base_klass = PrintableString
3509 def text_alphabet(self):
3510 return ascii_letters + digits + " '()+,-./:=?"
3512 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3513 def test_non_printable(self, non_printable_text):
3514 with assertRaisesRegex(self, DecodeError, "non-printable"):
3515 self.base_klass(non_printable_text)
3518 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3519 integers(min_value=0),
3522 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3523 value, bound_min = list(sorted(ints))
3525 class String(self.base_klass):
3526 bounds = (bound_min, bound_min)
3527 with self.assertRaises(DecodeError) as err:
3529 self.base_klass(b"1" * value).encode(),
3531 decode_path=decode_path,
3534 self.assertEqual(err.exception.offset, offset)
3535 self.assertEqual(err.exception.decode_path, decode_path)
3537 def test_allowable_invalid_chars(self):
3539 ("*", {"allow_asterisk": True}),
3540 ("&", {"allow_ampersand": True}),
3541 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3543 s = "hello invalid " + c
3544 with assertRaisesRegex(self, DecodeError, "non-printable"):
3546 self.base_klass(s, **kwargs)
3547 klass = self.base_klass(**kwargs)
3553 class TestTeletexString(
3554 UnicodeDecodeErrorMixin,
3559 base_klass = TeletexString
3562 class TestVideotexString(
3563 UnicodeDecodeErrorMixin,
3568 base_klass = VideotexString
3571 class TestIA5String(
3572 UnicodeDecodeErrorMixin,
3577 base_klass = IA5String
3580 class TestGraphicString(
3581 UnicodeDecodeErrorMixin,
3586 base_klass = GraphicString
3589 class TestVisibleString(
3590 UnicodeDecodeErrorMixin,
3595 base_klass = VisibleString
3597 def test_x690_vector(self):
3598 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3599 self.assertSequenceEqual(tail, b"")
3600 self.assertEqual(str(obj), "Jones")
3601 self.assertFalse(obj.ber_encoded)
3602 self.assertFalse(obj.lenindef)
3603 self.assertFalse(obj.bered)
3605 obj, tail = VisibleString().decode(
3606 hexdec("3A0904034A6F6E04026573"),
3607 ctx={"bered": True},
3609 self.assertSequenceEqual(tail, b"")
3610 self.assertEqual(str(obj), "Jones")
3611 self.assertTrue(obj.ber_encoded)
3612 self.assertFalse(obj.lenindef)
3613 self.assertTrue(obj.bered)
3615 self.assertTrue(obj.ber_encoded)
3616 self.assertFalse(obj.lenindef)
3617 self.assertTrue(obj.bered)
3619 obj, tail = VisibleString().decode(
3620 hexdec("3A8004034A6F6E040265730000"),
3621 ctx={"bered": True},
3623 self.assertSequenceEqual(tail, b"")
3624 self.assertEqual(str(obj), "Jones")
3625 self.assertTrue(obj.ber_encoded)
3626 self.assertTrue(obj.lenindef)
3627 self.assertTrue(obj.bered)
3629 self.assertTrue(obj.ber_encoded)
3630 self.assertTrue(obj.lenindef)
3631 self.assertTrue(obj.bered)
3634 class TestGeneralString(
3635 UnicodeDecodeErrorMixin,
3640 base_klass = GeneralString
3643 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3644 base_klass = UniversalString
3647 class TestBMPString(StringMixin, CommonMixin, TestCase):
3648 base_klass = BMPString
3652 def generalized_time_values_strategy(
3660 if draw(booleans()):
3661 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3663 value = value.replace(microsecond=0)
3665 if draw(booleans()):
3666 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3668 default = default.replace(microsecond=0)
3672 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3674 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3675 optional = draw(one_of(none(), booleans()))
3677 draw(integers(min_value=0)),
3678 draw(integers(min_value=0)),
3679 draw(integers(min_value=0)),
3681 return (value, impl, expl, default, optional, _decoded)
3684 class TimeMixin(object):
3685 def test_invalid_value_type(self):
3686 with self.assertRaises(InvalidValueType) as err:
3687 self.base_klass(datetime.now().timetuple())
3690 @given(data_strategy())
3691 def test_optional(self, d):
3692 default = d.draw(datetimes(
3693 min_value=self.min_datetime,
3694 max_value=self.max_datetime,
3696 optional = d.draw(booleans())
3697 obj = self.base_klass(default=default, optional=optional)
3698 self.assertTrue(obj.optional)
3700 @given(data_strategy())
3701 def test_ready(self, d):
3702 obj = self.base_klass()
3703 self.assertFalse(obj.ready)
3706 pprint(obj, big_blobs=True, with_decode_path=True)
3707 with self.assertRaises(ObjNotReady) as err:
3710 value = d.draw(datetimes(min_value=self.min_datetime))
3711 obj = self.base_klass(value)
3712 self.assertTrue(obj.ready)
3715 pprint(obj, big_blobs=True, with_decode_path=True)
3717 @given(data_strategy())
3718 def test_comparison(self, d):
3719 value1 = d.draw(datetimes(
3720 min_value=self.min_datetime,
3721 max_value=self.max_datetime,
3723 value2 = d.draw(datetimes(
3724 min_value=self.min_datetime,
3725 max_value=self.max_datetime,
3727 tag1 = d.draw(binary(min_size=1))
3728 tag2 = d.draw(binary(min_size=1))
3730 value1 = value1.replace(microsecond=0)
3731 value2 = value2.replace(microsecond=0)
3732 obj1 = self.base_klass(value1)
3733 obj2 = self.base_klass(value2)
3734 self.assertEqual(obj1 == obj2, value1 == value2)
3735 self.assertEqual(obj1 != obj2, value1 != value2)
3736 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3737 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3738 obj1 = self.base_klass(value1, impl=tag1)
3739 obj2 = self.base_klass(value1, impl=tag2)
3740 self.assertEqual(obj1 == obj2, tag1 == tag2)
3741 self.assertEqual(obj1 != obj2, tag1 != tag2)
3743 @given(data_strategy())
3744 def test_call(self, d):
3752 ) = d.draw(generalized_time_values_strategy(
3753 min_datetime=self.min_datetime,
3754 max_datetime=self.max_datetime,
3755 omit_ms=self.omit_ms,
3757 obj_initial = self.base_klass(
3758 value=value_initial,
3761 default=default_initial,
3762 optional=optional_initial or False,
3763 _decoded=_decoded_initial,
3772 ) = d.draw(generalized_time_values_strategy(
3773 min_datetime=self.min_datetime,
3774 max_datetime=self.max_datetime,
3775 omit_ms=self.omit_ms,
3776 do_expl=impl_initial is None,
3786 value_expected = default if value is None else value
3788 default_initial if value_expected is None
3791 self.assertEqual(obj, value_expected)
3792 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3793 self.assertEqual(obj.expl_tag, expl or expl_initial)
3796 default_initial if default is None else default,
3798 if obj.default is None:
3799 optional = optional_initial if optional is None else optional
3800 optional = False if optional is None else optional
3803 self.assertEqual(obj.optional, optional)
3805 @given(data_strategy())
3806 def test_copy(self, d):
3807 values = d.draw(generalized_time_values_strategy(
3808 min_datetime=self.min_datetime,
3809 max_datetime=self.max_datetime,
3811 obj = self.base_klass(*values)
3812 for copy_func in copy_funcs:
3813 obj_copied = copy_func(obj)
3814 self.assert_copied_basic_fields(obj, obj_copied)
3815 self.assertEqual(obj._value, obj_copied._value)
3817 @given(data_strategy())
3818 def test_stripped(self, d):
3819 value = d.draw(datetimes(
3820 min_value=self.min_datetime,
3821 max_value=self.max_datetime,
3823 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3824 obj = self.base_klass(value, impl=tag_impl)
3825 with self.assertRaises(NotEnoughData):
3826 obj.decode(obj.encode()[:-1])
3828 @given(data_strategy())
3829 def test_stripped_expl(self, d):
3830 value = d.draw(datetimes(
3831 min_value=self.min_datetime,
3832 max_value=self.max_datetime,
3834 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3835 obj = self.base_klass(value, expl=tag_expl)
3836 with self.assertRaises(NotEnoughData):
3837 obj.decode(obj.encode()[:-1])
3839 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3840 @given(data_strategy())
3841 def test_symmetric(self, d):
3842 values = d.draw(generalized_time_values_strategy(
3843 min_datetime=self.min_datetime,
3844 max_datetime=self.max_datetime,
3846 value = d.draw(datetimes(
3847 min_value=self.min_datetime,
3848 max_value=self.max_datetime,
3850 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3851 offset = d.draw(integers(min_value=0))
3852 tail_junk = d.draw(binary(max_size=5))
3853 _, _, _, default, optional, _decoded = values
3854 obj = self.base_klass(
3862 pprint(obj, big_blobs=True, with_decode_path=True)
3863 self.assertFalse(obj.expled)
3864 obj_encoded = obj.encode()
3865 self.additional_symmetric_check(value, obj_encoded)
3866 obj_expled = obj(value, expl=tag_expl)
3867 self.assertTrue(obj_expled.expled)
3869 list(obj_expled.pps())
3870 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3871 obj_expled_encoded = obj_expled.encode()
3872 ctx_copied = deepcopy(ctx_dummy)
3873 obj_decoded, tail = obj_expled.decode(
3874 obj_expled_encoded + tail_junk,
3878 self.assertDictEqual(ctx_copied, ctx_dummy)
3880 list(obj_decoded.pps())
3881 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3882 self.assertEqual(tail, tail_junk)
3883 self.assertEqual(obj_decoded, obj_expled)
3884 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3885 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3886 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3887 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3888 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3890 obj_decoded.expl_llen,
3891 len(len_encode(len(obj_encoded))),
3893 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3894 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3897 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3899 self.assertEqual(obj_decoded.expl_offset, offset)
3900 assert_exceeding_data(
3902 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3907 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3908 base_klass = GeneralizedTime
3910 min_datetime = datetime(1900, 1, 1)
3911 max_datetime = datetime(9999, 12, 31)
3913 def additional_symmetric_check(self, value, obj_encoded):
3914 if value.microsecond > 0:
3915 self.assertFalse(obj_encoded.endswith(b"0Z"))
3917 def test_x690_vector_valid(self):
3921 b"19920722132100.3Z",
3923 GeneralizedTime(data)
3925 def test_x690_vector_invalid(self):
3928 b"19920622123421.0Z",
3929 b"19920722132100.30Z",
3931 with self.assertRaises(DecodeError) as err:
3932 GeneralizedTime(data)
3935 def test_go_vectors_invalid(self):
3947 b"-20100102030410Z",
3948 b"2010-0102030410Z",
3949 b"2010-0002030410Z",
3950 b"201001-02030410Z",
3951 b"20100102-030410Z",
3952 b"2010010203-0410Z",
3953 b"201001020304-10Z",
3954 # These ones are INVALID in *DER*, but accepted
3955 # by Go's encoding/asn1
3956 b"20100102030405+0607",
3957 b"20100102030405-0607",
3959 with self.assertRaises(DecodeError) as err:
3960 GeneralizedTime(data)
3963 def test_go_vectors_valid(self):
3965 GeneralizedTime(b"20100102030405Z").todatetime(),
3966 datetime(2010, 1, 2, 3, 4, 5, 0),
3971 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3972 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3974 binary(min_size=1, max_size=1),
3976 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3977 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3980 def test_junk(self, part0, part1, part2):
3981 junk = part0 + part1 + part2
3982 assume(not (set(junk) <= set(digits.encode("ascii"))))
3983 with self.assertRaises(DecodeError):
3984 GeneralizedTime().decode(
3985 GeneralizedTime.tag_default +
3986 len_encode(len(junk)) +
3992 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3993 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3995 binary(min_size=1, max_size=1),
3997 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3998 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4001 def test_junk_dm(self, part0, part1, part2):
4002 junk = part0 + part1 + part2
4003 assume(not (set(junk) <= set(digits.encode("ascii"))))
4004 with self.assertRaises(DecodeError):
4005 GeneralizedTime().decode(
4006 GeneralizedTime.tag_default +
4007 len_encode(len(junk)) +
4011 def test_ns_fractions(self):
4012 GeneralizedTime(b"20010101000000.000001Z")
4013 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
4014 GeneralizedTime(b"20010101000000.0000001Z")
4017 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4018 base_klass = UTCTime
4020 min_datetime = datetime(2000, 1, 1)
4021 max_datetime = datetime(2049, 12, 31)
4023 def additional_symmetric_check(self, value, obj_encoded):
4026 def test_x690_vector_valid(self):
4034 def test_x690_vector_invalid(self):
4039 with self.assertRaises(DecodeError) as err:
4043 def test_go_vectors_invalid(self):
4069 # These ones are INVALID in *DER*, but accepted
4070 # by Go's encoding/asn1
4071 b"910506164540-0700",
4072 b"910506164540+0730",
4076 with self.assertRaises(DecodeError) as err:
4080 def test_go_vectors_valid(self):
4082 UTCTime(b"910506234540Z").todatetime(),
4083 datetime(1991, 5, 6, 23, 45, 40, 0),
4086 @given(integers(min_value=0, max_value=49))
4087 def test_pre50(self, year):
4089 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4093 @given(integers(min_value=50, max_value=99))
4094 def test_post50(self, year):
4096 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4102 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4103 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4105 binary(min_size=1, max_size=1),
4107 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4108 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4111 def test_junk(self, part0, part1, part2):
4112 junk = part0 + part1 + part2
4113 assume(not (set(junk) <= set(digits.encode("ascii"))))
4114 with self.assertRaises(DecodeError):
4116 UTCTime.tag_default +
4117 len_encode(len(junk)) +
4123 def any_values_strategy(draw, do_expl=False):
4124 value = draw(one_of(none(), binary()))
4127 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4128 optional = draw(one_of(none(), booleans()))
4130 draw(integers(min_value=0)),
4131 draw(integers(min_value=0)),
4132 draw(integers(min_value=0)),
4134 return (value, expl, optional, _decoded)
4137 class AnyInherited(Any):
4141 class TestAny(CommonMixin, TestCase):
4144 def test_invalid_value_type(self):
4145 with self.assertRaises(InvalidValueType) as err:
4150 def test_optional(self, optional):
4151 obj = Any(optional=optional)
4152 self.assertEqual(obj.optional, optional)
4155 def test_ready(self, value):
4157 self.assertFalse(obj.ready)
4160 pprint(obj, big_blobs=True, with_decode_path=True)
4161 with self.assertRaises(ObjNotReady) as err:
4165 self.assertTrue(obj.ready)
4168 pprint(obj, big_blobs=True, with_decode_path=True)
4171 def test_basic(self, value):
4172 integer_encoded = Integer(value).encode()
4174 Any(integer_encoded),
4175 Any(Integer(value)),
4176 Any(Any(Integer(value))),
4178 self.assertSequenceEqual(bytes(obj), integer_encoded)
4180 obj.decode(obj.encode())[0].vlen,
4181 len(integer_encoded),
4185 pprint(obj, big_blobs=True, with_decode_path=True)
4186 self.assertSequenceEqual(obj.encode(), integer_encoded)
4188 @given(binary(), binary())
4189 def test_comparison(self, value1, value2):
4190 for klass in (Any, AnyInherited):
4191 obj1 = klass(value1)
4192 obj2 = klass(value2)
4193 self.assertEqual(obj1 == obj2, value1 == value2)
4194 self.assertEqual(obj1 != obj2, value1 != value2)
4195 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4197 @given(data_strategy())
4198 def test_call(self, d):
4199 for klass in (Any, AnyInherited):
4205 ) = d.draw(any_values_strategy())
4206 obj_initial = klass(
4209 optional_initial or False,
4217 ) = d.draw(any_values_strategy(do_expl=True))
4218 obj = obj_initial(value, expl, optional)
4220 value_expected = None if value is None else value
4221 self.assertEqual(obj, value_expected)
4222 self.assertEqual(obj.expl_tag, expl or expl_initial)
4223 if obj.default is None:
4224 optional = optional_initial if optional is None else optional
4225 optional = False if optional is None else optional
4226 self.assertEqual(obj.optional, optional)
4228 def test_simultaneous_impl_expl(self):
4229 # override it, as Any does not have implicit tag
4232 def test_decoded(self):
4233 # override it, as Any does not have implicit tag
4236 @given(any_values_strategy())
4237 def test_copy(self, values):
4238 for klass in (Any, AnyInherited):
4239 obj = klass(*values)
4240 for copy_func in copy_funcs:
4241 obj_copied = copy_func(obj)
4242 self.assert_copied_basic_fields(obj, obj_copied)
4243 self.assertEqual(obj._value, obj_copied._value)
4245 @given(binary().map(OctetString))
4246 def test_stripped(self, value):
4248 with self.assertRaises(NotEnoughData):
4249 obj.decode(obj.encode()[:-1])
4253 integers(min_value=1).map(tag_ctxc),
4255 def test_stripped_expl(self, value, tag_expl):
4256 obj = Any(value, expl=tag_expl)
4257 with self.assertRaises(NotEnoughData):
4258 obj.decode(obj.encode()[:-1])
4261 integers(min_value=31),
4262 integers(min_value=0),
4265 def test_bad_tag(self, tag, offset, decode_path):
4266 with self.assertRaises(DecodeError) as err:
4268 tag_encode(tag)[:-1],
4270 decode_path=decode_path,
4273 self.assertEqual(err.exception.offset, offset)
4274 self.assertEqual(err.exception.decode_path, decode_path)
4277 integers(min_value=128),
4278 integers(min_value=0),
4281 def test_bad_len(self, l, offset, decode_path):
4282 with self.assertRaises(DecodeError) as err:
4284 Any.tag_default + len_encode(l)[:-1],
4286 decode_path=decode_path,
4289 self.assertEqual(err.exception.offset, offset)
4290 self.assertEqual(err.exception.decode_path, decode_path)
4292 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4294 any_values_strategy(),
4295 integers().map(lambda x: Integer(x).encode()),
4296 integers(min_value=1).map(tag_ctxc),
4297 integers(min_value=0),
4300 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4301 for klass in (Any, AnyInherited):
4302 _, _, optional, _decoded = values
4303 obj = klass(value=value, optional=optional, _decoded=_decoded)
4306 pprint(obj, big_blobs=True, with_decode_path=True)
4307 self.assertFalse(obj.expled)
4308 obj_encoded = obj.encode()
4309 obj_expled = obj(value, expl=tag_expl)
4310 self.assertTrue(obj_expled.expled)
4312 list(obj_expled.pps())
4313 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4314 obj_expled_encoded = obj_expled.encode()
4315 ctx_copied = deepcopy(ctx_dummy)
4316 obj_decoded, tail = obj_expled.decode(
4317 obj_expled_encoded + tail_junk,
4321 self.assertDictEqual(ctx_copied, ctx_dummy)
4323 list(obj_decoded.pps())
4324 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4325 self.assertEqual(tail, tail_junk)
4326 self.assertEqual(obj_decoded, obj_expled)
4327 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4328 self.assertEqual(bytes(obj_decoded), bytes(obj))
4329 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4330 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4331 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4333 obj_decoded.expl_llen,
4334 len(len_encode(len(obj_encoded))),
4336 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4337 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4340 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4342 self.assertEqual(obj_decoded.expl_offset, offset)
4343 self.assertEqual(obj_decoded.tlen, 0)
4344 self.assertEqual(obj_decoded.llen, 0)
4345 self.assertEqual(obj_decoded.vlen, len(value))
4346 assert_exceeding_data(
4348 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4353 integers(min_value=1).map(tag_ctxc),
4354 integers(min_value=0, max_value=3),
4355 integers(min_value=0),
4359 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4360 chunk = Boolean(False, expl=expl).encode()
4362 OctetString.tag_default +
4364 b"".join([chunk] * chunks) +
4367 with self.assertRaises(LenIndefForm):
4371 decode_path=decode_path,
4373 obj, tail = Any().decode(
4376 decode_path=decode_path,
4377 ctx={"bered": True},
4379 self.assertSequenceEqual(tail, junk)
4380 self.assertEqual(obj.offset, offset)
4381 self.assertEqual(obj.tlvlen, len(encoded))
4382 self.assertTrue(obj.lenindef)
4383 self.assertFalse(obj.ber_encoded)
4384 self.assertTrue(obj.bered)
4386 self.assertTrue(obj.lenindef)
4387 self.assertFalse(obj.ber_encoded)
4388 self.assertTrue(obj.bered)
4391 pprint(obj, big_blobs=True, with_decode_path=True)
4392 with self.assertRaises(NotEnoughData) as err:
4396 decode_path=decode_path,
4397 ctx={"bered": True},
4399 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4400 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4402 class SeqOf(SequenceOf):
4403 schema = Boolean(expl=expl)
4405 class Seq(Sequence):
4407 ("type", ObjectIdentifier(defines=((("value",), {
4408 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4413 ("type", ObjectIdentifier("1.2.3")),
4414 ("value", Any(encoded)),
4416 seq_encoded = seq.encode()
4417 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4418 self.assertIsNotNone(seq_decoded["value"].defined)
4420 list(seq_decoded.pps())
4421 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4422 self.assertTrue(seq_decoded.bered)
4423 self.assertFalse(seq_decoded["type"].bered)
4424 self.assertTrue(seq_decoded["value"].bered)
4426 chunk = chunk[:-1] + b"\x01"
4427 chunks = b"".join([chunk] * (chunks + 1))
4428 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4430 ("type", ObjectIdentifier("1.2.3")),
4431 ("value", Any(encoded)),
4433 seq_encoded = seq.encode()
4434 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4435 self.assertIsNotNone(seq_decoded["value"].defined)
4437 list(seq_decoded.pps())
4438 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4439 self.assertTrue(seq_decoded.bered)
4440 self.assertFalse(seq_decoded["type"].bered)
4441 self.assertTrue(seq_decoded["value"].bered)
4445 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4447 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4448 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4450 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4451 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4453 min_size=len(names),
4454 max_size=len(names),
4457 (name, Integer(**tag_kwargs))
4458 for name, tag_kwargs in zip(names, tags)
4461 if value_required or draw(booleans()):
4462 value = draw(tuples(
4463 sampled_from([name for name, _ in schema]),
4464 integers().map(Integer),
4468 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4469 default = draw(one_of(
4471 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4473 optional = draw(one_of(none(), booleans()))
4475 draw(integers(min_value=0)),
4476 draw(integers(min_value=0)),
4477 draw(integers(min_value=0)),
4479 return (schema, value, expl, default, optional, _decoded)
4482 class ChoiceInherited(Choice):
4486 class TestChoice(CommonMixin, TestCase):
4488 schema = (("whatever", Boolean()),)
4491 def test_schema_required(self):
4492 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4495 def test_impl_forbidden(self):
4496 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4497 Choice(impl=b"whatever")
4499 def test_invalid_value_type(self):
4500 with self.assertRaises(InvalidValueType) as err:
4501 self.base_klass(123)
4503 with self.assertRaises(ObjUnknown) as err:
4504 self.base_klass(("whenever", Boolean(False)))
4506 with self.assertRaises(InvalidValueType) as err:
4507 self.base_klass(("whatever", Integer(123)))
4511 def test_optional(self, optional):
4512 obj = self.base_klass(
4513 default=self.base_klass(("whatever", Boolean(False))),
4516 self.assertTrue(obj.optional)
4519 def test_ready(self, value):
4520 obj = self.base_klass()
4521 self.assertFalse(obj.ready)
4524 pprint(obj, big_blobs=True, with_decode_path=True)
4525 self.assertIsNone(obj["whatever"])
4526 with self.assertRaises(ObjNotReady) as err:
4529 obj["whatever"] = Boolean()
4530 self.assertFalse(obj.ready)
4533 pprint(obj, big_blobs=True, with_decode_path=True)
4534 obj["whatever"] = Boolean(value)
4535 self.assertTrue(obj.ready)
4538 pprint(obj, big_blobs=True, with_decode_path=True)
4540 @given(booleans(), booleans())
4541 def test_comparison(self, value1, value2):
4542 class WahlInherited(self.base_klass):
4544 for klass in (self.base_klass, WahlInherited):
4545 obj1 = klass(("whatever", Boolean(value1)))
4546 obj2 = klass(("whatever", Boolean(value2)))
4547 self.assertEqual(obj1 == obj2, value1 == value2)
4548 self.assertEqual(obj1 != obj2, value1 != value2)
4549 self.assertEqual(obj1 == obj2._value, value1 == value2)
4550 self.assertFalse(obj1 == obj2._value[1])
4552 @given(data_strategy())
4553 def test_call(self, d):
4554 for klass in (Choice, ChoiceInherited):
4562 ) = d.draw(choice_values_strategy())
4565 schema = schema_initial
4567 value=value_initial,
4569 default=default_initial,
4570 optional=optional_initial or False,
4571 _decoded=_decoded_initial,
4580 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4581 obj = obj_initial(value, expl, default, optional)
4583 value_expected = default if value is None else value
4585 default_initial if value_expected is None
4588 self.assertEqual(obj.choice, value_expected[0])
4589 self.assertEqual(obj.value, int(value_expected[1]))
4590 self.assertEqual(obj.expl_tag, expl or expl_initial)
4591 default_expect = default_initial if default is None else default
4592 if default_expect is not None:
4593 self.assertEqual(obj.default.choice, default_expect[0])
4594 self.assertEqual(obj.default.value, int(default_expect[1]))
4595 if obj.default is None:
4596 optional = optional_initial if optional is None else optional
4597 optional = False if optional is None else optional
4600 self.assertEqual(obj.optional, optional)
4601 self.assertEqual(obj.specs, obj_initial.specs)
4603 def test_simultaneous_impl_expl(self):
4604 # override it, as Any does not have implicit tag
4607 def test_decoded(self):
4608 # override it, as Any does not have implicit tag
4611 @given(choice_values_strategy())
4612 def test_copy(self, values):
4613 _schema, value, expl, default, optional, _decoded = values
4615 class Wahl(self.base_klass):
4617 register_class(Wahl)
4622 optional=optional or False,
4625 for copy_func in copy_funcs:
4626 obj_copied = copy_func(obj)
4627 self.assertIsNone(obj.tag)
4628 self.assertIsNone(obj_copied.tag)
4629 # hack for assert_copied_basic_fields
4630 obj.tag = "whatever"
4631 obj_copied.tag = "whatever"
4632 self.assert_copied_basic_fields(obj, obj_copied)
4634 self.assertEqual(obj._value, obj_copied._value)
4635 self.assertEqual(obj.specs, obj_copied.specs)
4638 def test_stripped(self, value):
4639 obj = self.base_klass(("whatever", Boolean(value)))
4640 with self.assertRaises(NotEnoughData):
4641 obj.decode(obj.encode()[:-1])
4645 integers(min_value=1).map(tag_ctxc),
4647 def test_stripped_expl(self, value, tag_expl):
4648 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4649 with self.assertRaises(NotEnoughData):
4650 obj.decode(obj.encode()[:-1])
4652 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4653 @given(data_strategy())
4654 def test_symmetric(self, d):
4655 _schema, value, _, default, optional, _decoded = d.draw(
4656 choice_values_strategy(value_required=True)
4658 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4659 offset = d.draw(integers(min_value=0))
4660 tail_junk = d.draw(binary(max_size=5))
4662 class Wahl(self.base_klass):
4672 pprint(obj, big_blobs=True, with_decode_path=True)
4673 self.assertFalse(obj.expled)
4674 obj_encoded = obj.encode()
4675 obj_expled = obj(value, expl=tag_expl)
4676 self.assertTrue(obj_expled.expled)
4678 list(obj_expled.pps())
4679 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4680 obj_expled_encoded = obj_expled.encode()
4681 ctx_copied = deepcopy(ctx_dummy)
4682 obj_decoded, tail = obj_expled.decode(
4683 obj_expled_encoded + tail_junk,
4687 self.assertDictEqual(ctx_copied, ctx_dummy)
4689 list(obj_decoded.pps())
4690 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4691 self.assertEqual(tail, tail_junk)
4692 self.assertEqual(obj_decoded, obj_expled)
4693 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4694 self.assertEqual(obj_decoded.value, obj_expled.value)
4695 self.assertEqual(obj_decoded.choice, obj.choice)
4696 self.assertEqual(obj_decoded.value, obj.value)
4697 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4698 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4699 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4701 obj_decoded.expl_llen,
4702 len(len_encode(len(obj_encoded))),
4704 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4705 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4708 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4710 self.assertEqual(obj_decoded.expl_offset, offset)
4711 self.assertSequenceEqual(
4713 obj_decoded.value.fulloffset - offset:
4714 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4718 assert_exceeding_data(
4720 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4725 def test_set_get(self, value):
4728 ("erste", Boolean()),
4729 ("zweite", Integer()),
4732 with self.assertRaises(ObjUnknown) as err:
4733 obj["whatever"] = "whenever"
4734 with self.assertRaises(InvalidValueType) as err:
4735 obj["zweite"] = Boolean(False)
4736 obj["zweite"] = Integer(value)
4738 with self.assertRaises(ObjUnknown) as err:
4741 self.assertIsNone(obj["erste"])
4742 self.assertEqual(obj["zweite"], Integer(value))
4744 def test_tag_mismatch(self):
4747 ("erste", Boolean()),
4749 int_encoded = Integer(123).encode()
4750 bool_encoded = Boolean(False).encode()
4752 obj.decode(bool_encoded)
4753 with self.assertRaises(TagMismatch):
4754 obj.decode(int_encoded)
4756 def test_tag_mismatch_underlying(self):
4757 class SeqOfBoolean(SequenceOf):
4760 class SeqOfInteger(SequenceOf):
4765 ("erste", SeqOfBoolean()),
4768 int_encoded = SeqOfInteger((Integer(123),)).encode()
4769 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4771 obj.decode(bool_encoded)
4772 with self.assertRaises(TagMismatch) as err:
4773 obj.decode(int_encoded)
4774 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4778 def seq_values_strategy(draw, seq_klass, do_expl=False):
4780 if draw(booleans()):
4782 value._value = draw(dictionaries(
4785 booleans().map(Boolean),
4786 integers().map(Integer),
4790 if draw(booleans()):
4791 schema = list(draw(dictionaries(
4794 booleans().map(Boolean),
4795 integers().map(Integer),
4801 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4803 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4805 if draw(booleans()):
4806 default = seq_klass()
4807 default._value = draw(dictionaries(
4810 booleans().map(Boolean),
4811 integers().map(Integer),
4814 optional = draw(one_of(none(), booleans()))
4816 draw(integers(min_value=0)),
4817 draw(integers(min_value=0)),
4818 draw(integers(min_value=0)),
4820 return (value, schema, impl, expl, default, optional, _decoded)
4824 def sequence_strategy(draw, seq_klass):
4825 inputs = draw(lists(
4827 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4828 tuples(just(Integer), integers(), one_of(none(), integers())),
4833 integers(min_value=1),
4834 min_size=len(inputs),
4835 max_size=len(inputs),
4838 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4839 for tag, expled in zip(tags, draw(lists(
4841 min_size=len(inputs),
4842 max_size=len(inputs),
4846 for i, optional in enumerate(draw(lists(
4847 sampled_from(("required", "optional", "empty")),
4848 min_size=len(inputs),
4849 max_size=len(inputs),
4851 if optional in ("optional", "empty"):
4852 inits[i]["optional"] = True
4853 if optional == "empty":
4855 empties = set(empties)
4856 names = list(draw(sets(
4858 min_size=len(inputs),
4859 max_size=len(inputs),
4862 for i, (klass, value, default) in enumerate(inputs):
4863 schema.append((names[i], klass(default=default, **inits[i])))
4864 seq_name = draw(text_letters())
4865 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4868 for i, (klass, value, default) in enumerate(inputs):
4875 "default_value": None if spec.default is None else default,
4879 expect["optional"] = True
4881 expect["presented"] = True
4882 expect["value"] = value
4884 expect["optional"] = True
4885 if default is not None and default == value:
4886 expect["presented"] = False
4887 seq[name] = klass(value)
4888 expects.append(expect)
4893 def sequences_strategy(draw, seq_klass):
4894 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4896 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4897 for tag, expled in zip(tags, draw(lists(
4904 i for i, is_default in enumerate(draw(lists(
4910 names = list(draw(sets(
4915 seq_expectses = draw(lists(
4916 sequence_strategy(seq_klass=seq_klass),
4920 seqs = [seq for seq, _ in seq_expectses]
4922 for i, (name, seq) in enumerate(zip(names, seqs)):
4925 seq(default=(seq if i in defaulted else None), **inits[i]),
4927 seq_name = draw(text_letters())
4928 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4931 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4934 "expects": expects_inner,
4937 seq_outer[name] = seq_inner
4938 if seq_outer.specs[name].default is None:
4939 expect["presented"] = True
4940 expect_outers.append(expect)
4941 return seq_outer, expect_outers
4944 class SeqMixing(object):
4945 def test_invalid_value_type(self):
4946 with self.assertRaises(InvalidValueType) as err:
4947 self.base_klass(123)
4950 def test_invalid_value_type_set(self):
4951 class Seq(self.base_klass):
4952 schema = (("whatever", Boolean()),)
4954 with self.assertRaises(InvalidValueType) as err:
4955 seq["whatever"] = Integer(123)
4959 def test_optional(self, optional):
4960 obj = self.base_klass(default=self.base_klass(), optional=optional)
4961 self.assertTrue(obj.optional)
4963 @given(data_strategy())
4964 def test_ready(self, d):
4966 str(i): v for i, v in enumerate(d.draw(lists(
4973 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4980 for name in d.draw(permutations(
4981 list(ready.keys()) + list(non_ready.keys()),
4983 schema_input.append((name, Boolean()))
4985 class Seq(self.base_klass):
4986 schema = tuple(schema_input)
4988 for name in ready.keys():
4990 seq[name] = Boolean()
4991 self.assertFalse(seq.ready)
4994 pprint(seq, big_blobs=True, with_decode_path=True)
4995 for name, value in ready.items():
4996 seq[name] = Boolean(value)
4997 self.assertFalse(seq.ready)
5000 pprint(seq, big_blobs=True, with_decode_path=True)
5001 with self.assertRaises(ObjNotReady) as err:
5004 for name, value in non_ready.items():
5005 seq[name] = Boolean(value)
5006 self.assertTrue(seq.ready)
5009 pprint(seq, big_blobs=True, with_decode_path=True)
5011 @given(data_strategy())
5012 def test_call(self, d):
5013 class SeqInherited(self.base_klass):
5015 for klass in (self.base_klass, SeqInherited):
5024 ) = d.draw(seq_values_strategy(seq_klass=klass))
5025 obj_initial = klass(
5031 optional_initial or False,
5042 ) = d.draw(seq_values_strategy(
5044 do_expl=impl_initial is None,
5046 obj = obj_initial(value, impl, expl, default, optional)
5047 value_expected = default if value is None else value
5049 default_initial if value_expected is None
5052 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5053 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5054 self.assertEqual(obj.expl_tag, expl or expl_initial)
5056 {} if obj.default is None else obj.default._value,
5057 getattr(default_initial if default is None else default, "_value", {}),
5059 if obj.default is None:
5060 optional = optional_initial if optional is None else optional
5061 optional = False if optional is None else optional
5064 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5065 self.assertEqual(obj.optional, optional)
5067 @given(data_strategy())
5068 def test_copy(self, d):
5069 class SeqInherited(self.base_klass):
5071 register_class(SeqInherited)
5072 for klass in (self.base_klass, SeqInherited):
5073 values = d.draw(seq_values_strategy(seq_klass=klass))
5074 obj = klass(*values)
5075 for copy_func in copy_funcs:
5076 obj_copied = copy_func(obj)
5077 self.assert_copied_basic_fields(obj, obj_copied)
5078 self.assertEqual(obj.specs, obj_copied.specs)
5079 self.assertEqual(obj._value, obj_copied._value)
5081 @given(data_strategy())
5082 def test_stripped(self, d):
5083 value = d.draw(integers())
5084 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5086 class Seq(self.base_klass):
5088 schema = (("whatever", Integer()),)
5090 seq["whatever"] = Integer(value)
5091 with self.assertRaises(NotEnoughData):
5092 seq.decode(seq.encode()[:-1])
5094 @given(data_strategy())
5095 def test_stripped_expl(self, d):
5096 value = d.draw(integers())
5097 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5099 class Seq(self.base_klass):
5101 schema = (("whatever", Integer()),)
5103 seq["whatever"] = Integer(value)
5104 with self.assertRaises(NotEnoughData):
5105 seq.decode(seq.encode()[:-1])
5107 @given(binary(min_size=2))
5108 def test_non_tag_mismatch_raised(self, junk):
5110 _, _, len_encoded = tag_strip(memoryview(junk))
5111 len_decode(len_encoded)
5117 class Seq(self.base_klass):
5119 ("whatever", Integer()),
5121 ("whenever", Integer()),
5124 seq["whatever"] = Integer(123)
5125 seq["junk"] = Any(junk)
5126 seq["whenever"] = Integer(123)
5127 with self.assertRaises(DecodeError):
5128 seq.decode(seq.encode())
5131 integers(min_value=31),
5132 integers(min_value=0),
5135 def test_bad_tag(self, tag, offset, decode_path):
5136 with self.assertRaises(DecodeError) as err:
5137 self.base_klass().decode(
5138 tag_encode(tag)[:-1],
5140 decode_path=decode_path,
5143 self.assertEqual(err.exception.offset, offset)
5144 self.assertEqual(err.exception.decode_path, decode_path)
5147 integers(min_value=128),
5148 integers(min_value=0),
5151 def test_bad_len(self, l, offset, decode_path):
5152 with self.assertRaises(DecodeError) as err:
5153 self.base_klass().decode(
5154 self.base_klass.tag_default + len_encode(l)[:-1],
5156 decode_path=decode_path,
5159 self.assertEqual(err.exception.offset, offset)
5160 self.assertEqual(err.exception.decode_path, decode_path)
5162 def _assert_expects(self, seq, expects):
5163 for expect in expects:
5165 seq.specs[expect["name"]].optional,
5168 if expect["default_value"] is not None:
5170 seq.specs[expect["name"]].default,
5171 expect["default_value"],
5173 if expect["presented"]:
5174 self.assertIn(expect["name"], seq)
5175 self.assertEqual(seq[expect["name"]], expect["value"])
5177 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5178 @given(data_strategy())
5179 def test_symmetric(self, d):
5180 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5181 tail_junk = d.draw(binary(max_size=5))
5182 self.assertTrue(seq.ready)
5183 self.assertFalse(seq.decoded)
5184 self._assert_expects(seq, expects)
5187 pprint(seq, big_blobs=True, with_decode_path=True)
5188 self.assertTrue(seq.ready)
5189 seq_encoded = seq.encode()
5190 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5191 self.assertFalse(seq_decoded.lenindef)
5192 self.assertFalse(seq_decoded.ber_encoded)
5193 self.assertFalse(seq_decoded.bered)
5195 t, _, lv = tag_strip(seq_encoded)
5196 _, _, v = len_decode(lv)
5197 seq_encoded_lenindef = t + LENINDEF + v + EOC
5198 ctx_copied = deepcopy(ctx_dummy)
5199 ctx_copied["bered"] = True
5200 seq_decoded_lenindef, tail_lenindef = seq.decode(
5201 seq_encoded_lenindef + tail_junk,
5204 del ctx_copied["bered"]
5205 self.assertDictEqual(ctx_copied, ctx_dummy)
5206 self.assertTrue(seq_decoded_lenindef.lenindef)
5207 self.assertTrue(seq_decoded_lenindef.bered)
5208 seq_decoded_lenindef = copy(seq_decoded_lenindef)
5209 self.assertTrue(seq_decoded_lenindef.lenindef)
5210 self.assertTrue(seq_decoded_lenindef.bered)
5211 with self.assertRaises(DecodeError):
5212 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5213 with self.assertRaises(DecodeError):
5214 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5215 repr(seq_decoded_lenindef)
5216 list(seq_decoded_lenindef.pps())
5217 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5218 self.assertTrue(seq_decoded_lenindef.ready)
5220 for decoded, decoded_tail, encoded in (
5221 (seq_decoded, tail, seq_encoded),
5222 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5224 self.assertEqual(decoded_tail, tail_junk)
5225 self._assert_expects(decoded, expects)
5226 self.assertEqual(seq, decoded)
5227 self.assertEqual(decoded.encode(), seq_encoded)
5228 self.assertEqual(decoded.tlvlen, len(encoded))
5229 for expect in expects:
5230 if not expect["presented"]:
5231 self.assertNotIn(expect["name"], decoded)
5233 self.assertIn(expect["name"], decoded)
5234 obj = decoded[expect["name"]]
5235 self.assertTrue(obj.decoded)
5236 offset = obj.expl_offset if obj.expled else obj.offset
5237 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5238 self.assertSequenceEqual(
5239 seq_encoded[offset:offset + tlvlen],
5243 assert_exceeding_data(
5245 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
5249 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5250 @given(data_strategy())
5251 def test_symmetric_with_seq(self, d):
5252 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5253 self.assertTrue(seq.ready)
5254 seq_encoded = seq.encode()
5255 seq_decoded, tail = seq.decode(seq_encoded)
5256 self.assertEqual(tail, b"")
5257 self.assertTrue(seq.ready)
5258 self.assertEqual(seq, seq_decoded)
5259 self.assertEqual(seq_decoded.encode(), seq_encoded)
5260 for expect_outer in expect_outers:
5261 if not expect_outer["presented"]:
5262 self.assertNotIn(expect_outer["name"], seq_decoded)
5264 self.assertIn(expect_outer["name"], seq_decoded)
5265 obj = seq_decoded[expect_outer["name"]]
5266 self.assertTrue(obj.decoded)
5267 offset = obj.expl_offset if obj.expled else obj.offset
5268 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5269 self.assertSequenceEqual(
5270 seq_encoded[offset:offset + tlvlen],
5273 self._assert_expects(obj, expect_outer["expects"])
5275 @given(data_strategy())
5276 def test_default_disappears(self, d):
5277 _schema = list(d.draw(dictionaries(
5279 sets(integers(), min_size=2, max_size=2),
5283 class Seq(self.base_klass):
5285 (n, Integer(default=d))
5286 for n, (_, d) in _schema
5289 for name, (value, _) in _schema:
5290 seq[name] = Integer(value)
5291 self.assertEqual(len(seq._value), len(_schema))
5292 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5293 self.assertGreater(len(seq.encode()), len(empty_seq))
5294 for name, (_, default) in _schema:
5295 seq[name] = Integer(default)
5296 self.assertEqual(len(seq._value), 0)
5297 self.assertSequenceEqual(seq.encode(), empty_seq)
5299 @given(data_strategy())
5300 def test_encoded_default_not_accepted(self, d):
5301 _schema = list(d.draw(dictionaries(
5306 tags = [tag_encode(tag) for tag in d.draw(sets(
5307 integers(min_value=0),
5308 min_size=len(_schema),
5309 max_size=len(_schema),
5312 class SeqWithoutDefault(self.base_klass):
5314 (n, Integer(impl=t))
5315 for (n, _), t in zip(_schema, tags)
5317 seq_without_default = SeqWithoutDefault()
5318 for name, value in _schema:
5319 seq_without_default[name] = Integer(value)
5320 seq_encoded = seq_without_default.encode()
5322 class SeqWithDefault(self.base_klass):
5324 (n, Integer(default=v, impl=t))
5325 for (n, v), t in zip(_schema, tags)
5327 seq_with_default = SeqWithDefault()
5328 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5329 seq_with_default.decode(seq_encoded)
5330 for ctx in ({"bered": True}, {"allow_default_values": True}):
5331 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5332 self.assertTrue(seq_decoded.ber_encoded)
5333 self.assertTrue(seq_decoded.bered)
5334 seq_decoded = copy(seq_decoded)
5335 self.assertTrue(seq_decoded.ber_encoded)
5336 self.assertTrue(seq_decoded.bered)
5337 for name, value in _schema:
5338 self.assertEqual(seq_decoded[name], seq_with_default[name])
5339 self.assertEqual(seq_decoded[name], value)
5341 @given(data_strategy())
5342 def test_missing_from_spec(self, d):
5343 names = list(d.draw(sets(text_letters(), min_size=2)))
5344 tags = [tag_encode(tag) for tag in d.draw(sets(
5345 integers(min_value=0),
5346 min_size=len(names),
5347 max_size=len(names),
5349 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5351 class SeqFull(self.base_klass):
5352 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5353 seq_full = SeqFull()
5354 for i, name in enumerate(names):
5355 seq_full[name] = Integer(i)
5356 seq_encoded = seq_full.encode()
5357 altered = names_tags[:-2] + names_tags[-1:]
5359 class SeqMissing(self.base_klass):
5360 schema = [(n, Integer(impl=t)) for n, t in altered]
5361 seq_missing = SeqMissing()
5362 with self.assertRaises(TagMismatch):
5363 seq_missing.decode(seq_encoded)
5365 def test_bered(self):
5366 class Seq(self.base_klass):
5367 schema = (("underlying", Boolean()),)
5368 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5369 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5370 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5371 self.assertFalse(decoded.ber_encoded)
5372 self.assertFalse(decoded.lenindef)
5373 self.assertTrue(decoded.bered)
5374 decoded = copy(decoded)
5375 self.assertFalse(decoded.ber_encoded)
5376 self.assertFalse(decoded.lenindef)
5377 self.assertTrue(decoded.bered)
5379 class Seq(self.base_klass):
5380 schema = (("underlying", OctetString()),)
5382 tag_encode(form=TagFormConstructed, num=4) +
5384 OctetString(b"whatever").encode() +
5387 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5388 with self.assertRaises(DecodeError):
5389 Seq().decode(encoded)
5390 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5391 self.assertFalse(decoded.ber_encoded)
5392 self.assertFalse(decoded.lenindef)
5393 self.assertTrue(decoded.bered)
5394 decoded = copy(decoded)
5395 self.assertFalse(decoded.ber_encoded)
5396 self.assertFalse(decoded.lenindef)
5397 self.assertTrue(decoded.bered)
5400 class TestSequence(SeqMixing, CommonMixin, TestCase):
5401 base_klass = Sequence
5407 def test_remaining(self, value, junk):
5408 class Seq(Sequence):
5410 ("whatever", Integer()),
5412 int_encoded = Integer(value).encode()
5414 Sequence.tag_default,
5415 len_encode(len(int_encoded + junk)),
5418 with assertRaisesRegex(self, DecodeError, "remaining"):
5419 Seq().decode(junked)
5421 @given(sets(text_letters(), min_size=2))
5422 def test_obj_unknown(self, names):
5423 missing = names.pop()
5425 class Seq(Sequence):
5426 schema = [(n, Boolean()) for n in names]
5428 with self.assertRaises(ObjUnknown) as err:
5431 with self.assertRaises(ObjUnknown) as err:
5432 seq[missing] = Boolean()
5435 def test_x690_vector(self):
5436 class Seq(Sequence):
5438 ("name", IA5String()),
5441 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5442 self.assertEqual(seq["name"], "Smith")
5443 self.assertEqual(seq["ok"], True)
5446 class TestSet(SeqMixing, CommonMixin, TestCase):
5449 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5450 @given(data_strategy())
5451 def test_sorted(self, d):
5453 tag_encode(tag) for tag in
5454 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5458 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5460 for name, _ in Seq.schema:
5461 seq[name] = OctetString(b"")
5462 seq_encoded = seq.encode()
5463 seq_decoded, _ = seq.decode(seq_encoded)
5464 self.assertSequenceEqual(
5465 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5466 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5469 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5470 @given(data_strategy())
5471 def test_unsorted(self, d):
5473 tag_encode(tag) for tag in
5474 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5476 tags = d.draw(permutations(tags))
5477 assume(tags != sorted(tags))
5478 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5479 seq_encoded = b"".join((
5481 len_encode(len(encoded)),
5486 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5488 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5489 seq.decode(seq_encoded)
5490 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5491 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5492 self.assertTrue(seq_decoded.ber_encoded)
5493 self.assertTrue(seq_decoded.bered)
5494 seq_decoded = copy(seq_decoded)
5495 self.assertTrue(seq_decoded.ber_encoded)
5496 self.assertTrue(seq_decoded.bered)
5497 self.assertSequenceEqual(
5498 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5504 def seqof_values_strategy(draw, schema=None, do_expl=False):
5506 schema = draw(sampled_from((Boolean(), Integer())))
5507 bound_min, bound_max = sorted(draw(sets(
5508 integers(min_value=0, max_value=10),
5512 if isinstance(schema, Boolean):
5513 values_generator = booleans().map(Boolean)
5514 elif isinstance(schema, Integer):
5515 values_generator = integers().map(Integer)
5516 values_generator = lists(
5521 values = draw(one_of(none(), values_generator))
5525 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5527 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5528 default = draw(one_of(none(), values_generator))
5529 optional = draw(one_of(none(), booleans()))
5531 draw(integers(min_value=0)),
5532 draw(integers(min_value=0)),
5533 draw(integers(min_value=0)),
5538 (bound_min, bound_max),
5547 class SeqOfMixing(object):
5548 def test_invalid_value_type(self):
5549 with self.assertRaises(InvalidValueType) as err:
5550 self.base_klass(123)
5553 def test_invalid_values_type(self):
5554 class SeqOf(self.base_klass):
5556 with self.assertRaises(InvalidValueType) as err:
5557 SeqOf([Integer(123), Boolean(False), Integer(234)])
5560 def test_schema_required(self):
5561 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5562 self.base_klass.__mro__[1]()
5564 @given(booleans(), booleans(), binary(), binary())
5565 def test_comparison(self, value1, value2, tag1, tag2):
5566 class SeqOf(self.base_klass):
5568 obj1 = SeqOf([Boolean(value1)])
5569 obj2 = SeqOf([Boolean(value2)])
5570 self.assertEqual(obj1 == obj2, value1 == value2)
5571 self.assertEqual(obj1 != obj2, value1 != value2)
5572 self.assertEqual(obj1 == list(obj2), value1 == value2)
5573 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5574 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5575 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5576 self.assertEqual(obj1 == obj2, tag1 == tag2)
5577 self.assertEqual(obj1 != obj2, tag1 != tag2)
5579 @given(lists(booleans()))
5580 def test_iter(self, values):
5581 class SeqOf(self.base_klass):
5583 obj = SeqOf([Boolean(value) for value in values])
5584 self.assertEqual(len(obj), len(values))
5585 for i, value in enumerate(obj):
5586 self.assertEqual(value, values[i])
5588 @given(data_strategy())
5589 def test_ready(self, d):
5590 ready = [Integer(v) for v in d.draw(lists(
5597 range(d.draw(integers(min_value=1, max_value=5)))
5600 class SeqOf(self.base_klass):
5602 values = d.draw(permutations(ready + non_ready))
5604 for value in values:
5606 self.assertFalse(seqof.ready)
5609 pprint(seqof, big_blobs=True, with_decode_path=True)
5610 with self.assertRaises(ObjNotReady) as err:
5613 for i, value in enumerate(values):
5614 self.assertEqual(seqof[i], value)
5615 if not seqof[i].ready:
5616 seqof[i] = Integer(i)
5617 self.assertTrue(seqof.ready)
5620 pprint(seqof, big_blobs=True, with_decode_path=True)
5622 def test_spec_mismatch(self):
5623 class SeqOf(self.base_klass):
5626 seqof.append(Integer(123))
5627 with self.assertRaises(ValueError):
5628 seqof.append(Boolean(False))
5629 with self.assertRaises(ValueError):
5630 seqof[0] = Boolean(False)
5632 @given(data_strategy())
5633 def test_bounds_satisfied(self, d):
5634 class SeqOf(self.base_klass):
5636 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5637 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5638 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5639 SeqOf(value=value, bounds=(bound_min, bound_max))
5641 @given(data_strategy())
5642 def test_bounds_unsatisfied(self, d):
5643 class SeqOf(self.base_klass):
5645 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5646 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5647 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5648 with self.assertRaises(BoundsError) as err:
5649 SeqOf(value=value, bounds=(bound_min, bound_max))
5651 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5652 SeqOf(bounds=(bound_min, bound_max)).decode(
5653 SeqOf(value).encode()
5656 value = [Boolean(True)] * d.draw(integers(
5657 min_value=bound_max + 1,
5658 max_value=bound_max + 10,
5660 with self.assertRaises(BoundsError) as err:
5661 SeqOf(value=value, bounds=(bound_min, bound_max))
5663 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5664 SeqOf(bounds=(bound_min, bound_max)).decode(
5665 SeqOf(value).encode()
5669 @given(integers(min_value=1, max_value=10))
5670 def test_out_of_bounds(self, bound_max):
5671 class SeqOf(self.base_klass):
5673 bounds = (0, bound_max)
5675 for _ in range(bound_max):
5676 seqof.append(Integer(123))
5677 with self.assertRaises(BoundsError):
5678 seqof.append(Integer(123))
5680 @given(data_strategy())
5681 def test_call(self, d):
5691 ) = d.draw(seqof_values_strategy())
5693 class SeqOf(self.base_klass):
5694 schema = schema_initial
5695 obj_initial = SeqOf(
5696 value=value_initial,
5697 bounds=bounds_initial,
5700 default=default_initial,
5701 optional=optional_initial or False,
5702 _decoded=_decoded_initial,
5713 ) = d.draw(seqof_values_strategy(
5714 schema=schema_initial,
5715 do_expl=impl_initial is None,
5717 if (default is None) and (obj_initial.default is not None):
5720 (bounds is None) and
5721 (value is not None) and
5722 (bounds_initial is not None) and
5723 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5727 (bounds is None) and
5728 (default is not None) and
5729 (bounds_initial is not None) and
5730 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5742 value_expected = default if value is None else value
5744 default_initial if value_expected is None
5747 value_expected = () if value_expected is None else value_expected
5748 self.assertEqual(obj, value_expected)
5749 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5750 self.assertEqual(obj.expl_tag, expl or expl_initial)
5753 default_initial if default is None else default,
5755 if obj.default is None:
5756 optional = optional_initial if optional is None else optional
5757 optional = False if optional is None else optional
5760 self.assertEqual(obj.optional, optional)
5762 (obj._bound_min, obj._bound_max),
5763 bounds or bounds_initial or (0, float("+inf")),
5766 @given(seqof_values_strategy())
5767 def test_copy(self, values):
5768 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5770 class SeqOf(self.base_klass):
5772 register_class(SeqOf)
5779 optional=optional or False,
5782 for copy_func in copy_funcs:
5783 obj_copied = copy_func(obj)
5784 self.assert_copied_basic_fields(obj, obj_copied)
5785 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5786 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5787 self.assertEqual(obj._value, obj_copied._value)
5791 integers(min_value=1).map(tag_encode),
5793 def test_stripped(self, values, tag_impl):
5794 class SeqOf(self.base_klass):
5795 schema = OctetString()
5796 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5797 with self.assertRaises(NotEnoughData):
5798 obj.decode(obj.encode()[:-1])
5802 integers(min_value=1).map(tag_ctxc),
5804 def test_stripped_expl(self, values, tag_expl):
5805 class SeqOf(self.base_klass):
5806 schema = OctetString()
5807 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5808 with self.assertRaises(NotEnoughData):
5809 obj.decode(obj.encode()[:-1])
5812 integers(min_value=31),
5813 integers(min_value=0),
5816 def test_bad_tag(self, tag, offset, decode_path):
5817 with self.assertRaises(DecodeError) as err:
5818 self.base_klass().decode(
5819 tag_encode(tag)[:-1],
5821 decode_path=decode_path,
5824 self.assertEqual(err.exception.offset, offset)
5825 self.assertEqual(err.exception.decode_path, decode_path)
5828 integers(min_value=128),
5829 integers(min_value=0),
5832 def test_bad_len(self, l, offset, decode_path):
5833 with self.assertRaises(DecodeError) as err:
5834 self.base_klass().decode(
5835 self.base_klass.tag_default + len_encode(l)[:-1],
5837 decode_path=decode_path,
5840 self.assertEqual(err.exception.offset, offset)
5841 self.assertEqual(err.exception.decode_path, decode_path)
5843 @given(binary(min_size=1))
5844 def test_tag_mismatch(self, impl):
5845 assume(impl != self.base_klass.tag_default)
5846 with self.assertRaises(TagMismatch):
5847 self.base_klass(impl=impl).decode(self.base_klass().encode())
5849 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5851 seqof_values_strategy(schema=Integer()),
5852 lists(integers().map(Integer)),
5853 integers(min_value=1).map(tag_ctxc),
5854 integers(min_value=0),
5857 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5858 _, _, _, _, _, default, optional, _decoded = values
5860 class SeqOf(self.base_klass):
5870 pprint(obj, big_blobs=True, with_decode_path=True)
5871 self.assertFalse(obj.expled)
5872 obj_encoded = obj.encode()
5873 obj_expled = obj(value, expl=tag_expl)
5874 self.assertTrue(obj_expled.expled)
5876 list(obj_expled.pps())
5877 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5878 obj_expled_encoded = obj_expled.encode()
5879 ctx_copied = deepcopy(ctx_dummy)
5880 obj_decoded, tail = obj_expled.decode(
5881 obj_expled_encoded + tail_junk,
5885 self.assertDictEqual(ctx_copied, ctx_dummy)
5887 list(obj_decoded.pps())
5888 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5889 self.assertEqual(tail, tail_junk)
5890 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5891 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5892 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5893 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5895 obj_decoded.expl_llen,
5896 len(len_encode(len(obj_encoded))),
5898 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5899 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5902 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5904 self.assertEqual(obj_decoded.expl_offset, offset)
5905 for obj_inner in obj_decoded:
5906 self.assertIn(obj_inner, obj_decoded)
5907 self.assertSequenceEqual(
5910 obj_inner.offset - offset:
5911 obj_inner.offset + obj_inner.tlvlen - offset
5915 t, _, lv = tag_strip(obj_encoded)
5916 _, _, v = len_decode(lv)
5917 obj_encoded_lenindef = t + LENINDEF + v + EOC
5918 obj_decoded_lenindef, tail_lenindef = obj.decode(
5919 obj_encoded_lenindef + tail_junk,
5920 ctx={"bered": True},
5922 self.assertTrue(obj_decoded_lenindef.lenindef)
5923 self.assertTrue(obj_decoded_lenindef.bered)
5924 obj_decoded_lenindef = copy(obj_decoded_lenindef)
5925 self.assertTrue(obj_decoded_lenindef.lenindef)
5926 self.assertTrue(obj_decoded_lenindef.bered)
5927 repr(obj_decoded_lenindef)
5928 list(obj_decoded_lenindef.pps())
5929 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5930 self.assertEqual(tail_lenindef, tail_junk)
5931 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5932 with self.assertRaises(DecodeError):
5933 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5934 with self.assertRaises(DecodeError):
5935 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5937 assert_exceeding_data(
5939 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5943 def test_bered(self):
5944 class SeqOf(self.base_klass):
5946 encoded = Boolean(False).encode()
5947 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5948 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5949 with self.assertRaises(DecodeError):
5950 SeqOf().decode(encoded)
5951 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5952 self.assertFalse(decoded.ber_encoded)
5953 self.assertFalse(decoded.lenindef)
5954 self.assertTrue(decoded.bered)
5955 decoded = copy(decoded)
5956 self.assertFalse(decoded.ber_encoded)
5957 self.assertFalse(decoded.lenindef)
5958 self.assertTrue(decoded.bered)
5960 class SeqOf(self.base_klass):
5961 schema = OctetString()
5962 encoded = OctetString(b"whatever").encode()
5964 tag_encode(form=TagFormConstructed, num=4) +
5966 OctetString(b"whatever").encode() +
5969 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5970 with self.assertRaises(DecodeError):
5971 SeqOf().decode(encoded)
5972 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5973 self.assertFalse(decoded.ber_encoded)
5974 self.assertFalse(decoded.lenindef)
5975 self.assertTrue(decoded.bered)
5976 decoded = copy(decoded)
5977 self.assertFalse(decoded.ber_encoded)
5978 self.assertFalse(decoded.lenindef)
5979 self.assertTrue(decoded.bered)
5982 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5983 class SeqOf(SequenceOf):
5987 def _test_symmetric_compare_objs(self, obj1, obj2):
5988 self.assertEqual(obj1, obj2)
5989 self.assertSequenceEqual(list(obj1), list(obj2))
5992 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5997 def _test_symmetric_compare_objs(self, obj1, obj2):
5998 self.assertSetEqual(
5999 set(int(v) for v in obj1),
6000 set(int(v) for v in obj2),
6003 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6004 @given(data_strategy())
6005 def test_sorted(self, d):
6006 values = [OctetString(v) for v in d.draw(lists(binary()))]
6009 schema = OctetString()
6011 seq_encoded = seq.encode()
6012 seq_decoded, _ = seq.decode(seq_encoded)
6013 self.assertSequenceEqual(
6014 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6015 b"".join(sorted([v.encode() for v in values])),
6018 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6019 @given(data_strategy())
6020 def test_unsorted(self, d):
6021 values = [OctetString(v).encode() for v in d.draw(sets(
6022 binary(min_size=1, max_size=5),
6026 values = d.draw(permutations(values))
6027 assume(values != sorted(values))
6028 encoded = b"".join(values)
6029 seq_encoded = b"".join((
6031 len_encode(len(encoded)),
6036 schema = OctetString()
6038 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6039 seq.decode(seq_encoded)
6041 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6042 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6043 self.assertTrue(seq_decoded.ber_encoded)
6044 self.assertTrue(seq_decoded.bered)
6045 seq_decoded = copy(seq_decoded)
6046 self.assertTrue(seq_decoded.ber_encoded)
6047 self.assertTrue(seq_decoded.bered)
6048 self.assertSequenceEqual(
6049 [obj.encode() for obj in seq_decoded],
6054 class TestGoMarshalVectors(TestCase):
6056 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6057 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6058 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6059 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6060 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6062 class Seq(Sequence):
6064 ("erste", Integer()),
6065 ("zweite", Integer(optional=True))
6068 seq["erste"] = Integer(64)
6069 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6070 seq["erste"] = Integer(0x123456)
6071 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6072 seq["erste"] = Integer(64)
6073 seq["zweite"] = Integer(65)
6074 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6076 class NestedSeq(Sequence):
6080 seq["erste"] = Integer(127)
6081 seq["zweite"] = None
6082 nested = NestedSeq()
6083 nested["nest"] = seq
6084 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6086 self.assertSequenceEqual(
6087 OctetString(b"\x01\x02\x03").encode(),
6088 hexdec("0403010203"),
6091 class Seq(Sequence):
6093 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6096 seq["erste"] = Integer(64)
6097 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6099 class Seq(Sequence):
6101 ("erste", Integer(expl=tag_ctxc(5))),
6104 seq["erste"] = Integer(64)
6105 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6107 class Seq(Sequence):
6110 impl=tag_encode(0, klass=TagClassContext),
6115 seq["erste"] = Null()
6116 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6118 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6120 self.assertSequenceEqual(
6121 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6122 hexdec("170d3730303130313030303030305a"),
6124 self.assertSequenceEqual(
6125 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6126 hexdec("170d3039313131353232353631365a"),
6128 self.assertSequenceEqual(
6129 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6130 hexdec("180f32313030303430353132303130315a"),
6133 class Seq(Sequence):
6135 ("erste", GeneralizedTime()),
6138 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6139 self.assertSequenceEqual(
6141 hexdec("3011180f32303039313131353232353631365a"),
6144 self.assertSequenceEqual(
6145 BitString((1, b"\x80")).encode(),
6148 self.assertSequenceEqual(
6149 BitString((12, b"\x81\xF0")).encode(),
6150 hexdec("03030481f0"),
6153 self.assertSequenceEqual(
6154 ObjectIdentifier("1.2.3.4").encode(),
6155 hexdec("06032a0304"),
6157 self.assertSequenceEqual(
6158 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6159 hexdec("06092a864888932d010105"),
6161 self.assertSequenceEqual(
6162 ObjectIdentifier("2.100.3").encode(),
6163 hexdec("0603813403"),
6166 self.assertSequenceEqual(
6167 PrintableString("test").encode(),
6168 hexdec("130474657374"),
6170 self.assertSequenceEqual(
6171 PrintableString("x" * 127).encode(),
6172 hexdec("137F" + "78" * 127),
6174 self.assertSequenceEqual(
6175 PrintableString("x" * 128).encode(),
6176 hexdec("138180" + "78" * 128),
6178 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6180 class Seq(Sequence):
6182 ("erste", IA5String()),
6185 seq["erste"] = IA5String("test")
6186 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6188 class Seq(Sequence):
6190 ("erste", PrintableString()),
6193 seq["erste"] = PrintableString("test")
6194 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6195 # Asterisk is actually not allowable
6196 PrintableString._allowable_chars |= set(b"*")
6197 seq["erste"] = PrintableString("test*")
6198 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6199 PrintableString._allowable_chars -= set(b"*")
6201 class Seq(Sequence):
6203 ("erste", Any(optional=True)),
6204 ("zweite", Integer()),
6207 seq["zweite"] = Integer(64)
6208 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6213 seq.append(Integer(10))
6214 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6216 class _SeqOf(SequenceOf):
6217 schema = PrintableString()
6219 class SeqOf(SequenceOf):
6222 _seqof.append(PrintableString("1"))
6224 seqof.append(_seqof)
6225 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6227 class Seq(Sequence):
6229 ("erste", Integer(default=1)),
6232 seq["erste"] = Integer(0)
6233 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6234 seq["erste"] = Integer(1)
6235 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6236 seq["erste"] = Integer(2)
6237 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6240 class TestPP(TestCase):
6241 @given(data_strategy())
6242 def test_oid_printing(self, d):
6244 str(ObjectIdentifier(k)): v * 2
6245 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6247 chosen = d.draw(sampled_from(sorted(oids)))
6248 chosen_id = oids[chosen]
6249 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6250 self.assertNotIn(chosen_id, pp_console_row(pp))
6253 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6257 class TestAutoAddSlots(TestCase):
6259 class Inher(Integer):
6262 with self.assertRaises(AttributeError):
6264 inher.unexistent = "whatever"
6267 class TestOIDDefines(TestCase):
6268 @given(data_strategy())
6269 def runTest(self, d):
6270 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6271 value_name_chosen = d.draw(sampled_from(value_names))
6273 ObjectIdentifier(oid)
6274 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6276 oid_chosen = d.draw(sampled_from(oids))
6277 values = d.draw(lists(
6279 min_size=len(value_names),
6280 max_size=len(value_names),
6283 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6284 oid: Integer() for oid in oids[:-1]
6287 for i, value_name in enumerate(value_names):
6288 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6290 class Seq(Sequence):
6293 for value_name, value in zip(value_names, values):
6294 seq[value_name] = Any(Integer(value).encode())
6295 seq["type"] = oid_chosen
6296 seq, _ = Seq().decode(seq.encode())
6297 for value_name in value_names:
6298 if value_name == value_name_chosen:
6300 self.assertIsNone(seq[value_name].defined)
6301 if value_name_chosen in oids[:-1]:
6302 self.assertIsNotNone(seq[value_name_chosen].defined)
6303 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6304 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6307 pprint(seq, big_blobs=True, with_decode_path=True)
6310 class TestDefinesByPath(TestCase):
6311 def test_generated(self):
6312 class Seq(Sequence):
6314 ("type", ObjectIdentifier()),
6315 ("value", OctetString(expl=tag_ctxc(123))),
6318 class SeqInner(Sequence):
6320 ("typeInner", ObjectIdentifier()),
6321 ("valueInner", Any()),
6324 class PairValue(SetOf):
6327 class Pair(Sequence):
6329 ("type", ObjectIdentifier()),
6330 ("value", PairValue()),
6333 class Pairs(SequenceOf):
6340 type_octet_stringed,
6342 ObjectIdentifier(oid)
6343 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6345 seq_integered = Seq()
6346 seq_integered["type"] = type_integered
6347 seq_integered["value"] = OctetString(Integer(123).encode())
6348 seq_integered_raw = seq_integered.encode()
6352 (type_octet_stringed, OctetString(b"whatever")),
6353 (type_integered, Integer(123)),
6354 (type_octet_stringed, OctetString(b"whenever")),
6355 (type_integered, Integer(234)),
6357 for t, v in pairs_input:
6360 pair["value"] = PairValue((Any(v),))
6362 seq_inner = SeqInner()
6363 seq_inner["typeInner"] = type_innered
6364 seq_inner["valueInner"] = Any(pairs)
6365 seq_sequenced = Seq()
6366 seq_sequenced["type"] = type_sequenced
6367 seq_sequenced["value"] = OctetString(seq_inner.encode())
6368 seq_sequenced_raw = seq_sequenced.encode()
6370 list(seq_sequenced.pps())
6371 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6373 defines_by_path = []
6374 ctx_copied = deepcopy(ctx_dummy)
6375 seq_integered, _ = Seq().decode(
6379 self.assertDictEqual(ctx_copied, ctx_dummy)
6380 self.assertIsNone(seq_integered["value"].defined)
6381 defines_by_path.append(
6382 (("type",), ((("value",), {
6383 type_integered: Integer(),
6384 type_sequenced: SeqInner(),
6387 ctx_copied["defines_by_path"] = defines_by_path
6388 seq_integered, _ = Seq().decode(
6392 del ctx_copied["defines_by_path"]
6393 self.assertDictEqual(ctx_copied, ctx_dummy)
6394 self.assertIsNotNone(seq_integered["value"].defined)
6395 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6396 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6397 self.assertTrue(seq_integered_raw[
6398 seq_integered["value"].defined[1].offset:
6399 ].startswith(Integer(123).encode()))
6401 list(seq_integered.pps())
6402 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6404 ctx_copied["defines_by_path"] = defines_by_path
6405 seq_sequenced, _ = Seq().decode(
6409 del ctx_copied["defines_by_path"]
6410 self.assertDictEqual(ctx_copied, ctx_dummy)
6411 self.assertIsNotNone(seq_sequenced["value"].defined)
6412 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6413 seq_inner = seq_sequenced["value"].defined[1]
6414 self.assertIsNone(seq_inner["valueInner"].defined)
6416 list(seq_sequenced.pps())
6417 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6419 defines_by_path.append((
6420 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6421 ((("valueInner",), {type_innered: Pairs()}),),
6423 ctx_copied["defines_by_path"] = defines_by_path
6424 seq_sequenced, _ = Seq().decode(
6428 del ctx_copied["defines_by_path"]
6429 self.assertDictEqual(ctx_copied, ctx_dummy)
6430 self.assertIsNotNone(seq_sequenced["value"].defined)
6431 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6432 seq_inner = seq_sequenced["value"].defined[1]
6433 self.assertIsNotNone(seq_inner["valueInner"].defined)
6434 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6435 pairs = seq_inner["valueInner"].defined[1]
6437 self.assertIsNone(pair["value"][0].defined)
6439 list(seq_sequenced.pps())
6440 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6442 defines_by_path.append((
6445 DecodePathDefBy(type_sequenced),
6447 DecodePathDefBy(type_innered),
6452 type_integered: Integer(),
6453 type_octet_stringed: OctetString(),
6456 ctx_copied["defines_by_path"] = defines_by_path
6457 seq_sequenced, _ = Seq().decode(
6461 del ctx_copied["defines_by_path"]
6462 self.assertDictEqual(ctx_copied, ctx_dummy)
6463 self.assertIsNotNone(seq_sequenced["value"].defined)
6464 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6465 seq_inner = seq_sequenced["value"].defined[1]
6466 self.assertIsNotNone(seq_inner["valueInner"].defined)
6467 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6468 pairs_got = seq_inner["valueInner"].defined[1]
6469 for pair_input, pair_got in zip(pairs_input, pairs_got):
6470 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6471 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6473 list(seq_sequenced.pps())
6474 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6476 @given(oid_strategy(), integers())
6477 def test_simple(self, oid, tgt):
6478 class Inner(Sequence):
6480 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6481 ObjectIdentifier(oid): Integer(),
6485 class Outer(Sequence):
6488 ("tgt", OctetString()),
6492 inner["oid"] = ObjectIdentifier(oid)
6494 outer["inner"] = inner
6495 outer["tgt"] = OctetString(Integer(tgt).encode())
6496 decoded, _ = Outer().decode(outer.encode())
6497 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6500 class TestAbsDecodePath(TestCase):
6502 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6503 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6505 def test_concat(self, decode_path, rel_path):
6506 self.assertSequenceEqual(
6507 abs_decode_path(decode_path, rel_path),
6508 decode_path + rel_path,
6512 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6513 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6515 def test_abs(self, decode_path, rel_path):
6516 self.assertSequenceEqual(
6517 abs_decode_path(decode_path, ("/",) + rel_path),
6522 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6523 integers(min_value=1, max_value=3),
6524 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6526 def test_dots(self, decode_path, number_of_dots, rel_path):
6527 self.assertSequenceEqual(
6528 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6529 decode_path[:-number_of_dots] + rel_path,
6533 class TestStrictDefaultExistence(TestCase):
6534 @given(data_strategy())
6535 def runTest(self, d):
6536 count = d.draw(integers(min_value=1, max_value=10))
6537 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6539 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6540 for i in range(count)
6542 for klass in (Sequence, Set):
6546 for i in range(count):
6547 seq["int%d" % i] = Integer(123)
6549 chosen_choice = "int%d" % chosen
6550 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6551 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6553 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6554 self.assertTrue(decoded.ber_encoded)
6555 self.assertTrue(decoded.bered)
6556 decoded = copy(decoded)
6557 self.assertTrue(decoded.ber_encoded)
6558 self.assertTrue(decoded.bered)
6559 decoded, _ = seq.decode(raw, ctx={"bered": True})
6560 self.assertTrue(decoded.ber_encoded)
6561 self.assertTrue(decoded.bered)
6562 decoded = copy(decoded)
6563 self.assertTrue(decoded.ber_encoded)
6564 self.assertTrue(decoded.bered)
6567 class TestX690PrefixedType(TestCase):
6569 self.assertSequenceEqual(
6570 VisibleString("Jones").encode(),
6571 hexdec("1A054A6F6E6573"),
6573 self.assertSequenceEqual(
6576 impl=tag_encode(3, klass=TagClassApplication),
6578 hexdec("43054A6F6E6573"),
6580 self.assertSequenceEqual(
6584 impl=tag_encode(3, klass=TagClassApplication),
6588 hexdec("A20743054A6F6E6573"),
6590 self.assertSequenceEqual(
6594 impl=tag_encode(3, klass=TagClassApplication),
6596 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6598 hexdec("670743054A6F6E6573"),
6600 self.assertSequenceEqual(
6601 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6602 hexdec("82054A6F6E6573"),
6606 class TestExplOOB(TestCase):
6608 expl = tag_ctxc(123)
6609 raw = Integer(123).encode() + Integer(234).encode()
6610 raw = b"".join((expl, len_encode(len(raw)), raw))
6611 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6612 Integer(expl=expl).decode(raw)
6613 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
6616 class TestPickleDifferentVersion(TestCase):
6618 pickled = pickle_dumps(Integer(123), pickle_proto)
6620 version_orig = pyderasn.__version__
6621 pyderasn.__version__ += "different"
6622 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
6623 pickle_loads(pickled)
6624 pyderasn.__version__ = version_orig
6625 pickle_loads(pickled)