2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2018 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, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from datetime import datetime
20 from string import ascii_letters
21 from string import digits
22 from string import printable
23 from string import whitespace
24 from unittest import TestCase
26 from hypothesis import assume
27 from hypothesis import given
28 from hypothesis import settings
29 from hypothesis.strategies import binary
30 from hypothesis.strategies import booleans
31 from hypothesis.strategies import composite
32 from hypothesis.strategies import data as data_strategy
33 from hypothesis.strategies import datetimes
34 from hypothesis.strategies import dictionaries
35 from hypothesis.strategies import integers
36 from hypothesis.strategies import just
37 from hypothesis.strategies import lists
38 from hypothesis.strategies import none
39 from hypothesis.strategies import one_of
40 from hypothesis.strategies import permutations
41 from hypothesis.strategies import sampled_from
42 from hypothesis.strategies import sets
43 from hypothesis.strategies import text
44 from hypothesis.strategies import tuples
45 from six import assertRaisesRegex
46 from six import binary_type
47 from six import byte2int
48 from six import indexbytes
49 from six import int2byte
50 from six import iterbytes
52 from six import text_type
53 from six import unichr as six_unichr
55 from pyderasn import _pp
56 from pyderasn import abs_decode_path
57 from pyderasn import Any
58 from pyderasn import BitString
59 from pyderasn import BMPString
60 from pyderasn import Boolean
61 from pyderasn import BoundsError
62 from pyderasn import Choice
63 from pyderasn import DecodeError
64 from pyderasn import DecodePathDefBy
65 from pyderasn import Enumerated
66 from pyderasn import EOC
67 from pyderasn import EOC_LEN
68 from pyderasn import GeneralizedTime
69 from pyderasn import GeneralString
70 from pyderasn import GraphicString
71 from pyderasn import hexdec
72 from pyderasn import hexenc
73 from pyderasn import IA5String
74 from pyderasn import Integer
75 from pyderasn import InvalidLength
76 from pyderasn import InvalidOID
77 from pyderasn import InvalidValueType
78 from pyderasn import len_decode
79 from pyderasn import len_encode
80 from pyderasn import LEN_YYMMDDHHMMSSZ
81 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
82 from pyderasn import LEN_YYYYMMDDHHMMSSZ
83 from pyderasn import LENINDEF
84 from pyderasn import NotEnoughData
85 from pyderasn import Null
86 from pyderasn import NumericString
87 from pyderasn import ObjectIdentifier
88 from pyderasn import ObjNotReady
89 from pyderasn import ObjUnknown
90 from pyderasn import OctetString
91 from pyderasn import pp_console_row
92 from pyderasn import pprint
93 from pyderasn import PrintableString
94 from pyderasn import Sequence
95 from pyderasn import SequenceOf
96 from pyderasn import Set
97 from pyderasn import SetOf
98 from pyderasn import tag_ctxc
99 from pyderasn import tag_ctxp
100 from pyderasn import tag_decode
101 from pyderasn import tag_encode
102 from pyderasn import tag_strip
103 from pyderasn import TagClassApplication
104 from pyderasn import TagClassContext
105 from pyderasn import TagClassPrivate
106 from pyderasn import TagClassUniversal
107 from pyderasn import TagFormConstructed
108 from pyderasn import TagFormPrimitive
109 from pyderasn import TagMismatch
110 from pyderasn import TeletexString
111 from pyderasn import UniversalString
112 from pyderasn import UTCTime
113 from pyderasn import UTF8String
114 from pyderasn import VideotexString
115 from pyderasn import VisibleString
118 settings.register_profile("local", settings(
121 settings.load_profile("local")
122 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
124 tag_classes = sampled_from((
130 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
131 decode_path_strat = lists(integers(), max_size=3).map(
132 lambda decode_path: tuple(str(dp) for dp in decode_path)
136 class TestHex(TestCase):
138 def test_symmetric(self, data):
139 self.assertEqual(hexdec(hexenc(data)), data)
142 class TestTagCoder(TestCase):
143 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
147 integers(min_value=0, max_value=30),
150 def test_short(self, klass, form, num, junk):
151 raw = tag_encode(klass=klass, form=form, num=num)
152 self.assertEqual(tag_decode(raw), (klass, form, num))
153 self.assertEqual(len(raw), 1)
155 byte2int(tag_encode(klass=klass, form=form, num=0)),
156 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
158 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
159 self.assertSequenceEqual(stripped.tobytes(), raw)
160 self.assertEqual(tlen, len(raw))
161 self.assertSequenceEqual(tail, junk)
163 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
167 integers(min_value=31),
170 def test_long(self, klass, form, num, junk):
171 raw = tag_encode(klass=klass, form=form, num=num)
172 self.assertEqual(tag_decode(raw), (klass, form, num))
173 self.assertGreater(len(raw), 1)
175 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
178 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
179 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
180 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
181 self.assertSequenceEqual(stripped.tobytes(), raw)
182 self.assertEqual(tlen, len(raw))
183 self.assertSequenceEqual(tail, junk)
185 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
186 @given(integers(min_value=31))
187 def test_unfinished_tag(self, num):
188 raw = bytearray(tag_encode(num=num))
189 for i in range(1, len(raw)):
191 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
192 tag_strip(bytes(raw))
194 def test_go_vectors_valid(self):
195 for data, (eklass, etag, elen, eform) in (
196 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
197 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
198 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
199 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
200 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
201 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
202 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
203 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
204 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
205 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
207 tag, _, len_encoded = tag_strip(memoryview(data))
208 klass, form, num = tag_decode(tag)
209 _len, _, tail = len_decode(len_encoded)
210 self.assertSequenceEqual(tail, b"")
211 self.assertEqual(klass, eklass)
212 self.assertEqual(num, etag)
213 self.assertEqual(_len, elen)
214 self.assertEqual(form, eform)
216 def test_go_vectors_invalid(self):
224 with self.assertRaises(DecodeError):
225 _, _, len_encoded = tag_strip(memoryview(data))
226 len_decode(len_encoded)
229 integers(min_value=0, max_value=127),
230 integers(min_value=0, max_value=2),
232 def test_long_instead_of_short(self, l, dummy_num):
233 octets = (b"\x00" * dummy_num) + int2byte(l)
234 octets = int2byte((dummy_num + 1) | 0x80) + octets
235 with self.assertRaises(DecodeError):
239 class TestLenCoder(TestCase):
240 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
242 integers(min_value=0, max_value=127),
245 def test_short(self, l, junk):
246 raw = len_encode(l) + junk
247 decoded, llen, tail = len_decode(memoryview(raw))
248 self.assertEqual(decoded, l)
249 self.assertEqual(llen, 1)
250 self.assertEqual(len(raw), 1 + len(junk))
251 self.assertEqual(tail.tobytes(), junk)
253 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
255 integers(min_value=128),
258 def test_long(self, l, junk):
259 raw = len_encode(l) + junk
260 decoded, llen, tail = len_decode(memoryview(raw))
261 self.assertEqual(decoded, l)
262 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
263 self.assertEqual(llen, len(raw) - len(junk))
264 self.assertNotEqual(indexbytes(raw, 1), 0)
265 self.assertSequenceEqual(tail.tobytes(), junk)
267 def test_empty(self):
268 with self.assertRaises(NotEnoughData):
271 @given(integers(min_value=128))
272 def test_stripped(self, _len):
273 with self.assertRaises(NotEnoughData):
274 len_decode(len_encode(_len)[:-1])
277 text_printable = text(alphabet=printable, min_size=1)
281 def text_letters(draw):
282 result = draw(text(alphabet=ascii_letters, min_size=1))
284 result = result.encode("ascii")
288 class CommonMixin(object):
289 def test_tag_default(self):
290 obj = self.base_klass()
291 self.assertEqual(obj.tag, obj.tag_default)
293 def test_simultaneous_impl_expl(self):
294 with self.assertRaises(ValueError):
295 self.base_klass(impl=b"whatever", expl=b"whenever")
297 @given(binary(min_size=1), integers(), integers(), integers())
298 def test_decoded(self, impl, offset, llen, vlen):
299 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
300 self.assertEqual(obj.offset, offset)
301 self.assertEqual(obj.llen, llen)
302 self.assertEqual(obj.vlen, vlen)
303 self.assertEqual(obj.tlen, len(impl))
304 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
306 @given(binary(min_size=1))
307 def test_impl_inherited(self, impl_tag):
308 class Inherited(self.base_klass):
311 self.assertSequenceEqual(obj.impl, impl_tag)
312 self.assertFalse(obj.expled)
315 def test_expl_inherited(self, expl_tag):
316 class Inherited(self.base_klass):
319 self.assertSequenceEqual(obj.expl, expl_tag)
320 self.assertTrue(obj.expled)
322 def assert_copied_basic_fields(self, obj, obj_copied):
323 self.assertEqual(obj, obj_copied)
324 self.assertSequenceEqual(obj.tag, obj_copied.tag)
325 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
326 self.assertEqual(obj.default, obj_copied.default)
327 self.assertEqual(obj.optional, obj_copied.optional)
328 self.assertEqual(obj.offset, obj_copied.offset)
329 self.assertEqual(obj.llen, obj_copied.llen)
330 self.assertEqual(obj.vlen, obj_copied.vlen)
334 def boolean_values_strategy(draw, do_expl=False):
335 value = draw(one_of(none(), booleans()))
339 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
341 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
342 default = draw(one_of(none(), booleans()))
343 optional = draw(one_of(none(), booleans()))
345 draw(integers(min_value=0)),
346 draw(integers(min_value=0)),
347 draw(integers(min_value=0)),
349 return (value, impl, expl, default, optional, _decoded)
352 class BooleanInherited(Boolean):
356 class TestBoolean(CommonMixin, TestCase):
359 def test_invalid_value_type(self):
360 with self.assertRaises(InvalidValueType) as err:
365 def test_optional(self, optional):
366 obj = Boolean(default=Boolean(False), optional=optional)
367 self.assertTrue(obj.optional)
370 def test_ready(self, value):
372 self.assertFalse(obj.ready)
375 with self.assertRaises(ObjNotReady) as err:
379 self.assertTrue(obj.ready)
383 @given(booleans(), booleans(), binary(), binary())
384 def test_comparison(self, value1, value2, tag1, tag2):
385 for klass in (Boolean, BooleanInherited):
388 self.assertEqual(obj1 == obj2, value1 == value2)
389 self.assertEqual(obj1 != obj2, value1 != value2)
390 self.assertEqual(obj1 == bool(obj2), value1 == value2)
391 obj1 = klass(value1, impl=tag1)
392 obj2 = klass(value1, impl=tag2)
393 self.assertEqual(obj1 == obj2, tag1 == tag2)
394 self.assertEqual(obj1 != obj2, tag1 != tag2)
396 @given(data_strategy())
397 def test_call(self, d):
398 for klass in (Boolean, BooleanInherited):
406 ) = d.draw(boolean_values_strategy())
412 optional_initial or False,
422 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
423 obj = obj_initial(value, impl, expl, default, optional)
425 value_expected = default if value is None else value
427 default_initial if value_expected is None
430 self.assertEqual(obj, value_expected)
431 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
432 self.assertEqual(obj.expl_tag, expl or expl_initial)
435 default_initial if default is None else default,
437 if obj.default is None:
438 optional = optional_initial if optional is None else optional
439 optional = False if optional is None else optional
442 self.assertEqual(obj.optional, optional)
444 @given(boolean_values_strategy())
445 def test_copy(self, values):
446 for klass in (Boolean, BooleanInherited):
448 obj_copied = obj.copy()
449 self.assert_copied_basic_fields(obj, obj_copied)
453 integers(min_value=1).map(tag_encode),
455 def test_stripped(self, value, tag_impl):
456 obj = Boolean(value, impl=tag_impl)
457 with self.assertRaises(NotEnoughData):
458 obj.decode(obj.encode()[:-1])
462 integers(min_value=1).map(tag_ctxc),
464 def test_stripped_expl(self, value, tag_expl):
465 obj = Boolean(value, expl=tag_expl)
466 with self.assertRaises(NotEnoughData):
467 obj.decode(obj.encode()[:-1])
470 integers(min_value=31),
471 integers(min_value=0),
474 def test_bad_tag(self, tag, offset, decode_path):
475 with self.assertRaises(DecodeError) as err:
477 tag_encode(tag)[:-1],
479 decode_path=decode_path,
482 self.assertEqual(err.exception.offset, offset)
483 self.assertEqual(err.exception.decode_path, decode_path)
486 integers(min_value=31),
487 integers(min_value=0),
490 def test_bad_expl_tag(self, tag, offset, decode_path):
491 with self.assertRaises(DecodeError) as err:
492 Boolean(expl=Boolean.tag_default).decode(
493 tag_encode(tag)[:-1],
495 decode_path=decode_path,
498 self.assertEqual(err.exception.offset, offset)
499 self.assertEqual(err.exception.decode_path, decode_path)
502 integers(min_value=128),
503 integers(min_value=0),
506 def test_bad_len(self, l, offset, decode_path):
507 with self.assertRaises(DecodeError) as err:
509 Boolean.tag_default + len_encode(l)[:-1],
511 decode_path=decode_path,
514 self.assertEqual(err.exception.offset, offset)
515 self.assertEqual(err.exception.decode_path, decode_path)
518 integers(min_value=128),
519 integers(min_value=0),
522 def test_bad_expl_len(self, l, offset, decode_path):
523 with self.assertRaises(DecodeError) as err:
524 Boolean(expl=Boolean.tag_default).decode(
525 Boolean.tag_default + len_encode(l)[:-1],
527 decode_path=decode_path,
530 self.assertEqual(err.exception.offset, offset)
531 self.assertEqual(err.exception.decode_path, decode_path)
533 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
535 boolean_values_strategy(),
537 integers(min_value=1).map(tag_ctxc),
538 integers(min_value=0),
541 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
542 for klass in (Boolean, BooleanInherited):
543 _, _, _, default, optional, _decoded = values
552 self.assertFalse(obj.expled)
553 obj_encoded = obj.encode()
554 obj_expled = obj(value, expl=tag_expl)
555 self.assertTrue(obj_expled.expled)
558 obj_expled_encoded = obj_expled.encode()
559 obj_decoded, tail = obj_expled.decode(
560 obj_expled_encoded + tail_junk,
565 self.assertEqual(tail, tail_junk)
566 self.assertEqual(obj_decoded, obj_expled)
567 self.assertNotEqual(obj_decoded, obj)
568 self.assertEqual(bool(obj_decoded), bool(obj_expled))
569 self.assertEqual(bool(obj_decoded), bool(obj))
570 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
571 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
572 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
574 obj_decoded.expl_llen,
575 len(len_encode(len(obj_encoded))),
577 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
578 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
581 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
583 self.assertEqual(obj_decoded.expl_offset, offset)
585 @given(integers(min_value=2))
586 def test_invalid_len(self, l):
587 with self.assertRaises(InvalidLength):
588 Boolean().decode(b"".join((
594 @given(integers(min_value=0 + 1, max_value=255 - 1))
595 def test_ber_value(self, value):
596 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
597 Boolean().decode(b"".join((
602 obj, _ = Boolean().decode(
610 self.assertTrue(bool(obj))
611 self.assertTrue(obj.bered)
612 self.assertFalse(obj.lenindef)
615 integers(min_value=1).map(tag_ctxc),
616 binary().filter(lambda x: not x.startswith(EOC)),
618 def test_ber_expl_no_eoc(self, expl, junk):
619 encoded = expl + LENINDEF + Boolean(False).encode()
620 with assertRaisesRegex(self, DecodeError, "no EOC"):
621 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
622 obj, tail = Boolean(expl=expl).decode(
623 encoded + EOC + junk,
626 self.assertTrue(obj.expl_lenindef)
627 self.assertSequenceEqual(tail, junk)
630 integers(min_value=1).map(tag_ctxc),
637 def test_ber_expl(self, expl, values):
643 Boolean(value).encode() +
646 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
648 class SeqOf(SequenceOf):
649 schema = Boolean(expl=expl)
650 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
651 self.assertSequenceEqual(tail, b"")
652 self.assertSequenceEqual([bool(v) for v in seqof], values)
667 len(expl) + 1 + 3 + EOC_LEN,
678 def integer_values_strategy(draw, do_expl=False):
679 bound_min, value, default, bound_max = sorted(draw(sets(
688 _specs = draw(sets(text_letters()))
691 min_size=len(_specs),
692 max_size=len(_specs),
694 _specs = list(zip(_specs, values))
697 bounds = (bound_min, bound_max)
701 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
703 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
706 optional = draw(one_of(none(), booleans()))
708 draw(integers(min_value=0)),
709 draw(integers(min_value=0)),
710 draw(integers(min_value=0)),
712 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
715 class IntegerInherited(Integer):
719 class TestInteger(CommonMixin, TestCase):
722 def test_invalid_value_type(self):
723 with self.assertRaises(InvalidValueType) as err:
727 @given(sets(text_letters(), min_size=2))
728 def test_unknown_name(self, names_input):
729 missing = names_input.pop()
732 schema = [(n, 123) for n in names_input]
733 with self.assertRaises(ObjUnknown) as err:
737 @given(sets(text_letters(), min_size=2))
738 def test_known_name(self, names_input):
740 schema = [(n, 123) for n in names_input]
741 Int(names_input.pop())
744 def test_optional(self, optional):
745 obj = Integer(default=Integer(0), optional=optional)
746 self.assertTrue(obj.optional)
749 def test_ready(self, value):
751 self.assertFalse(obj.ready)
754 with self.assertRaises(ObjNotReady) as err:
758 self.assertTrue(obj.ready)
763 @given(integers(), integers(), binary(), binary())
764 def test_comparison(self, value1, value2, tag1, tag2):
765 for klass in (Integer, IntegerInherited):
768 self.assertEqual(obj1 == obj2, value1 == value2)
769 self.assertEqual(obj1 != obj2, value1 != value2)
770 self.assertEqual(obj1 == int(obj2), value1 == value2)
771 obj1 = klass(value1, impl=tag1)
772 obj2 = klass(value1, impl=tag2)
773 self.assertEqual(obj1 == obj2, tag1 == tag2)
774 self.assertEqual(obj1 != obj2, tag1 != tag2)
776 @given(lists(integers()))
777 def test_sorted_works(self, values):
778 self.assertSequenceEqual(
779 [int(v) for v in sorted(Integer(v) for v in values)],
783 @given(data_strategy())
784 def test_named(self, d):
785 names_input = list(d.draw(sets(text_letters(), min_size=1)))
786 values_input = list(d.draw(sets(
788 min_size=len(names_input),
789 max_size=len(names_input),
791 chosen_name = d.draw(sampled_from(names_input))
792 names_input = dict(zip(names_input, values_input))
796 _int = Int(chosen_name)
797 self.assertEqual(_int.named, chosen_name)
798 self.assertEqual(int(_int), names_input[chosen_name])
800 @given(integers(), integers(min_value=0), integers(min_value=0))
801 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
802 value = bound_min + value_delta
803 bound_max = value + bound_delta
804 Integer(value=value, bounds=(bound_min, bound_max))
806 @given(sets(integers(), min_size=3, max_size=3))
807 def test_bounds_unsatisfied(self, values):
808 values = sorted(values)
809 with self.assertRaises(BoundsError) as err:
810 Integer(value=values[0], bounds=(values[1], values[2]))
812 with assertRaisesRegex(self, DecodeError, "bounds") as err:
813 Integer(bounds=(values[1], values[2])).decode(
814 Integer(values[0]).encode()
817 with self.assertRaises(BoundsError) as err:
818 Integer(value=values[2], bounds=(values[0], values[1]))
820 with assertRaisesRegex(self, DecodeError, "bounds") as err:
821 Integer(bounds=(values[0], values[1])).decode(
822 Integer(values[2]).encode()
826 @given(data_strategy())
827 def test_call(self, d):
828 for klass in (Integer, IntegerInherited):
838 ) = d.draw(integer_values_strategy())
845 optional_initial or False,
858 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
859 if (default is None) and (obj_initial.default is not None):
863 (value is not None) and
864 (bounds_initial is not None) and
865 not (bounds_initial[0] <= value <= bounds_initial[1])
870 (default is not None) and
871 (bounds_initial is not None) and
872 not (bounds_initial[0] <= default <= bounds_initial[1])
875 obj = obj_initial(value, bounds, impl, expl, default, optional)
877 value_expected = default if value is None else value
879 default_initial if value_expected is None
882 self.assertEqual(obj, value_expected)
883 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
884 self.assertEqual(obj.expl_tag, expl or expl_initial)
887 default_initial if default is None else default,
889 if obj.default is None:
890 optional = optional_initial if optional is None else optional
891 optional = False if optional is None else optional
894 self.assertEqual(obj.optional, optional)
896 (obj._bound_min, obj._bound_max),
897 bounds or bounds_initial or (float("-inf"), float("+inf")),
901 {} if _specs_initial is None else dict(_specs_initial),
904 @given(integer_values_strategy())
905 def test_copy(self, values):
906 for klass in (Integer, IntegerInherited):
908 obj_copied = obj.copy()
909 self.assert_copied_basic_fields(obj, obj_copied)
910 self.assertEqual(obj.specs, obj_copied.specs)
911 self.assertEqual(obj._bound_min, obj_copied._bound_min)
912 self.assertEqual(obj._bound_max, obj_copied._bound_max)
913 self.assertEqual(obj._value, obj_copied._value)
917 integers(min_value=1).map(tag_encode),
919 def test_stripped(self, value, tag_impl):
920 obj = Integer(value, impl=tag_impl)
921 with self.assertRaises(NotEnoughData):
922 obj.decode(obj.encode()[:-1])
926 integers(min_value=1).map(tag_ctxc),
928 def test_stripped_expl(self, value, tag_expl):
929 obj = Integer(value, expl=tag_expl)
930 with self.assertRaises(NotEnoughData):
931 obj.decode(obj.encode()[:-1])
933 def test_zero_len(self):
934 with self.assertRaises(NotEnoughData):
935 Integer().decode(b"".join((
941 integers(min_value=31),
942 integers(min_value=0),
945 def test_bad_tag(self, tag, offset, decode_path):
946 with self.assertRaises(DecodeError) as err:
948 tag_encode(tag)[:-1],
950 decode_path=decode_path,
953 self.assertEqual(err.exception.offset, offset)
954 self.assertEqual(err.exception.decode_path, decode_path)
957 integers(min_value=128),
958 integers(min_value=0),
961 def test_bad_len(self, l, offset, decode_path):
962 with self.assertRaises(DecodeError) as err:
964 Integer.tag_default + len_encode(l)[:-1],
966 decode_path=decode_path,
969 self.assertEqual(err.exception.offset, offset)
970 self.assertEqual(err.exception.decode_path, decode_path)
973 sets(integers(), min_size=2, max_size=2),
974 integers(min_value=0),
977 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
978 value, bound_min = list(sorted(ints))
981 bounds = (bound_min, bound_min)
982 with self.assertRaises(DecodeError) as err:
984 Integer(value).encode(),
986 decode_path=decode_path,
989 self.assertEqual(err.exception.offset, offset)
990 self.assertEqual(err.exception.decode_path, decode_path)
992 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
994 integer_values_strategy(),
996 integers(min_value=1).map(tag_ctxc),
997 integers(min_value=0),
1000 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1001 for klass in (Integer, IntegerInherited):
1002 _, _, _, _, default, optional, _, _decoded = values
1011 self.assertFalse(obj.expled)
1012 obj_encoded = obj.encode()
1013 obj_expled = obj(value, expl=tag_expl)
1014 self.assertTrue(obj_expled.expled)
1017 obj_expled_encoded = obj_expled.encode()
1018 obj_decoded, tail = obj_expled.decode(
1019 obj_expled_encoded + tail_junk,
1024 self.assertEqual(tail, tail_junk)
1025 self.assertEqual(obj_decoded, obj_expled)
1026 self.assertNotEqual(obj_decoded, obj)
1027 self.assertEqual(int(obj_decoded), int(obj_expled))
1028 self.assertEqual(int(obj_decoded), int(obj))
1029 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1030 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1031 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1033 obj_decoded.expl_llen,
1034 len(len_encode(len(obj_encoded))),
1036 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1037 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1040 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1042 self.assertEqual(obj_decoded.expl_offset, offset)
1044 def test_go_vectors_valid(self):
1045 for data, expect in ((
1049 (b"\xff\x7f", -129),
1053 (b"\xff\x00", -256),
1057 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1058 (b"\x80\x00\x00\x00", -2147483648),
1061 Integer().decode(b"".join((
1062 Integer.tag_default,
1063 len_encode(len(data)),
1069 def test_go_vectors_invalid(self):
1074 with self.assertRaises(DecodeError):
1075 Integer().decode(b"".join((
1076 Integer.tag_default,
1077 len_encode(len(data)),
1083 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1086 if draw(booleans()):
1087 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1089 integers(min_value=0, max_value=255),
1090 min_size=len(schema),
1091 max_size=len(schema),
1093 schema = list(zip(schema, bits))
1095 def _value(value_required):
1096 if not value_required and draw(booleans()):
1098 generation_choice = 0
1100 generation_choice = draw(sampled_from((1, 2, 3)))
1101 if generation_choice == 1 or draw(booleans()):
1102 return "'%s'B" % "".join(draw(lists(
1103 sampled_from(("0", "1")),
1104 max_size=len(schema),
1106 elif generation_choice == 2 or draw(booleans()):
1107 return draw(binary(max_size=len(schema) // 8))
1108 elif generation_choice == 3 or draw(booleans()):
1109 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1111 value = _value(value_required)
1112 default = _value(value_required=False)
1116 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1118 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1119 optional = draw(one_of(none(), booleans()))
1121 draw(integers(min_value=0)),
1122 draw(integers(min_value=0)),
1123 draw(integers(min_value=0)),
1125 return (schema, value, impl, expl, default, optional, _decoded)
1128 class BitStringInherited(BitString):
1132 class TestBitString(CommonMixin, TestCase):
1133 base_klass = BitString
1135 @given(lists(booleans()))
1136 def test_b_encoding(self, bits):
1137 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1138 self.assertEqual(obj.bit_len, len(bits))
1139 self.assertSequenceEqual(list(obj), bits)
1140 for i, bit in enumerate(bits):
1141 self.assertEqual(obj[i], bit)
1143 @given(lists(booleans()))
1144 def test_out_of_bounds_bits(self, bits):
1145 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1146 for i in range(len(bits), len(bits) * 2):
1147 self.assertFalse(obj[i])
1149 def test_bad_b_encoding(self):
1150 with self.assertRaises(ValueError):
1151 BitString("'010120101'B")
1154 integers(min_value=1, max_value=255),
1155 integers(min_value=1, max_value=255),
1157 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1158 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1159 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1160 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1162 class BS(BitString):
1163 schema = (("whatever", 0),)
1164 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1165 self.assertEqual(obj.bit_len, leading_zeros + 1)
1166 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1168 def test_zero_len(self):
1169 with self.assertRaises(NotEnoughData):
1170 BitString().decode(b"".join((
1171 BitString.tag_default,
1175 def test_invalid_value_type(self):
1176 with self.assertRaises(InvalidValueType) as err:
1179 with self.assertRaises(InvalidValueType) as err:
1183 def test_obj_unknown(self):
1184 with self.assertRaises(ObjUnknown) as err:
1185 BitString(b"whatever")["whenever"]
1188 def test_get_invalid_type(self):
1189 with self.assertRaises(InvalidValueType) as err:
1190 BitString(b"whatever")[(1, 2, 3)]
1193 @given(data_strategy())
1194 def test_unknown_name(self, d):
1195 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1196 missing = _schema.pop()
1198 class BS(BitString):
1199 schema = [(n, i) for i, n in enumerate(_schema)]
1200 with self.assertRaises(ObjUnknown) as err:
1205 def test_optional(self, optional):
1206 obj = BitString(default=BitString(b""), optional=optional)
1207 self.assertTrue(obj.optional)
1210 def test_ready(self, value):
1212 self.assertFalse(obj.ready)
1215 with self.assertRaises(ObjNotReady) as err:
1218 obj = BitString(value)
1219 self.assertTrue(obj.ready)
1224 tuples(integers(min_value=0), binary()),
1225 tuples(integers(min_value=0), binary()),
1229 def test_comparison(self, value1, value2, tag1, tag2):
1230 for klass in (BitString, BitStringInherited):
1231 obj1 = klass(value1)
1232 obj2 = klass(value2)
1233 self.assertEqual(obj1 == obj2, value1 == value2)
1234 self.assertEqual(obj1 != obj2, value1 != value2)
1235 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1236 obj1 = klass(value1, impl=tag1)
1237 obj2 = klass(value1, impl=tag2)
1238 self.assertEqual(obj1 == obj2, tag1 == tag2)
1239 self.assertEqual(obj1 != obj2, tag1 != tag2)
1241 @given(data_strategy())
1242 def test_call(self, d):
1243 for klass in (BitString, BitStringInherited):
1252 ) = d.draw(bit_string_values_strategy())
1255 schema = schema_initial
1257 value=value_initial,
1260 default=default_initial,
1261 optional=optional_initial or False,
1262 _decoded=_decoded_initial,
1272 ) = d.draw(bit_string_values_strategy(
1273 schema=schema_initial,
1274 do_expl=impl_initial is None,
1283 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1284 self.assertEqual(obj.expl_tag, expl or expl_initial)
1285 if obj.default is None:
1286 optional = optional_initial if optional is None else optional
1287 optional = False if optional is None else optional
1290 self.assertEqual(obj.optional, optional)
1291 self.assertEqual(obj.specs, obj_initial.specs)
1293 @given(bit_string_values_strategy())
1294 def test_copy(self, values):
1295 for klass in (BitString, BitStringInherited):
1296 _schema, value, impl, expl, default, optional, _decoded = values
1305 optional=optional or False,
1308 obj_copied = obj.copy()
1309 self.assert_copied_basic_fields(obj, obj_copied)
1310 self.assertEqual(obj.specs, obj_copied.specs)
1311 self.assertEqual(obj._value, obj_copied._value)
1315 integers(min_value=1).map(tag_encode),
1317 def test_stripped(self, value, tag_impl):
1318 obj = BitString(value, impl=tag_impl)
1319 with self.assertRaises(NotEnoughData):
1320 obj.decode(obj.encode()[:-1])
1324 integers(min_value=1).map(tag_ctxc),
1326 def test_stripped_expl(self, value, tag_expl):
1327 obj = BitString(value, expl=tag_expl)
1328 with self.assertRaises(NotEnoughData):
1329 obj.decode(obj.encode()[:-1])
1332 integers(min_value=31),
1333 integers(min_value=0),
1336 def test_bad_tag(self, tag, offset, decode_path):
1337 with self.assertRaises(DecodeError) as err:
1339 tag_encode(tag)[:-1],
1341 decode_path=decode_path,
1344 self.assertEqual(err.exception.offset, offset)
1345 self.assertEqual(err.exception.decode_path, decode_path)
1348 integers(min_value=128),
1349 integers(min_value=0),
1352 def test_bad_len(self, l, offset, decode_path):
1353 with self.assertRaises(DecodeError) as err:
1355 BitString.tag_default + len_encode(l)[:-1],
1357 decode_path=decode_path,
1360 self.assertEqual(err.exception.offset, offset)
1361 self.assertEqual(err.exception.decode_path, decode_path)
1363 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1364 @given(data_strategy())
1365 def test_symmetric(self, d):
1374 ) = d.draw(bit_string_values_strategy(value_required=True))
1375 tail_junk = d.draw(binary(max_size=5))
1376 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1377 offset = d.draw(integers(min_value=0))
1378 for klass in (BitString, BitStringInherited):
1389 self.assertFalse(obj.expled)
1390 obj_encoded = obj.encode()
1391 obj_expled = obj(value, expl=tag_expl)
1392 self.assertTrue(obj_expled.expled)
1395 obj_expled_encoded = obj_expled.encode()
1396 obj_decoded, tail = obj_expled.decode(
1397 obj_expled_encoded + tail_junk,
1402 self.assertEqual(tail, tail_junk)
1403 self.assertEqual(obj_decoded, obj_expled)
1404 self.assertNotEqual(obj_decoded, obj)
1405 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1406 self.assertEqual(bytes(obj_decoded), bytes(obj))
1407 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1408 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1409 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1411 obj_decoded.expl_llen,
1412 len(len_encode(len(obj_encoded))),
1414 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1415 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1418 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1420 self.assertEqual(obj_decoded.expl_offset, offset)
1421 if isinstance(value, tuple):
1422 self.assertSetEqual(set(value), set(obj_decoded.named))
1426 @given(integers(min_value=1, max_value=255))
1427 def test_bad_zero_value(self, pad_size):
1428 with self.assertRaises(DecodeError):
1429 BitString().decode(b"".join((
1430 BitString.tag_default,
1435 def test_go_vectors_invalid(self):
1441 with self.assertRaises(DecodeError):
1442 BitString().decode(b"".join((
1443 BitString.tag_default,
1448 def test_go_vectors_valid(self):
1449 obj, _ = BitString().decode(b"".join((
1450 BitString.tag_default,
1454 self.assertEqual(bytes(obj), b"")
1455 self.assertEqual(obj.bit_len, 0)
1457 obj, _ = BitString().decode(b"".join((
1458 BitString.tag_default,
1462 self.assertEqual(bytes(obj), b"\x00")
1463 self.assertEqual(obj.bit_len, 1)
1465 obj = BitString((16, b"\x82\x40"))
1466 self.assertTrue(obj[0])
1467 self.assertFalse(obj[1])
1468 self.assertTrue(obj[6])
1469 self.assertTrue(obj[9])
1470 self.assertFalse(obj[17])
1473 integers(min_value=1, max_value=30),
1476 binary(min_size=1, max_size=5),
1478 binary(min_size=1, max_size=5),
1486 lists(booleans(), min_size=1),
1489 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1490 def chunk_constructed(contents):
1492 tag_encode(form=TagFormConstructed, num=3) +
1494 b"".join(BitString(content).encode() for content in contents) +
1498 payload_expected = b""
1499 bit_len_expected = 0
1500 for chunk_input in chunk_inputs:
1501 if isinstance(chunk_input, binary_type):
1502 chunks.append(BitString(chunk_input).encode())
1503 payload_expected += chunk_input
1504 bit_len_expected += len(chunk_input) * 8
1506 chunks.append(chunk_constructed(chunk_input))
1507 payload = b"".join(chunk_input)
1508 payload_expected += payload
1509 bit_len_expected += len(payload) * 8
1510 chunk_last = BitString("'%s'B" % "".join(
1511 "1" if bit else "0" for bit in chunk_last_bits
1513 payload_expected += bytes(chunk_last)
1514 bit_len_expected += chunk_last.bit_len
1515 encoded_indefinite = (
1516 tag_encode(form=TagFormConstructed, num=impl) +
1519 chunk_last.encode() +
1522 encoded_definite = (
1523 tag_encode(form=TagFormConstructed, num=impl) +
1524 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1528 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1529 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1530 for lenindef_expected, encoded in (
1531 (True, encoded_indefinite),
1532 (False, encoded_definite),
1534 obj, tail = BitString(impl=tag_encode(impl)).decode(
1536 ctx={"bered": True},
1538 self.assertSequenceEqual(tail, junk)
1539 self.assertEqual(obj.bit_len, bit_len_expected)
1540 self.assertSequenceEqual(bytes(obj), payload_expected)
1541 self.assertTrue(obj.bered)
1542 self.assertEqual(obj.lenindef, lenindef_expected)
1543 self.assertEqual(len(encoded), obj.tlvlen)
1546 integers(min_value=0),
1549 def test_ber_definite_too_short(self, offset, decode_path):
1550 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1552 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1554 decode_path=decode_path,
1555 ctx={"bered": True},
1557 self.assertEqual(err.exception.decode_path, decode_path)
1558 self.assertEqual(err.exception.offset, offset)
1561 integers(min_value=0),
1564 def test_ber_definite_no_data(self, offset, decode_path):
1565 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1567 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1569 decode_path=decode_path,
1570 ctx={"bered": True},
1572 self.assertEqual(err.exception.decode_path, decode_path)
1573 self.assertEqual(err.exception.offset, offset)
1576 integers(min_value=0),
1578 integers(min_value=1, max_value=3),
1580 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1581 bs = BitString(b"data").encode()
1582 with self.assertRaises(NotEnoughData) as err:
1584 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1586 decode_path=decode_path,
1587 ctx={"bered": True},
1589 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1590 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1593 integers(min_value=0),
1595 integers(min_value=1, max_value=3),
1597 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1598 bs = BitString(b"data").encode()
1599 bs_longer = BitString(b"data-longer").encode()
1600 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1603 tag_encode(3, form=TagFormConstructed) +
1604 len_encode((chunks + 1) * len(bs)) +
1609 decode_path=decode_path,
1610 ctx={"bered": True},
1612 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1613 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1616 integers(min_value=0),
1619 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1620 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1622 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1624 decode_path=decode_path,
1625 ctx={"bered": True},
1627 self.assertEqual(err.exception.decode_path, decode_path)
1628 self.assertEqual(err.exception.offset, offset)
1630 @given(data_strategy())
1631 def test_ber_indefinite_not_multiple(self, d):
1632 bs_short = BitString("'A'H").encode()
1633 bs_full = BitString("'AA'H").encode()
1634 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1635 chunks.append(bs_short)
1636 d.draw(permutations(chunks))
1637 chunks.append(bs_short)
1638 offset = d.draw(integers(min_value=0))
1639 decode_path = d.draw(decode_path_strat)
1640 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1643 tag_encode(3, form=TagFormConstructed) +
1649 decode_path=decode_path,
1650 ctx={"bered": True},
1653 err.exception.decode_path,
1654 decode_path + (str(chunks.index(bs_short)),),
1657 err.exception.offset,
1658 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1661 def test_x690_vector(self):
1662 vector = BitString("'0A3B5F291CD'H")
1663 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1664 self.assertSequenceEqual(tail, b"")
1665 self.assertEqual(obj, vector)
1666 obj, tail = BitString().decode(
1667 hexdec("23800303000A3B0305045F291CD00000"),
1668 ctx={"bered": True},
1670 self.assertSequenceEqual(tail, b"")
1671 self.assertEqual(obj, vector)
1672 self.assertTrue(obj.bered)
1673 self.assertTrue(obj.lenindef)
1677 def octet_string_values_strategy(draw, do_expl=False):
1678 bound_min, bound_max = sorted(draw(sets(
1679 integers(min_value=0, max_value=1 << 7),
1683 value = draw(one_of(
1685 binary(min_size=bound_min, max_size=bound_max),
1687 default = draw(one_of(
1689 binary(min_size=bound_min, max_size=bound_max),
1692 if draw(booleans()):
1693 bounds = (bound_min, bound_max)
1697 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1699 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1700 optional = draw(one_of(none(), booleans()))
1702 draw(integers(min_value=0)),
1703 draw(integers(min_value=0)),
1704 draw(integers(min_value=0)),
1706 return (value, bounds, impl, expl, default, optional, _decoded)
1709 class OctetStringInherited(OctetString):
1713 class TestOctetString(CommonMixin, TestCase):
1714 base_klass = OctetString
1716 def test_invalid_value_type(self):
1717 with self.assertRaises(InvalidValueType) as err:
1718 OctetString(text_type(123))
1722 def test_optional(self, optional):
1723 obj = OctetString(default=OctetString(b""), optional=optional)
1724 self.assertTrue(obj.optional)
1727 def test_ready(self, value):
1729 self.assertFalse(obj.ready)
1732 with self.assertRaises(ObjNotReady) as err:
1735 obj = OctetString(value)
1736 self.assertTrue(obj.ready)
1740 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1741 def test_comparison(self, value1, value2, tag1, tag2):
1742 for klass in (OctetString, OctetStringInherited):
1743 obj1 = klass(value1)
1744 obj2 = klass(value2)
1745 self.assertEqual(obj1 == obj2, value1 == value2)
1746 self.assertEqual(obj1 != obj2, value1 != value2)
1747 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1748 obj1 = klass(value1, impl=tag1)
1749 obj2 = klass(value1, impl=tag2)
1750 self.assertEqual(obj1 == obj2, tag1 == tag2)
1751 self.assertEqual(obj1 != obj2, tag1 != tag2)
1753 @given(lists(binary()))
1754 def test_sorted_works(self, values):
1755 self.assertSequenceEqual(
1756 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1760 @given(data_strategy())
1761 def test_bounds_satisfied(self, d):
1762 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1763 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1764 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1765 OctetString(value=value, bounds=(bound_min, bound_max))
1767 @given(data_strategy())
1768 def test_bounds_unsatisfied(self, d):
1769 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1770 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1771 value = d.draw(binary(max_size=bound_min - 1))
1772 with self.assertRaises(BoundsError) as err:
1773 OctetString(value=value, bounds=(bound_min, bound_max))
1775 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1776 OctetString(bounds=(bound_min, bound_max)).decode(
1777 OctetString(value).encode()
1780 value = d.draw(binary(min_size=bound_max + 1))
1781 with self.assertRaises(BoundsError) as err:
1782 OctetString(value=value, bounds=(bound_min, bound_max))
1784 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1785 OctetString(bounds=(bound_min, bound_max)).decode(
1786 OctetString(value).encode()
1790 @given(data_strategy())
1791 def test_call(self, d):
1792 for klass in (OctetString, OctetStringInherited):
1801 ) = d.draw(octet_string_values_strategy())
1802 obj_initial = klass(
1808 optional_initial or False,
1819 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1820 if (default is None) and (obj_initial.default is not None):
1823 (bounds is None) and
1824 (value is not None) and
1825 (bounds_initial is not None) and
1826 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1830 (bounds is None) and
1831 (default is not None) and
1832 (bounds_initial is not None) and
1833 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1836 obj = obj_initial(value, bounds, impl, expl, default, optional)
1838 value_expected = default if value is None else value
1840 default_initial if value_expected is None
1843 self.assertEqual(obj, value_expected)
1844 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1845 self.assertEqual(obj.expl_tag, expl or expl_initial)
1848 default_initial if default is None else default,
1850 if obj.default is None:
1851 optional = optional_initial if optional is None else optional
1852 optional = False if optional is None else optional
1855 self.assertEqual(obj.optional, optional)
1857 (obj._bound_min, obj._bound_max),
1858 bounds or bounds_initial or (0, float("+inf")),
1861 @given(octet_string_values_strategy())
1862 def test_copy(self, values):
1863 for klass in (OctetString, OctetStringInherited):
1864 obj = klass(*values)
1865 obj_copied = obj.copy()
1866 self.assert_copied_basic_fields(obj, obj_copied)
1867 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1868 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1869 self.assertEqual(obj._value, obj_copied._value)
1873 integers(min_value=1).map(tag_encode),
1875 def test_stripped(self, value, tag_impl):
1876 obj = OctetString(value, impl=tag_impl)
1877 with self.assertRaises(NotEnoughData):
1878 obj.decode(obj.encode()[:-1])
1882 integers(min_value=1).map(tag_ctxc),
1884 def test_stripped_expl(self, value, tag_expl):
1885 obj = OctetString(value, expl=tag_expl)
1886 with self.assertRaises(NotEnoughData):
1887 obj.decode(obj.encode()[:-1])
1890 integers(min_value=31),
1891 integers(min_value=0),
1894 def test_bad_tag(self, tag, offset, decode_path):
1895 with self.assertRaises(DecodeError) as err:
1896 OctetString().decode(
1897 tag_encode(tag)[:-1],
1899 decode_path=decode_path,
1902 self.assertEqual(err.exception.offset, offset)
1903 self.assertEqual(err.exception.decode_path, decode_path)
1906 integers(min_value=128),
1907 integers(min_value=0),
1910 def test_bad_len(self, l, offset, decode_path):
1911 with self.assertRaises(DecodeError) as err:
1912 OctetString().decode(
1913 OctetString.tag_default + len_encode(l)[:-1],
1915 decode_path=decode_path,
1918 self.assertEqual(err.exception.offset, offset)
1919 self.assertEqual(err.exception.decode_path, decode_path)
1922 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1923 integers(min_value=0),
1926 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1927 value, bound_min = list(sorted(ints))
1929 class String(OctetString):
1930 bounds = (bound_min, bound_min)
1931 with self.assertRaises(DecodeError) as err:
1933 OctetString(b"\x00" * value).encode(),
1935 decode_path=decode_path,
1938 self.assertEqual(err.exception.offset, offset)
1939 self.assertEqual(err.exception.decode_path, decode_path)
1941 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1943 octet_string_values_strategy(),
1945 integers(min_value=1).map(tag_ctxc),
1946 integers(min_value=0),
1949 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1950 for klass in (OctetString, OctetStringInherited):
1951 _, _, _, _, default, optional, _decoded = values
1960 self.assertFalse(obj.expled)
1961 obj_encoded = obj.encode()
1962 obj_expled = obj(value, expl=tag_expl)
1963 self.assertTrue(obj_expled.expled)
1966 obj_expled_encoded = obj_expled.encode()
1967 obj_decoded, tail = obj_expled.decode(
1968 obj_expled_encoded + tail_junk,
1973 self.assertEqual(tail, tail_junk)
1974 self.assertEqual(obj_decoded, obj_expled)
1975 self.assertNotEqual(obj_decoded, obj)
1976 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1977 self.assertEqual(bytes(obj_decoded), bytes(obj))
1978 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1979 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1980 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1982 obj_decoded.expl_llen,
1983 len(len_encode(len(obj_encoded))),
1985 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1986 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1989 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1991 self.assertEqual(obj_decoded.expl_offset, offset)
1994 integers(min_value=1, max_value=30),
1997 binary(min_size=1, max_size=5),
1999 binary(min_size=1, max_size=5),
2009 def test_constructed(self, impl, chunk_inputs, junk):
2010 def chunk_constructed(contents):
2012 tag_encode(form=TagFormConstructed, num=4) +
2014 b"".join(OctetString(content).encode() for content in contents) +
2018 payload_expected = b""
2019 for chunk_input in chunk_inputs:
2020 if isinstance(chunk_input, binary_type):
2021 chunks.append(OctetString(chunk_input).encode())
2022 payload_expected += chunk_input
2024 chunks.append(chunk_constructed(chunk_input))
2025 payload = b"".join(chunk_input)
2026 payload_expected += payload
2027 encoded_indefinite = (
2028 tag_encode(form=TagFormConstructed, num=impl) +
2033 encoded_definite = (
2034 tag_encode(form=TagFormConstructed, num=impl) +
2035 len_encode(len(b"".join(chunks))) +
2038 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2039 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2040 for lenindef_expected, encoded in (
2041 (True, encoded_indefinite),
2042 (False, encoded_definite),
2044 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2046 ctx={"bered": True},
2048 self.assertSequenceEqual(tail, junk)
2049 self.assertSequenceEqual(bytes(obj), payload_expected)
2050 self.assertTrue(obj.bered)
2051 self.assertEqual(obj.lenindef, lenindef_expected)
2052 self.assertEqual(len(encoded), obj.tlvlen)
2055 integers(min_value=0),
2058 def test_ber_definite_too_short(self, offset, decode_path):
2059 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2060 OctetString().decode(
2061 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2063 decode_path=decode_path,
2064 ctx={"bered": True},
2066 self.assertEqual(err.exception.decode_path, decode_path)
2067 self.assertEqual(err.exception.offset, offset)
2070 integers(min_value=0),
2072 integers(min_value=1, max_value=3),
2074 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2075 bs = OctetString(b"data").encode()
2076 with self.assertRaises(NotEnoughData) as err:
2077 OctetString().decode(
2078 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2080 decode_path=decode_path,
2081 ctx={"bered": True},
2083 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2084 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2087 integers(min_value=0),
2089 integers(min_value=1, max_value=3),
2091 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2092 bs = OctetString(b"data").encode()
2093 bs_longer = OctetString(b"data-longer").encode()
2094 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2095 OctetString().decode(
2097 tag_encode(4, form=TagFormConstructed) +
2098 len_encode((chunks + 1) * len(bs)) +
2103 decode_path=decode_path,
2104 ctx={"bered": True},
2106 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2107 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2111 def null_values_strategy(draw, do_expl=False):
2115 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2117 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2118 optional = draw(one_of(none(), booleans()))
2120 draw(integers(min_value=0)),
2121 draw(integers(min_value=0)),
2122 draw(integers(min_value=0)),
2124 return (impl, expl, optional, _decoded)
2127 class NullInherited(Null):
2131 class TestNull(CommonMixin, TestCase):
2134 def test_ready(self):
2136 self.assertTrue(obj.ready)
2140 @given(binary(), binary())
2141 def test_comparison(self, tag1, tag2):
2142 for klass in (Null, NullInherited):
2143 obj1 = klass(impl=tag1)
2144 obj2 = klass(impl=tag2)
2145 self.assertEqual(obj1 == obj2, tag1 == tag2)
2146 self.assertEqual(obj1 != obj2, tag1 != tag2)
2147 self.assertNotEqual(obj1, tag2)
2149 @given(data_strategy())
2150 def test_call(self, d):
2151 for klass in (Null, NullInherited):
2157 ) = d.draw(null_values_strategy())
2158 obj_initial = klass(
2161 optional=optional_initial or False,
2162 _decoded=_decoded_initial,
2169 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2170 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2171 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2172 self.assertEqual(obj.expl_tag, expl or expl_initial)
2173 optional = optional_initial if optional is None else optional
2174 optional = False if optional is None else optional
2175 self.assertEqual(obj.optional, optional)
2177 @given(null_values_strategy())
2178 def test_copy(self, values):
2179 for klass in (Null, NullInherited):
2180 impl, expl, optional, _decoded = values
2184 optional=optional or False,
2187 obj_copied = obj.copy()
2188 self.assert_copied_basic_fields(obj, obj_copied)
2190 @given(integers(min_value=1).map(tag_encode))
2191 def test_stripped(self, tag_impl):
2192 obj = Null(impl=tag_impl)
2193 with self.assertRaises(NotEnoughData):
2194 obj.decode(obj.encode()[:-1])
2196 @given(integers(min_value=1).map(tag_ctxc))
2197 def test_stripped_expl(self, tag_expl):
2198 obj = Null(expl=tag_expl)
2199 with self.assertRaises(NotEnoughData):
2200 obj.decode(obj.encode()[:-1])
2203 integers(min_value=31),
2204 integers(min_value=0),
2207 def test_bad_tag(self, tag, offset, decode_path):
2208 with self.assertRaises(DecodeError) as err:
2210 tag_encode(tag)[:-1],
2212 decode_path=decode_path,
2215 self.assertEqual(err.exception.offset, offset)
2216 self.assertEqual(err.exception.decode_path, decode_path)
2219 integers(min_value=128),
2220 integers(min_value=0),
2223 def test_bad_len(self, l, offset, decode_path):
2224 with self.assertRaises(DecodeError) as err:
2226 Null.tag_default + len_encode(l)[:-1],
2228 decode_path=decode_path,
2231 self.assertEqual(err.exception.offset, offset)
2232 self.assertEqual(err.exception.decode_path, decode_path)
2234 @given(binary(min_size=1))
2235 def test_tag_mismatch(self, impl):
2236 assume(impl != Null.tag_default)
2237 with self.assertRaises(TagMismatch):
2238 Null(impl=impl).decode(Null().encode())
2241 null_values_strategy(),
2242 integers(min_value=1).map(tag_ctxc),
2243 integers(min_value=0),
2246 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2247 for klass in (Null, NullInherited):
2248 _, _, optional, _decoded = values
2249 obj = klass(optional=optional, _decoded=_decoded)
2252 self.assertFalse(obj.expled)
2253 obj_encoded = obj.encode()
2254 obj_expled = obj(expl=tag_expl)
2255 self.assertTrue(obj_expled.expled)
2258 obj_expled_encoded = obj_expled.encode()
2259 obj_decoded, tail = obj_expled.decode(
2260 obj_expled_encoded + tail_junk,
2265 self.assertEqual(tail, tail_junk)
2266 self.assertEqual(obj_decoded, obj_expled)
2267 self.assertNotEqual(obj_decoded, obj)
2268 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2269 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2270 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2272 obj_decoded.expl_llen,
2273 len(len_encode(len(obj_encoded))),
2275 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2276 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2279 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2281 self.assertEqual(obj_decoded.expl_offset, offset)
2283 @given(integers(min_value=1))
2284 def test_invalid_len(self, l):
2285 with self.assertRaises(InvalidLength):
2286 Null().decode(b"".join((
2293 def oid_strategy(draw):
2294 first_arc = draw(integers(min_value=0, max_value=2))
2296 if first_arc in (0, 1):
2297 second_arc = draw(integers(min_value=0, max_value=39))
2299 second_arc = draw(integers(min_value=0))
2300 other_arcs = draw(lists(integers(min_value=0)))
2301 return tuple([first_arc, second_arc] + other_arcs)
2305 def oid_values_strategy(draw, do_expl=False):
2306 value = draw(one_of(none(), oid_strategy()))
2310 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2312 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2313 default = draw(one_of(none(), oid_strategy()))
2314 optional = draw(one_of(none(), booleans()))
2316 draw(integers(min_value=0)),
2317 draw(integers(min_value=0)),
2318 draw(integers(min_value=0)),
2320 return (value, impl, expl, default, optional, _decoded)
2323 class ObjectIdentifierInherited(ObjectIdentifier):
2327 class TestObjectIdentifier(CommonMixin, TestCase):
2328 base_klass = ObjectIdentifier
2330 def test_invalid_value_type(self):
2331 with self.assertRaises(InvalidValueType) as err:
2332 ObjectIdentifier(123)
2336 def test_optional(self, optional):
2337 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2338 self.assertTrue(obj.optional)
2340 @given(oid_strategy())
2341 def test_ready(self, value):
2342 obj = ObjectIdentifier()
2343 self.assertFalse(obj.ready)
2346 with self.assertRaises(ObjNotReady) as err:
2349 obj = ObjectIdentifier(value)
2350 self.assertTrue(obj.ready)
2355 @given(oid_strategy(), oid_strategy(), binary(), binary())
2356 def test_comparison(self, value1, value2, tag1, tag2):
2357 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2358 obj1 = klass(value1)
2359 obj2 = klass(value2)
2360 self.assertEqual(obj1 == obj2, value1 == value2)
2361 self.assertEqual(obj1 != obj2, value1 != value2)
2362 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2363 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2364 obj1 = klass(value1, impl=tag1)
2365 obj2 = klass(value1, impl=tag2)
2366 self.assertEqual(obj1 == obj2, tag1 == tag2)
2367 self.assertEqual(obj1 != obj2, tag1 != tag2)
2369 @given(lists(oid_strategy()))
2370 def test_sorted_works(self, values):
2371 self.assertSequenceEqual(
2372 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2376 @given(data_strategy())
2377 def test_call(self, d):
2378 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2386 ) = d.draw(oid_values_strategy())
2387 obj_initial = klass(
2388 value=value_initial,
2391 default=default_initial,
2392 optional=optional_initial or False,
2393 _decoded=_decoded_initial,
2402 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2411 value_expected = default if value is None else value
2413 default_initial if value_expected is None
2416 self.assertEqual(obj, value_expected)
2417 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2418 self.assertEqual(obj.expl_tag, expl or expl_initial)
2421 default_initial if default is None else default,
2423 if obj.default is None:
2424 optional = optional_initial if optional is None else optional
2425 optional = False if optional is None else optional
2428 self.assertEqual(obj.optional, optional)
2430 @given(oid_values_strategy())
2431 def test_copy(self, values):
2432 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2449 obj_copied = obj.copy()
2450 self.assert_copied_basic_fields(obj, obj_copied)
2451 self.assertEqual(obj._value, obj_copied._value)
2453 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2456 integers(min_value=1).map(tag_encode),
2458 def test_stripped(self, value, tag_impl):
2459 obj = ObjectIdentifier(value, impl=tag_impl)
2460 with self.assertRaises(NotEnoughData):
2461 obj.decode(obj.encode()[:-1])
2465 integers(min_value=1).map(tag_ctxc),
2467 def test_stripped_expl(self, value, tag_expl):
2468 obj = ObjectIdentifier(value, expl=tag_expl)
2469 with self.assertRaises(NotEnoughData):
2470 obj.decode(obj.encode()[:-1])
2473 integers(min_value=31),
2474 integers(min_value=0),
2477 def test_bad_tag(self, tag, offset, decode_path):
2478 with self.assertRaises(DecodeError) as err:
2479 ObjectIdentifier().decode(
2480 tag_encode(tag)[:-1],
2482 decode_path=decode_path,
2485 self.assertEqual(err.exception.offset, offset)
2486 self.assertEqual(err.exception.decode_path, decode_path)
2489 integers(min_value=128),
2490 integers(min_value=0),
2493 def test_bad_len(self, l, offset, decode_path):
2494 with self.assertRaises(DecodeError) as err:
2495 ObjectIdentifier().decode(
2496 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2498 decode_path=decode_path,
2501 self.assertEqual(err.exception.offset, offset)
2502 self.assertEqual(err.exception.decode_path, decode_path)
2504 def test_zero_oid(self):
2505 with self.assertRaises(NotEnoughData):
2506 ObjectIdentifier().decode(
2507 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2510 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2511 @given(oid_strategy())
2512 def test_unfinished_oid(self, value):
2513 assume(list(value)[-1] > 255)
2514 obj_encoded = ObjectIdentifier(value).encode()
2515 obj, _ = ObjectIdentifier().decode(obj_encoded)
2516 data = obj_encoded[obj.tlen + obj.llen:-1]
2518 ObjectIdentifier.tag_default,
2519 len_encode(len(data)),
2522 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2525 @given(integers(min_value=0))
2526 def test_invalid_short(self, value):
2527 with self.assertRaises(InvalidOID):
2528 ObjectIdentifier((value,))
2529 with self.assertRaises(InvalidOID):
2530 ObjectIdentifier("%d" % value)
2532 @given(integers(min_value=3), integers(min_value=0))
2533 def test_invalid_first_arc(self, first_arc, second_arc):
2534 with self.assertRaises(InvalidOID):
2535 ObjectIdentifier((first_arc, second_arc))
2536 with self.assertRaises(InvalidOID):
2537 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2539 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2540 def test_invalid_second_arc(self, first_arc, second_arc):
2541 with self.assertRaises(InvalidOID):
2542 ObjectIdentifier((first_arc, second_arc))
2543 with self.assertRaises(InvalidOID):
2544 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2546 @given(text(alphabet=ascii_letters + ".", min_size=1))
2547 def test_junk(self, oid):
2548 with self.assertRaises(InvalidOID):
2549 ObjectIdentifier(oid)
2551 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2552 @given(oid_strategy())
2553 def test_validness(self, oid):
2554 obj = ObjectIdentifier(oid)
2555 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2560 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2562 oid_values_strategy(),
2564 integers(min_value=1).map(tag_ctxc),
2565 integers(min_value=0),
2568 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2569 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2570 _, _, _, default, optional, _decoded = values
2579 self.assertFalse(obj.expled)
2580 obj_encoded = obj.encode()
2581 obj_expled = obj(value, expl=tag_expl)
2582 self.assertTrue(obj_expled.expled)
2585 obj_expled_encoded = obj_expled.encode()
2586 obj_decoded, tail = obj_expled.decode(
2587 obj_expled_encoded + tail_junk,
2592 self.assertEqual(tail, tail_junk)
2593 self.assertEqual(obj_decoded, obj_expled)
2594 self.assertNotEqual(obj_decoded, obj)
2595 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2596 self.assertEqual(tuple(obj_decoded), tuple(obj))
2597 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2598 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2599 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2601 obj_decoded.expl_llen,
2602 len(len_encode(len(obj_encoded))),
2604 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2605 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2608 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2610 self.assertEqual(obj_decoded.expl_offset, offset)
2613 oid_strategy().map(ObjectIdentifier),
2614 oid_strategy().map(ObjectIdentifier),
2616 def test_add(self, oid1, oid2):
2617 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2618 for oid_to_add in (oid2, tuple(oid2)):
2619 self.assertEqual(oid1 + oid_to_add, oid_expect)
2620 with self.assertRaises(InvalidValueType):
2623 def test_go_vectors_valid(self):
2624 for data, expect in (
2626 (b"\x55\x02", (2, 5, 2)),
2627 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2628 (b"\x81\x34\x03", (2, 100, 3)),
2631 ObjectIdentifier().decode(b"".join((
2632 ObjectIdentifier.tag_default,
2633 len_encode(len(data)),
2639 def test_go_vectors_invalid(self):
2640 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2641 with self.assertRaises(DecodeError):
2642 ObjectIdentifier().decode(b"".join((
2643 Integer.tag_default,
2644 len_encode(len(data)),
2648 def test_x690_vector(self):
2650 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2651 ObjectIdentifier((2, 999, 3)),
2656 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2658 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2659 values = list(draw(sets(
2661 min_size=len(schema),
2662 max_size=len(schema),
2664 schema = list(zip(schema, values))
2665 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2669 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2671 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2672 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2673 optional = draw(one_of(none(), booleans()))
2675 draw(integers(min_value=0)),
2676 draw(integers(min_value=0)),
2677 draw(integers(min_value=0)),
2679 return (schema, value, impl, expl, default, optional, _decoded)
2682 class TestEnumerated(CommonMixin, TestCase):
2683 class EWhatever(Enumerated):
2684 schema = (("whatever", 0),)
2686 base_klass = EWhatever
2688 def test_schema_required(self):
2689 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2692 def test_invalid_value_type(self):
2693 with self.assertRaises(InvalidValueType) as err:
2694 self.base_klass((1, 2))
2697 @given(sets(text_letters(), min_size=2))
2698 def test_unknown_name(self, schema_input):
2699 missing = schema_input.pop()
2701 class E(Enumerated):
2702 schema = [(n, 123) for n in schema_input]
2703 with self.assertRaises(ObjUnknown) as err:
2708 sets(text_letters(), min_size=2),
2709 sets(integers(), min_size=2),
2711 def test_unknown_value(self, schema_input, values_input):
2713 missing_value = values_input.pop()
2714 _input = list(zip(schema_input, values_input))
2716 class E(Enumerated):
2718 with self.assertRaises(DecodeError) as err:
2723 def test_optional(self, optional):
2724 obj = self.base_klass(default="whatever", optional=optional)
2725 self.assertTrue(obj.optional)
2727 def test_ready(self):
2728 obj = self.base_klass()
2729 self.assertFalse(obj.ready)
2732 with self.assertRaises(ObjNotReady) as err:
2735 obj = self.base_klass("whatever")
2736 self.assertTrue(obj.ready)
2740 @given(integers(), integers(), binary(), binary())
2741 def test_comparison(self, value1, value2, tag1, tag2):
2742 class E(Enumerated):
2744 ("whatever0", value1),
2745 ("whatever1", value2),
2748 class EInherited(E):
2750 for klass in (E, EInherited):
2751 obj1 = klass(value1)
2752 obj2 = klass(value2)
2753 self.assertEqual(obj1 == obj2, value1 == value2)
2754 self.assertEqual(obj1 != obj2, value1 != value2)
2755 self.assertEqual(obj1 == int(obj2), value1 == value2)
2756 obj1 = klass(value1, impl=tag1)
2757 obj2 = klass(value1, impl=tag2)
2758 self.assertEqual(obj1 == obj2, tag1 == tag2)
2759 self.assertEqual(obj1 != obj2, tag1 != tag2)
2761 @given(data_strategy())
2762 def test_call(self, d):
2771 ) = d.draw(enumerated_values_strategy())
2773 class E(Enumerated):
2774 schema = schema_initial
2776 value=value_initial,
2779 default=default_initial,
2780 optional=optional_initial or False,
2781 _decoded=_decoded_initial,
2791 ) = d.draw(enumerated_values_strategy(
2792 schema=schema_initial,
2793 do_expl=impl_initial is None,
2803 value_expected = default if value is None else value
2805 default_initial if value_expected is None
2810 dict(schema_initial).get(value_expected, value_expected),
2812 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2813 self.assertEqual(obj.expl_tag, expl or expl_initial)
2816 default_initial if default is None else default,
2818 if obj.default is None:
2819 optional = optional_initial if optional is None else optional
2820 optional = False if optional is None else optional
2823 self.assertEqual(obj.optional, optional)
2824 self.assertEqual(obj.specs, dict(schema_initial))
2826 @given(enumerated_values_strategy())
2827 def test_copy(self, values):
2828 schema_input, value, impl, expl, default, optional, _decoded = values
2830 class E(Enumerated):
2831 schema = schema_input
2840 obj_copied = obj.copy()
2841 self.assert_copied_basic_fields(obj, obj_copied)
2842 self.assertEqual(obj.specs, obj_copied.specs)
2844 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2845 @given(data_strategy())
2846 def test_symmetric(self, d):
2847 schema_input, _, _, _, default, optional, _decoded = d.draw(
2848 enumerated_values_strategy(),
2850 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2851 offset = d.draw(integers(min_value=0))
2852 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2853 tail_junk = d.draw(binary(max_size=5))
2855 class E(Enumerated):
2856 schema = schema_input
2865 self.assertFalse(obj.expled)
2866 obj_encoded = obj.encode()
2867 obj_expled = obj(value, expl=tag_expl)
2868 self.assertTrue(obj_expled.expled)
2871 obj_expled_encoded = obj_expled.encode()
2872 obj_decoded, tail = obj_expled.decode(
2873 obj_expled_encoded + tail_junk,
2878 self.assertEqual(tail, tail_junk)
2879 self.assertEqual(obj_decoded, obj_expled)
2880 self.assertNotEqual(obj_decoded, obj)
2881 self.assertEqual(int(obj_decoded), int(obj_expled))
2882 self.assertEqual(int(obj_decoded), int(obj))
2883 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2884 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2885 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2887 obj_decoded.expl_llen,
2888 len(len_encode(len(obj_encoded))),
2890 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2891 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2894 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2896 self.assertEqual(obj_decoded.expl_offset, offset)
2900 def string_values_strategy(draw, alphabet, do_expl=False):
2901 bound_min, bound_max = sorted(draw(sets(
2902 integers(min_value=0, max_value=1 << 7),
2906 value = draw(one_of(
2908 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2910 default = draw(one_of(
2912 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2915 if draw(booleans()):
2916 bounds = (bound_min, bound_max)
2920 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2922 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2923 optional = draw(one_of(none(), booleans()))
2925 draw(integers(min_value=0)),
2926 draw(integers(min_value=0)),
2927 draw(integers(min_value=0)),
2929 return (value, bounds, impl, expl, default, optional, _decoded)
2932 class StringMixin(object):
2933 def test_invalid_value_type(self):
2934 with self.assertRaises(InvalidValueType) as err:
2935 self.base_klass((1, 2))
2938 def text_alphabet(self):
2939 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2940 return printable + whitespace
2944 def test_optional(self, optional):
2945 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2946 self.assertTrue(obj.optional)
2948 @given(data_strategy())
2949 def test_ready(self, d):
2950 obj = self.base_klass()
2951 self.assertFalse(obj.ready)
2955 with self.assertRaises(ObjNotReady) as err:
2958 value = d.draw(text(alphabet=self.text_alphabet()))
2959 obj = self.base_klass(value)
2960 self.assertTrue(obj.ready)
2965 @given(data_strategy())
2966 def test_comparison(self, d):
2967 value1 = d.draw(text(alphabet=self.text_alphabet()))
2968 value2 = d.draw(text(alphabet=self.text_alphabet()))
2969 tag1 = d.draw(binary(min_size=1))
2970 tag2 = d.draw(binary(min_size=1))
2971 obj1 = self.base_klass(value1)
2972 obj2 = self.base_klass(value2)
2973 self.assertEqual(obj1 == obj2, value1 == value2)
2974 self.assertEqual(obj1 != obj2, value1 != value2)
2975 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2976 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2977 obj1 = self.base_klass(value1, impl=tag1)
2978 obj2 = self.base_klass(value1, impl=tag2)
2979 self.assertEqual(obj1 == obj2, tag1 == tag2)
2980 self.assertEqual(obj1 != obj2, tag1 != tag2)
2982 @given(data_strategy())
2983 def test_bounds_satisfied(self, d):
2984 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2985 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2986 value = d.draw(text(
2987 alphabet=self.text_alphabet(),
2991 self.base_klass(value=value, bounds=(bound_min, bound_max))
2993 @given(data_strategy())
2994 def test_bounds_unsatisfied(self, d):
2995 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2996 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2997 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2998 with self.assertRaises(BoundsError) as err:
2999 self.base_klass(value=value, bounds=(bound_min, bound_max))
3001 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3002 self.base_klass(bounds=(bound_min, bound_max)).decode(
3003 self.base_klass(value).encode()
3006 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3007 with self.assertRaises(BoundsError) as err:
3008 self.base_klass(value=value, bounds=(bound_min, bound_max))
3010 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3011 self.base_klass(bounds=(bound_min, bound_max)).decode(
3012 self.base_klass(value).encode()
3016 @given(data_strategy())
3017 def test_call(self, d):
3026 ) = d.draw(string_values_strategy(self.text_alphabet()))
3027 obj_initial = self.base_klass(
3033 optional_initial or False,
3044 ) = d.draw(string_values_strategy(
3045 self.text_alphabet(),
3046 do_expl=impl_initial is None,
3048 if (default is None) and (obj_initial.default is not None):
3051 (bounds is None) and
3052 (value is not None) and
3053 (bounds_initial is not None) and
3054 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3058 (bounds is None) and
3059 (default is not None) and
3060 (bounds_initial is not None) and
3061 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3064 obj = obj_initial(value, bounds, impl, expl, default, optional)
3066 value_expected = default if value is None else value
3068 default_initial if value_expected is None
3071 self.assertEqual(obj, value_expected)
3072 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3073 self.assertEqual(obj.expl_tag, expl or expl_initial)
3076 default_initial if default is None else default,
3078 if obj.default is None:
3079 optional = optional_initial if optional is None else optional
3080 optional = False if optional is None else optional
3083 self.assertEqual(obj.optional, optional)
3085 (obj._bound_min, obj._bound_max),
3086 bounds or bounds_initial or (0, float("+inf")),
3089 @given(data_strategy())
3090 def test_copy(self, d):
3091 values = d.draw(string_values_strategy(self.text_alphabet()))
3092 obj = self.base_klass(*values)
3093 obj_copied = obj.copy()
3094 self.assert_copied_basic_fields(obj, obj_copied)
3095 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3096 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3097 self.assertEqual(obj._value, obj_copied._value)
3099 @given(data_strategy())
3100 def test_stripped(self, d):
3101 value = d.draw(text(alphabet=self.text_alphabet()))
3102 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3103 obj = self.base_klass(value, impl=tag_impl)
3104 with self.assertRaises(NotEnoughData):
3105 obj.decode(obj.encode()[:-1])
3107 @given(data_strategy())
3108 def test_stripped_expl(self, d):
3109 value = d.draw(text(alphabet=self.text_alphabet()))
3110 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3111 obj = self.base_klass(value, expl=tag_expl)
3112 with self.assertRaises(NotEnoughData):
3113 obj.decode(obj.encode()[:-1])
3116 integers(min_value=31),
3117 integers(min_value=0),
3120 def test_bad_tag(self, tag, offset, decode_path):
3121 with self.assertRaises(DecodeError) as err:
3122 self.base_klass().decode(
3123 tag_encode(tag)[:-1],
3125 decode_path=decode_path,
3128 self.assertEqual(err.exception.offset, offset)
3129 self.assertEqual(err.exception.decode_path, decode_path)
3132 integers(min_value=128),
3133 integers(min_value=0),
3136 def test_bad_len(self, l, offset, decode_path):
3137 with self.assertRaises(DecodeError) as err:
3138 self.base_klass().decode(
3139 self.base_klass.tag_default + len_encode(l)[:-1],
3141 decode_path=decode_path,
3144 self.assertEqual(err.exception.offset, offset)
3145 self.assertEqual(err.exception.decode_path, decode_path)
3148 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3149 integers(min_value=0),
3152 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3153 value, bound_min = list(sorted(ints))
3155 class String(self.base_klass):
3156 # Multiply this value by four, to satisfy UTF-32 bounds
3157 # (4 bytes per character) validation
3158 bounds = (bound_min * 4, bound_min * 4)
3159 with self.assertRaises(DecodeError) as err:
3161 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3163 decode_path=decode_path,
3166 self.assertEqual(err.exception.offset, offset)
3167 self.assertEqual(err.exception.decode_path, decode_path)
3169 @given(data_strategy())
3170 def test_symmetric(self, d):
3171 values = d.draw(string_values_strategy(self.text_alphabet()))
3172 value = d.draw(text(alphabet=self.text_alphabet()))
3173 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3174 offset = d.draw(integers(min_value=0))
3175 tail_junk = d.draw(binary(max_size=5))
3176 _, _, _, _, default, optional, _decoded = values
3177 obj = self.base_klass(
3185 self.assertFalse(obj.expled)
3186 obj_encoded = obj.encode()
3187 obj_expled = obj(value, expl=tag_expl)
3188 self.assertTrue(obj_expled.expled)
3191 obj_expled_encoded = obj_expled.encode()
3192 obj_decoded, tail = obj_expled.decode(
3193 obj_expled_encoded + tail_junk,
3198 self.assertEqual(tail, tail_junk)
3199 self.assertEqual(obj_decoded, obj_expled)
3200 self.assertNotEqual(obj_decoded, obj)
3201 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3202 self.assertEqual(bytes(obj_decoded), bytes(obj))
3203 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3204 self.assertEqual(text_type(obj_decoded), text_type(obj))
3205 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3206 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3207 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3209 obj_decoded.expl_llen,
3210 len(len_encode(len(obj_encoded))),
3212 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3213 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3216 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3218 self.assertEqual(obj_decoded.expl_offset, offset)
3221 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3222 base_klass = UTF8String
3225 class UnicodeDecodeErrorMixin(object):
3227 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3231 def test_unicode_decode_error(self, cyrillic_text):
3232 with self.assertRaises(DecodeError):
3233 self.base_klass(cyrillic_text)
3236 class TestNumericString(StringMixin, CommonMixin, TestCase):
3237 base_klass = NumericString
3239 def text_alphabet(self):
3242 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3243 def test_non_numeric(self, cyrillic_text):
3244 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3245 self.base_klass(cyrillic_text)
3248 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3249 integers(min_value=0),
3252 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3253 value, bound_min = list(sorted(ints))
3255 class String(self.base_klass):
3256 bounds = (bound_min, bound_min)
3257 with self.assertRaises(DecodeError) as err:
3259 self.base_klass(b"1" * value).encode(),
3261 decode_path=decode_path,
3264 self.assertEqual(err.exception.offset, offset)
3265 self.assertEqual(err.exception.decode_path, decode_path)
3268 class TestPrintableString(
3269 UnicodeDecodeErrorMixin,
3274 base_klass = PrintableString
3277 class TestTeletexString(
3278 UnicodeDecodeErrorMixin,
3283 base_klass = TeletexString
3286 class TestVideotexString(
3287 UnicodeDecodeErrorMixin,
3292 base_klass = VideotexString
3295 class TestIA5String(
3296 UnicodeDecodeErrorMixin,
3301 base_klass = IA5String
3304 class TestGraphicString(
3305 UnicodeDecodeErrorMixin,
3310 base_klass = GraphicString
3313 class TestVisibleString(
3314 UnicodeDecodeErrorMixin,
3319 base_klass = VisibleString
3321 def test_x690_vector(self):
3322 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3323 self.assertSequenceEqual(tail, b"")
3324 self.assertEqual(str(obj), "Jones")
3325 self.assertFalse(obj.bered)
3326 self.assertFalse(obj.lenindef)
3328 obj, tail = VisibleString().decode(
3329 hexdec("3A0904034A6F6E04026573"),
3330 ctx={"bered": True},
3332 self.assertSequenceEqual(tail, b"")
3333 self.assertEqual(str(obj), "Jones")
3334 self.assertTrue(obj.bered)
3335 self.assertFalse(obj.lenindef)
3337 obj, tail = VisibleString().decode(
3338 hexdec("3A8004034A6F6E040265730000"),
3339 ctx={"bered": True},
3341 self.assertSequenceEqual(tail, b"")
3342 self.assertEqual(str(obj), "Jones")
3343 self.assertTrue(obj.bered)
3344 self.assertTrue(obj.lenindef)
3347 class TestGeneralString(
3348 UnicodeDecodeErrorMixin,
3353 base_klass = GeneralString
3356 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3357 base_klass = UniversalString
3360 class TestBMPString(StringMixin, CommonMixin, TestCase):
3361 base_klass = BMPString
3365 def generalized_time_values_strategy(
3373 if draw(booleans()):
3374 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3376 value = value.replace(microsecond=0)
3378 if draw(booleans()):
3379 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3381 default = default.replace(microsecond=0)
3385 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3387 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3388 optional = draw(one_of(none(), booleans()))
3390 draw(integers(min_value=0)),
3391 draw(integers(min_value=0)),
3392 draw(integers(min_value=0)),
3394 return (value, impl, expl, default, optional, _decoded)
3397 class TimeMixin(object):
3398 def test_invalid_value_type(self):
3399 with self.assertRaises(InvalidValueType) as err:
3400 self.base_klass(datetime.now().timetuple())
3403 @given(data_strategy())
3404 def test_optional(self, d):
3405 default = d.draw(datetimes(
3406 min_value=self.min_datetime,
3407 max_value=self.max_datetime,
3409 optional = d.draw(booleans())
3410 obj = self.base_klass(default=default, optional=optional)
3411 self.assertTrue(obj.optional)
3413 @given(data_strategy())
3414 def test_ready(self, d):
3415 obj = self.base_klass()
3416 self.assertFalse(obj.ready)
3419 with self.assertRaises(ObjNotReady) as err:
3422 value = d.draw(datetimes(min_value=self.min_datetime))
3423 obj = self.base_klass(value)
3424 self.assertTrue(obj.ready)
3428 @given(data_strategy())
3429 def test_comparison(self, d):
3430 value1 = d.draw(datetimes(
3431 min_value=self.min_datetime,
3432 max_value=self.max_datetime,
3434 value2 = d.draw(datetimes(
3435 min_value=self.min_datetime,
3436 max_value=self.max_datetime,
3438 tag1 = d.draw(binary(min_size=1))
3439 tag2 = d.draw(binary(min_size=1))
3441 value1 = value1.replace(microsecond=0)
3442 value2 = value2.replace(microsecond=0)
3443 obj1 = self.base_klass(value1)
3444 obj2 = self.base_klass(value2)
3445 self.assertEqual(obj1 == obj2, value1 == value2)
3446 self.assertEqual(obj1 != obj2, value1 != value2)
3447 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3448 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3449 obj1 = self.base_klass(value1, impl=tag1)
3450 obj2 = self.base_klass(value1, impl=tag2)
3451 self.assertEqual(obj1 == obj2, tag1 == tag2)
3452 self.assertEqual(obj1 != obj2, tag1 != tag2)
3454 @given(data_strategy())
3455 def test_call(self, d):
3463 ) = d.draw(generalized_time_values_strategy(
3464 min_datetime=self.min_datetime,
3465 max_datetime=self.max_datetime,
3466 omit_ms=self.omit_ms,
3468 obj_initial = self.base_klass(
3469 value=value_initial,
3472 default=default_initial,
3473 optional=optional_initial or False,
3474 _decoded=_decoded_initial,
3483 ) = d.draw(generalized_time_values_strategy(
3484 min_datetime=self.min_datetime,
3485 max_datetime=self.max_datetime,
3486 omit_ms=self.omit_ms,
3487 do_expl=impl_initial is None,
3497 value_expected = default if value is None else value
3499 default_initial if value_expected is None
3502 self.assertEqual(obj, value_expected)
3503 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3504 self.assertEqual(obj.expl_tag, expl or expl_initial)
3507 default_initial if default is None else default,
3509 if obj.default is None:
3510 optional = optional_initial if optional is None else optional
3511 optional = False if optional is None else optional
3514 self.assertEqual(obj.optional, optional)
3516 @given(data_strategy())
3517 def test_copy(self, d):
3518 values = d.draw(generalized_time_values_strategy(
3519 min_datetime=self.min_datetime,
3520 max_datetime=self.max_datetime,
3522 obj = self.base_klass(*values)
3523 obj_copied = obj.copy()
3524 self.assert_copied_basic_fields(obj, obj_copied)
3525 self.assertEqual(obj._value, obj_copied._value)
3527 @given(data_strategy())
3528 def test_stripped(self, d):
3529 value = d.draw(datetimes(
3530 min_value=self.min_datetime,
3531 max_value=self.max_datetime,
3533 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3534 obj = self.base_klass(value, impl=tag_impl)
3535 with self.assertRaises(NotEnoughData):
3536 obj.decode(obj.encode()[:-1])
3538 @given(data_strategy())
3539 def test_stripped_expl(self, d):
3540 value = d.draw(datetimes(
3541 min_value=self.min_datetime,
3542 max_value=self.max_datetime,
3544 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3545 obj = self.base_klass(value, expl=tag_expl)
3546 with self.assertRaises(NotEnoughData):
3547 obj.decode(obj.encode()[:-1])
3549 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3550 @given(data_strategy())
3551 def test_symmetric(self, d):
3552 values = d.draw(generalized_time_values_strategy(
3553 min_datetime=self.min_datetime,
3554 max_datetime=self.max_datetime,
3556 value = d.draw(datetimes(
3557 min_value=self.min_datetime,
3558 max_value=self.max_datetime,
3560 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3561 offset = d.draw(integers(min_value=0))
3562 tail_junk = d.draw(binary(max_size=5))
3563 _, _, _, default, optional, _decoded = values
3564 obj = self.base_klass(
3572 self.assertFalse(obj.expled)
3573 obj_encoded = obj.encode()
3574 obj_expled = obj(value, expl=tag_expl)
3575 self.assertTrue(obj_expled.expled)
3578 obj_expled_encoded = obj_expled.encode()
3579 obj_decoded, tail = obj_expled.decode(
3580 obj_expled_encoded + tail_junk,
3585 self.assertEqual(tail, tail_junk)
3586 self.assertEqual(obj_decoded, obj_expled)
3587 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3588 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3589 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3590 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3591 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3593 obj_decoded.expl_llen,
3594 len(len_encode(len(obj_encoded))),
3596 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3597 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3600 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3602 self.assertEqual(obj_decoded.expl_offset, offset)
3605 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3606 base_klass = GeneralizedTime
3608 min_datetime = datetime(1900, 1, 1)
3609 max_datetime = datetime(9999, 12, 31)
3611 def test_go_vectors_invalid(self):
3623 b"-20100102030410Z",
3624 b"2010-0102030410Z",
3625 b"2010-0002030410Z",
3626 b"201001-02030410Z",
3627 b"20100102-030410Z",
3628 b"2010010203-0410Z",
3629 b"201001020304-10Z",
3630 # These ones are INVALID in *DER*, but accepted
3631 # by Go's encoding/asn1
3632 b"20100102030405+0607",
3633 b"20100102030405-0607",
3635 with self.assertRaises(DecodeError) as err:
3636 GeneralizedTime(data)
3639 def test_go_vectors_valid(self):
3641 GeneralizedTime(b"20100102030405Z").todatetime(),
3642 datetime(2010, 1, 2, 3, 4, 5, 0),
3647 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3648 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3650 binary(min_size=1, max_size=1),
3652 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3653 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3656 def test_junk(self, part0, part1, part2):
3657 junk = part0 + part1 + part2
3658 assume(not (set(junk) <= set(digits.encode("ascii"))))
3659 with self.assertRaises(DecodeError):
3660 GeneralizedTime().decode(
3661 GeneralizedTime.tag_default +
3662 len_encode(len(junk)) +
3668 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3669 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3671 binary(min_size=1, max_size=1),
3673 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3674 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3677 def test_junk_dm(self, part0, part1, part2):
3678 junk = part0 + part1 + part2
3679 assume(not (set(junk) <= set(digits.encode("ascii"))))
3680 with self.assertRaises(DecodeError):
3681 GeneralizedTime().decode(
3682 GeneralizedTime.tag_default +
3683 len_encode(len(junk)) +
3688 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3689 base_klass = UTCTime
3691 min_datetime = datetime(2000, 1, 1)
3692 max_datetime = datetime(2049, 12, 31)
3694 def test_go_vectors_invalid(self):
3720 # These ones are INVALID in *DER*, but accepted
3721 # by Go's encoding/asn1
3722 b"910506164540-0700",
3723 b"910506164540+0730",
3727 with self.assertRaises(DecodeError) as err:
3731 def test_go_vectors_valid(self):
3733 UTCTime(b"910506234540Z").todatetime(),
3734 datetime(1991, 5, 6, 23, 45, 40, 0),
3737 @given(integers(min_value=0, max_value=49))
3738 def test_pre50(self, year):
3740 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3744 @given(integers(min_value=50, max_value=99))
3745 def test_post50(self, year):
3747 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3753 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3754 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3756 binary(min_size=1, max_size=1),
3758 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3759 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3762 def test_junk(self, part0, part1, part2):
3763 junk = part0 + part1 + part2
3764 assume(not (set(junk) <= set(digits.encode("ascii"))))
3765 with self.assertRaises(DecodeError):
3767 UTCTime.tag_default +
3768 len_encode(len(junk)) +
3774 def any_values_strategy(draw, do_expl=False):
3775 value = draw(one_of(none(), binary()))
3778 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3779 optional = draw(one_of(none(), booleans()))
3781 draw(integers(min_value=0)),
3782 draw(integers(min_value=0)),
3783 draw(integers(min_value=0)),
3785 return (value, expl, optional, _decoded)
3788 class AnyInherited(Any):
3792 class TestAny(CommonMixin, TestCase):
3795 def test_invalid_value_type(self):
3796 with self.assertRaises(InvalidValueType) as err:
3801 def test_optional(self, optional):
3802 obj = Any(optional=optional)
3803 self.assertEqual(obj.optional, optional)
3806 def test_ready(self, value):
3808 self.assertFalse(obj.ready)
3811 with self.assertRaises(ObjNotReady) as err:
3815 self.assertTrue(obj.ready)
3820 def test_basic(self, value):
3821 integer_encoded = Integer(value).encode()
3823 Any(integer_encoded),
3824 Any(Integer(value)),
3825 Any(Any(Integer(value))),
3827 self.assertSequenceEqual(bytes(obj), integer_encoded)
3829 obj.decode(obj.encode())[0].vlen,
3830 len(integer_encoded),
3834 self.assertSequenceEqual(obj.encode(), integer_encoded)
3836 @given(binary(), binary())
3837 def test_comparison(self, value1, value2):
3838 for klass in (Any, AnyInherited):
3839 obj1 = klass(value1)
3840 obj2 = klass(value2)
3841 self.assertEqual(obj1 == obj2, value1 == value2)
3842 self.assertEqual(obj1 != obj2, value1 != value2)
3843 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3845 @given(data_strategy())
3846 def test_call(self, d):
3847 for klass in (Any, AnyInherited):
3853 ) = d.draw(any_values_strategy())
3854 obj_initial = klass(
3857 optional_initial or False,
3865 ) = d.draw(any_values_strategy(do_expl=True))
3866 obj = obj_initial(value, expl, optional)
3868 value_expected = None if value is None else value
3869 self.assertEqual(obj, value_expected)
3870 self.assertEqual(obj.expl_tag, expl or expl_initial)
3871 if obj.default is None:
3872 optional = optional_initial if optional is None else optional
3873 optional = False if optional is None else optional
3874 self.assertEqual(obj.optional, optional)
3876 def test_simultaneous_impl_expl(self):
3877 # override it, as Any does not have implicit tag
3880 def test_decoded(self):
3881 # override it, as Any does not have implicit tag
3884 @given(any_values_strategy())
3885 def test_copy(self, values):
3886 for klass in (Any, AnyInherited):
3887 obj = klass(*values)
3888 obj_copied = obj.copy()
3889 self.assert_copied_basic_fields(obj, obj_copied)
3890 self.assertEqual(obj._value, obj_copied._value)
3892 @given(binary().map(OctetString))
3893 def test_stripped(self, value):
3895 with self.assertRaises(NotEnoughData):
3896 obj.decode(obj.encode()[:-1])
3900 integers(min_value=1).map(tag_ctxc),
3902 def test_stripped_expl(self, value, tag_expl):
3903 obj = Any(value, expl=tag_expl)
3904 with self.assertRaises(NotEnoughData):
3905 obj.decode(obj.encode()[:-1])
3908 integers(min_value=31),
3909 integers(min_value=0),
3912 def test_bad_tag(self, tag, offset, decode_path):
3913 with self.assertRaises(DecodeError) as err:
3915 tag_encode(tag)[:-1],
3917 decode_path=decode_path,
3920 self.assertEqual(err.exception.offset, offset)
3921 self.assertEqual(err.exception.decode_path, decode_path)
3924 integers(min_value=128),
3925 integers(min_value=0),
3928 def test_bad_len(self, l, offset, decode_path):
3929 with self.assertRaises(DecodeError) as err:
3931 Any.tag_default + len_encode(l)[:-1],
3933 decode_path=decode_path,
3936 self.assertEqual(err.exception.offset, offset)
3937 self.assertEqual(err.exception.decode_path, decode_path)
3939 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3941 any_values_strategy(),
3942 integers().map(lambda x: Integer(x).encode()),
3943 integers(min_value=1).map(tag_ctxc),
3944 integers(min_value=0),
3947 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3948 for klass in (Any, AnyInherited):
3949 _, _, optional, _decoded = values
3950 obj = klass(value=value, optional=optional, _decoded=_decoded)
3953 self.assertFalse(obj.expled)
3954 obj_encoded = obj.encode()
3955 obj_expled = obj(value, expl=tag_expl)
3956 self.assertTrue(obj_expled.expled)
3959 obj_expled_encoded = obj_expled.encode()
3960 obj_decoded, tail = obj_expled.decode(
3961 obj_expled_encoded + tail_junk,
3966 self.assertEqual(tail, tail_junk)
3967 self.assertEqual(obj_decoded, obj_expled)
3968 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3969 self.assertEqual(bytes(obj_decoded), bytes(obj))
3970 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3971 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3972 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3974 obj_decoded.expl_llen,
3975 len(len_encode(len(obj_encoded))),
3977 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3978 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3981 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3983 self.assertEqual(obj_decoded.expl_offset, offset)
3984 self.assertEqual(obj_decoded.tlen, 0)
3985 self.assertEqual(obj_decoded.llen, 0)
3986 self.assertEqual(obj_decoded.vlen, len(value))
3989 integers(min_value=1).map(tag_ctxc),
3990 integers(min_value=0, max_value=3),
3991 integers(min_value=0),
3995 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
3996 chunk = Boolean(False, expl=expl).encode()
3998 OctetString.tag_default +
4000 b"".join([chunk] * chunks) +
4003 obj, tail = Any().decode(
4006 decode_path=decode_path,
4007 ctx={"bered": True},
4009 self.assertSequenceEqual(tail, junk)
4010 self.assertEqual(obj.offset, offset)
4011 self.assertEqual(obj.tlvlen, len(encoded))
4012 with self.assertRaises(NotEnoughData) as err:
4016 decode_path=decode_path,
4017 ctx={"bered": True},
4019 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4020 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4024 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4026 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4027 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4029 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4030 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4032 min_size=len(names),
4033 max_size=len(names),
4036 (name, Integer(**tag_kwargs))
4037 for name, tag_kwargs in zip(names, tags)
4040 if value_required or draw(booleans()):
4041 value = draw(tuples(
4042 sampled_from([name for name, _ in schema]),
4043 integers().map(Integer),
4047 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4048 default = draw(one_of(
4050 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4052 optional = draw(one_of(none(), booleans()))
4054 draw(integers(min_value=0)),
4055 draw(integers(min_value=0)),
4056 draw(integers(min_value=0)),
4058 return (schema, value, expl, default, optional, _decoded)
4061 class ChoiceInherited(Choice):
4065 class TestChoice(CommonMixin, TestCase):
4067 schema = (("whatever", Boolean()),)
4070 def test_schema_required(self):
4071 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4074 def test_impl_forbidden(self):
4075 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4076 Choice(impl=b"whatever")
4078 def test_invalid_value_type(self):
4079 with self.assertRaises(InvalidValueType) as err:
4080 self.base_klass(123)
4082 with self.assertRaises(ObjUnknown) as err:
4083 self.base_klass(("whenever", Boolean(False)))
4085 with self.assertRaises(InvalidValueType) as err:
4086 self.base_klass(("whatever", Integer(123)))
4090 def test_optional(self, optional):
4091 obj = self.base_klass(
4092 default=self.base_klass(("whatever", Boolean(False))),
4095 self.assertTrue(obj.optional)
4098 def test_ready(self, value):
4099 obj = self.base_klass()
4100 self.assertFalse(obj.ready)
4103 self.assertIsNone(obj["whatever"])
4104 with self.assertRaises(ObjNotReady) as err:
4107 obj["whatever"] = Boolean()
4108 self.assertFalse(obj.ready)
4111 obj["whatever"] = Boolean(value)
4112 self.assertTrue(obj.ready)
4116 @given(booleans(), booleans())
4117 def test_comparison(self, value1, value2):
4118 class WahlInherited(self.base_klass):
4120 for klass in (self.base_klass, WahlInherited):
4121 obj1 = klass(("whatever", Boolean(value1)))
4122 obj2 = klass(("whatever", Boolean(value2)))
4123 self.assertEqual(obj1 == obj2, value1 == value2)
4124 self.assertEqual(obj1 != obj2, value1 != value2)
4125 self.assertEqual(obj1 == obj2._value, value1 == value2)
4126 self.assertFalse(obj1 == obj2._value[1])
4128 @given(data_strategy())
4129 def test_call(self, d):
4130 for klass in (Choice, ChoiceInherited):
4138 ) = d.draw(choice_values_strategy())
4141 schema = schema_initial
4143 value=value_initial,
4145 default=default_initial,
4146 optional=optional_initial or False,
4147 _decoded=_decoded_initial,
4156 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4157 obj = obj_initial(value, expl, default, optional)
4159 value_expected = default if value is None else value
4161 default_initial if value_expected is None
4164 self.assertEqual(obj.choice, value_expected[0])
4165 self.assertEqual(obj.value, int(value_expected[1]))
4166 self.assertEqual(obj.expl_tag, expl or expl_initial)
4167 default_expect = default_initial if default is None else default
4168 if default_expect is not None:
4169 self.assertEqual(obj.default.choice, default_expect[0])
4170 self.assertEqual(obj.default.value, int(default_expect[1]))
4171 if obj.default is None:
4172 optional = optional_initial if optional is None else optional
4173 optional = False if optional is None else optional
4176 self.assertEqual(obj.optional, optional)
4177 self.assertEqual(obj.specs, obj_initial.specs)
4179 def test_simultaneous_impl_expl(self):
4180 # override it, as Any does not have implicit tag
4183 def test_decoded(self):
4184 # override it, as Any does not have implicit tag
4187 @given(choice_values_strategy())
4188 def test_copy(self, values):
4189 _schema, value, expl, default, optional, _decoded = values
4191 class Wahl(self.base_klass):
4197 optional=optional or False,
4200 obj_copied = obj.copy()
4201 self.assertIsNone(obj.tag)
4202 self.assertIsNone(obj_copied.tag)
4203 # hack for assert_copied_basic_fields
4204 obj.tag = "whatever"
4205 obj_copied.tag = "whatever"
4206 self.assert_copied_basic_fields(obj, obj_copied)
4207 self.assertEqual(obj._value, obj_copied._value)
4208 self.assertEqual(obj.specs, obj_copied.specs)
4211 def test_stripped(self, value):
4212 obj = self.base_klass(("whatever", Boolean(value)))
4213 with self.assertRaises(NotEnoughData):
4214 obj.decode(obj.encode()[:-1])
4218 integers(min_value=1).map(tag_ctxc),
4220 def test_stripped_expl(self, value, tag_expl):
4221 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4222 with self.assertRaises(NotEnoughData):
4223 obj.decode(obj.encode()[:-1])
4225 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4226 @given(data_strategy())
4227 def test_symmetric(self, d):
4228 _schema, value, _, default, optional, _decoded = d.draw(
4229 choice_values_strategy(value_required=True)
4231 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4232 offset = d.draw(integers(min_value=0))
4233 tail_junk = d.draw(binary(max_size=5))
4235 class Wahl(self.base_klass):
4245 self.assertFalse(obj.expled)
4246 obj_encoded = obj.encode()
4247 obj_expled = obj(value, expl=tag_expl)
4248 self.assertTrue(obj_expled.expled)
4251 obj_expled_encoded = obj_expled.encode()
4252 obj_decoded, tail = obj_expled.decode(
4253 obj_expled_encoded + tail_junk,
4258 self.assertEqual(tail, tail_junk)
4259 self.assertEqual(obj_decoded, obj_expled)
4260 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4261 self.assertEqual(obj_decoded.value, obj_expled.value)
4262 self.assertEqual(obj_decoded.choice, obj.choice)
4263 self.assertEqual(obj_decoded.value, obj.value)
4264 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4265 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4266 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4268 obj_decoded.expl_llen,
4269 len(len_encode(len(obj_encoded))),
4271 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4272 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4275 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4277 self.assertEqual(obj_decoded.expl_offset, offset)
4278 self.assertSequenceEqual(
4280 obj_decoded.value.fulloffset - offset:
4281 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4287 def test_set_get(self, value):
4290 ("erste", Boolean()),
4291 ("zweite", Integer()),
4294 with self.assertRaises(ObjUnknown) as err:
4295 obj["whatever"] = "whenever"
4296 with self.assertRaises(InvalidValueType) as err:
4297 obj["zweite"] = Boolean(False)
4298 obj["zweite"] = Integer(value)
4300 with self.assertRaises(ObjUnknown) as err:
4303 self.assertIsNone(obj["erste"])
4304 self.assertEqual(obj["zweite"], Integer(value))
4306 def test_tag_mismatch(self):
4309 ("erste", Boolean()),
4311 int_encoded = Integer(123).encode()
4312 bool_encoded = Boolean(False).encode()
4314 obj.decode(bool_encoded)
4315 with self.assertRaises(TagMismatch):
4316 obj.decode(int_encoded)
4318 def test_tag_mismatch_underlying(self):
4319 class SeqOfBoolean(SequenceOf):
4322 class SeqOfInteger(SequenceOf):
4327 ("erste", SeqOfBoolean()),
4330 int_encoded = SeqOfInteger((Integer(123),)).encode()
4331 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4333 obj.decode(bool_encoded)
4334 with self.assertRaises(TagMismatch) as err:
4335 obj.decode(int_encoded)
4336 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4340 def seq_values_strategy(draw, seq_klass, do_expl=False):
4342 if draw(booleans()):
4345 k: v for k, v in draw(dictionaries(
4348 booleans().map(Boolean),
4349 integers().map(Integer),
4354 if draw(booleans()):
4355 schema = list(draw(dictionaries(
4358 booleans().map(Boolean),
4359 integers().map(Integer),
4365 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4367 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4369 if draw(booleans()):
4370 default = seq_klass()
4372 k: v for k, v in draw(dictionaries(
4375 booleans().map(Boolean),
4376 integers().map(Integer),
4380 optional = draw(one_of(none(), booleans()))
4382 draw(integers(min_value=0)),
4383 draw(integers(min_value=0)),
4384 draw(integers(min_value=0)),
4386 return (value, schema, impl, expl, default, optional, _decoded)
4390 def sequence_strategy(draw, seq_klass):
4391 inputs = draw(lists(
4393 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4394 tuples(just(Integer), integers(), one_of(none(), integers())),
4399 integers(min_value=1),
4400 min_size=len(inputs),
4401 max_size=len(inputs),
4404 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4405 for tag, expled in zip(tags, draw(lists(
4407 min_size=len(inputs),
4408 max_size=len(inputs),
4412 for i, optional in enumerate(draw(lists(
4413 sampled_from(("required", "optional", "empty")),
4414 min_size=len(inputs),
4415 max_size=len(inputs),
4417 if optional in ("optional", "empty"):
4418 inits[i]["optional"] = True
4419 if optional == "empty":
4421 empties = set(empties)
4422 names = list(draw(sets(
4424 min_size=len(inputs),
4425 max_size=len(inputs),
4428 for i, (klass, value, default) in enumerate(inputs):
4429 schema.append((names[i], klass(default=default, **inits[i])))
4430 seq_name = draw(text_letters())
4431 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4434 for i, (klass, value, default) in enumerate(inputs):
4441 "default_value": None if spec.default is None else default,
4445 expect["optional"] = True
4447 expect["presented"] = True
4448 expect["value"] = value
4450 expect["optional"] = True
4451 if default is not None and default == value:
4452 expect["presented"] = False
4453 seq[name] = klass(value)
4454 expects.append(expect)
4459 def sequences_strategy(draw, seq_klass):
4460 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4462 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4463 for tag, expled in zip(tags, draw(lists(
4470 i for i, is_default in enumerate(draw(lists(
4476 names = list(draw(sets(
4481 seq_expectses = draw(lists(
4482 sequence_strategy(seq_klass=seq_klass),
4486 seqs = [seq for seq, _ in seq_expectses]
4488 for i, (name, seq) in enumerate(zip(names, seqs)):
4491 seq(default=(seq if i in defaulted else None), **inits[i]),
4493 seq_name = draw(text_letters())
4494 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4497 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4500 "expects": expects_inner,
4503 seq_outer[name] = seq_inner
4504 if seq_outer.specs[name].default is None:
4505 expect["presented"] = True
4506 expect_outers.append(expect)
4507 return seq_outer, expect_outers
4510 class SeqMixing(object):
4511 def test_invalid_value_type(self):
4512 with self.assertRaises(InvalidValueType) as err:
4513 self.base_klass(123)
4516 def test_invalid_value_type_set(self):
4517 class Seq(self.base_klass):
4518 schema = (("whatever", Boolean()),)
4520 with self.assertRaises(InvalidValueType) as err:
4521 seq["whatever"] = Integer(123)
4525 def test_optional(self, optional):
4526 obj = self.base_klass(default=self.base_klass(), optional=optional)
4527 self.assertTrue(obj.optional)
4529 @given(data_strategy())
4530 def test_ready(self, d):
4532 str(i): v for i, v in enumerate(d.draw(lists(
4539 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4546 for name in d.draw(permutations(
4547 list(ready.keys()) + list(non_ready.keys()),
4549 schema_input.append((name, Boolean()))
4551 class Seq(self.base_klass):
4552 schema = tuple(schema_input)
4554 for name in ready.keys():
4556 seq[name] = Boolean()
4557 self.assertFalse(seq.ready)
4560 for name, value in ready.items():
4561 seq[name] = Boolean(value)
4562 self.assertFalse(seq.ready)
4565 with self.assertRaises(ObjNotReady) as err:
4568 for name, value in non_ready.items():
4569 seq[name] = Boolean(value)
4570 self.assertTrue(seq.ready)
4574 @given(data_strategy())
4575 def test_call(self, d):
4576 class SeqInherited(self.base_klass):
4578 for klass in (self.base_klass, SeqInherited):
4587 ) = d.draw(seq_values_strategy(seq_klass=klass))
4588 obj_initial = klass(
4594 optional_initial or False,
4605 ) = d.draw(seq_values_strategy(
4607 do_expl=impl_initial is None,
4609 obj = obj_initial(value, impl, expl, default, optional)
4610 value_expected = default if value is None else value
4612 default_initial if value_expected is None
4615 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4616 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4617 self.assertEqual(obj.expl_tag, expl or expl_initial)
4619 {} if obj.default is None else obj.default._value,
4620 getattr(default_initial if default is None else default, "_value", {}),
4622 if obj.default is None:
4623 optional = optional_initial if optional is None else optional
4624 optional = False if optional is None else optional
4627 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4628 self.assertEqual(obj.optional, optional)
4630 @given(data_strategy())
4631 def test_copy(self, d):
4632 class SeqInherited(self.base_klass):
4634 for klass in (self.base_klass, SeqInherited):
4635 values = d.draw(seq_values_strategy(seq_klass=klass))
4636 obj = klass(*values)
4637 obj_copied = obj.copy()
4638 self.assert_copied_basic_fields(obj, obj_copied)
4639 self.assertEqual(obj.specs, obj_copied.specs)
4640 self.assertEqual(obj._value, obj_copied._value)
4642 @given(data_strategy())
4643 def test_stripped(self, d):
4644 value = d.draw(integers())
4645 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4647 class Seq(self.base_klass):
4649 schema = (("whatever", Integer()),)
4651 seq["whatever"] = Integer(value)
4652 with self.assertRaises(NotEnoughData):
4653 seq.decode(seq.encode()[:-1])
4655 @given(data_strategy())
4656 def test_stripped_expl(self, d):
4657 value = d.draw(integers())
4658 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4660 class Seq(self.base_klass):
4662 schema = (("whatever", Integer()),)
4664 seq["whatever"] = Integer(value)
4665 with self.assertRaises(NotEnoughData):
4666 seq.decode(seq.encode()[:-1])
4668 @given(binary(min_size=2))
4669 def test_non_tag_mismatch_raised(self, junk):
4671 _, _, len_encoded = tag_strip(memoryview(junk))
4672 len_decode(len_encoded)
4678 class Seq(self.base_klass):
4680 ("whatever", Integer()),
4682 ("whenever", Integer()),
4685 seq["whatever"] = Integer(123)
4686 seq["junk"] = Any(junk)
4687 seq["whenever"] = Integer(123)
4688 with self.assertRaises(DecodeError):
4689 seq.decode(seq.encode())
4692 integers(min_value=31),
4693 integers(min_value=0),
4696 def test_bad_tag(self, tag, offset, decode_path):
4697 with self.assertRaises(DecodeError) as err:
4698 self.base_klass().decode(
4699 tag_encode(tag)[:-1],
4701 decode_path=decode_path,
4704 self.assertEqual(err.exception.offset, offset)
4705 self.assertEqual(err.exception.decode_path, decode_path)
4708 integers(min_value=128),
4709 integers(min_value=0),
4712 def test_bad_len(self, l, offset, decode_path):
4713 with self.assertRaises(DecodeError) as err:
4714 self.base_klass().decode(
4715 self.base_klass.tag_default + len_encode(l)[:-1],
4717 decode_path=decode_path,
4720 self.assertEqual(err.exception.offset, offset)
4721 self.assertEqual(err.exception.decode_path, decode_path)
4723 def _assert_expects(self, seq, expects):
4724 for expect in expects:
4726 seq.specs[expect["name"]].optional,
4729 if expect["default_value"] is not None:
4731 seq.specs[expect["name"]].default,
4732 expect["default_value"],
4734 if expect["presented"]:
4735 self.assertIn(expect["name"], seq)
4736 self.assertEqual(seq[expect["name"]], expect["value"])
4738 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4739 @given(data_strategy())
4740 def test_symmetric(self, d):
4741 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4742 tail_junk = d.draw(binary(max_size=5))
4743 self.assertTrue(seq.ready)
4744 self.assertFalse(seq.decoded)
4745 self._assert_expects(seq, expects)
4748 self.assertTrue(seq.ready)
4749 seq_encoded = seq.encode()
4750 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4751 self.assertFalse(seq_decoded.lenindef)
4752 self.assertFalse(seq_decoded.bered)
4754 t, _, lv = tag_strip(seq_encoded)
4755 _, _, v = len_decode(lv)
4756 seq_encoded_lenindef = t + LENINDEF + v + EOC
4757 seq_decoded_lenindef, tail_lenindef = seq.decode(
4758 seq_encoded_lenindef + tail_junk,
4759 ctx={"bered": True},
4761 self.assertTrue(seq_decoded_lenindef.lenindef)
4762 with self.assertRaises(DecodeError):
4763 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4764 with self.assertRaises(DecodeError):
4765 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4766 repr(seq_decoded_lenindef)
4767 pprint(seq_decoded_lenindef)
4768 self.assertTrue(seq_decoded_lenindef.ready)
4770 for decoded, decoded_tail, encoded in (
4771 (seq_decoded, tail, seq_encoded),
4772 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4774 self.assertEqual(decoded_tail, tail_junk)
4775 self._assert_expects(decoded, expects)
4776 self.assertEqual(seq, decoded)
4777 self.assertEqual(decoded.encode(), seq_encoded)
4778 self.assertEqual(decoded.tlvlen, len(encoded))
4779 for expect in expects:
4780 if not expect["presented"]:
4781 self.assertNotIn(expect["name"], decoded)
4783 self.assertIn(expect["name"], decoded)
4784 obj = decoded[expect["name"]]
4785 self.assertTrue(obj.decoded)
4786 offset = obj.expl_offset if obj.expled else obj.offset
4787 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4788 self.assertSequenceEqual(
4789 seq_encoded[offset:offset + tlvlen],
4793 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4794 @given(data_strategy())
4795 def test_symmetric_with_seq(self, d):
4796 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4797 self.assertTrue(seq.ready)
4798 seq_encoded = seq.encode()
4799 seq_decoded, tail = seq.decode(seq_encoded)
4800 self.assertEqual(tail, b"")
4801 self.assertTrue(seq.ready)
4802 self.assertEqual(seq, seq_decoded)
4803 self.assertEqual(seq_decoded.encode(), seq_encoded)
4804 for expect_outer in expect_outers:
4805 if not expect_outer["presented"]:
4806 self.assertNotIn(expect_outer["name"], seq_decoded)
4808 self.assertIn(expect_outer["name"], seq_decoded)
4809 obj = seq_decoded[expect_outer["name"]]
4810 self.assertTrue(obj.decoded)
4811 offset = obj.expl_offset if obj.expled else obj.offset
4812 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4813 self.assertSequenceEqual(
4814 seq_encoded[offset:offset + tlvlen],
4817 self._assert_expects(obj, expect_outer["expects"])
4819 @given(data_strategy())
4820 def test_default_disappears(self, d):
4821 _schema = list(d.draw(dictionaries(
4823 sets(integers(), min_size=2, max_size=2),
4827 class Seq(self.base_klass):
4829 (n, Integer(default=d))
4830 for n, (_, d) in _schema
4833 for name, (value, _) in _schema:
4834 seq[name] = Integer(value)
4835 self.assertEqual(len(seq._value), len(_schema))
4836 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4837 self.assertGreater(len(seq.encode()), len(empty_seq))
4838 for name, (_, default) in _schema:
4839 seq[name] = Integer(default)
4840 self.assertEqual(len(seq._value), 0)
4841 self.assertSequenceEqual(seq.encode(), empty_seq)
4843 @given(data_strategy())
4844 def test_encoded_default_not_accepted(self, d):
4845 _schema = list(d.draw(dictionaries(
4850 tags = [tag_encode(tag) for tag in d.draw(sets(
4851 integers(min_value=0),
4852 min_size=len(_schema),
4853 max_size=len(_schema),
4856 class SeqWithoutDefault(self.base_klass):
4858 (n, Integer(impl=t))
4859 for (n, _), t in zip(_schema, tags)
4861 seq_without_default = SeqWithoutDefault()
4862 for name, value in _schema:
4863 seq_without_default[name] = Integer(value)
4864 seq_encoded = seq_without_default.encode()
4866 class SeqWithDefault(self.base_klass):
4868 (n, Integer(default=v, impl=t))
4869 for (n, v), t in zip(_schema, tags)
4871 seq_with_default = SeqWithDefault()
4872 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
4873 seq_with_default.decode(seq_encoded)
4874 for ctx in ({"bered": True}, {"allow_default_values": True}):
4875 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
4876 self.assertTrue(seq_decoded.bered)
4877 for name, value in _schema:
4878 self.assertEqual(seq_decoded[name], seq_with_default[name])
4879 self.assertEqual(seq_decoded[name], value)
4881 @given(data_strategy())
4882 def test_missing_from_spec(self, d):
4883 names = list(d.draw(sets(text_letters(), min_size=2)))
4884 tags = [tag_encode(tag) for tag in d.draw(sets(
4885 integers(min_value=0),
4886 min_size=len(names),
4887 max_size=len(names),
4889 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4891 class SeqFull(self.base_klass):
4892 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4893 seq_full = SeqFull()
4894 for i, name in enumerate(names):
4895 seq_full[name] = Integer(i)
4896 seq_encoded = seq_full.encode()
4897 altered = names_tags[:-2] + names_tags[-1:]
4899 class SeqMissing(self.base_klass):
4900 schema = [(n, Integer(impl=t)) for n, t in altered]
4901 seq_missing = SeqMissing()
4902 with self.assertRaises(TagMismatch):
4903 seq_missing.decode(seq_encoded)
4906 class TestSequence(SeqMixing, CommonMixin, TestCase):
4907 base_klass = Sequence
4913 def test_remaining(self, value, junk):
4914 class Seq(Sequence):
4916 ("whatever", Integer()),
4918 int_encoded = Integer(value).encode()
4920 Sequence.tag_default,
4921 len_encode(len(int_encoded + junk)),
4924 with assertRaisesRegex(self, DecodeError, "remaining"):
4925 Seq().decode(junked)
4927 @given(sets(text_letters(), min_size=2))
4928 def test_obj_unknown(self, names):
4929 missing = names.pop()
4931 class Seq(Sequence):
4932 schema = [(n, Boolean()) for n in names]
4934 with self.assertRaises(ObjUnknown) as err:
4937 with self.assertRaises(ObjUnknown) as err:
4938 seq[missing] = Boolean()
4941 def test_x690_vector(self):
4942 class Seq(Sequence):
4944 ("name", IA5String()),
4947 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4948 self.assertEqual(seq["name"], "Smith")
4949 self.assertEqual(seq["ok"], True)
4952 class TestSet(SeqMixing, CommonMixin, TestCase):
4955 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4956 @given(data_strategy())
4957 def test_sorted(self, d):
4959 tag_encode(tag) for tag in
4960 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4964 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4966 for name, _ in Seq.schema:
4967 seq[name] = OctetString(b"")
4968 seq_encoded = seq.encode()
4969 seq_decoded, _ = seq.decode(seq_encoded)
4970 self.assertSequenceEqual(
4971 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4972 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4975 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4976 @given(data_strategy())
4977 def test_unsorted(self, d):
4979 tag_encode(tag) for tag in
4980 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
4982 tags = d.draw(permutations(tags))
4983 assume(tags != sorted(tags))
4984 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
4985 seq_encoded = b"".join((
4987 len_encode(len(encoded)),
4992 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4994 with assertRaisesRegex(self, DecodeError, "unordered SET"):
4995 seq.decode(seq_encoded)
4996 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
4997 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
4998 self.assertTrue(seq_decoded.bered)
4999 self.assertSequenceEqual(
5000 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5006 def seqof_values_strategy(draw, schema=None, do_expl=False):
5008 schema = draw(sampled_from((Boolean(), Integer())))
5009 bound_min, bound_max = sorted(draw(sets(
5010 integers(min_value=0, max_value=10),
5014 if isinstance(schema, Boolean):
5015 values_generator = booleans().map(Boolean)
5016 elif isinstance(schema, Integer):
5017 values_generator = integers().map(Integer)
5018 values_generator = lists(
5023 values = draw(one_of(none(), values_generator))
5027 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5029 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5030 default = draw(one_of(none(), values_generator))
5031 optional = draw(one_of(none(), booleans()))
5033 draw(integers(min_value=0)),
5034 draw(integers(min_value=0)),
5035 draw(integers(min_value=0)),
5040 (bound_min, bound_max),
5049 class SeqOfMixing(object):
5050 def test_invalid_value_type(self):
5051 with self.assertRaises(InvalidValueType) as err:
5052 self.base_klass(123)
5055 def test_invalid_values_type(self):
5056 class SeqOf(self.base_klass):
5058 with self.assertRaises(InvalidValueType) as err:
5059 SeqOf([Integer(123), Boolean(False), Integer(234)])
5062 def test_schema_required(self):
5063 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5064 self.base_klass.__mro__[1]()
5066 @given(booleans(), booleans(), binary(), binary())
5067 def test_comparison(self, value1, value2, tag1, tag2):
5068 class SeqOf(self.base_klass):
5070 obj1 = SeqOf([Boolean(value1)])
5071 obj2 = SeqOf([Boolean(value2)])
5072 self.assertEqual(obj1 == obj2, value1 == value2)
5073 self.assertEqual(obj1 != obj2, value1 != value2)
5074 self.assertEqual(obj1 == list(obj2), value1 == value2)
5075 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5076 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5077 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5078 self.assertEqual(obj1 == obj2, tag1 == tag2)
5079 self.assertEqual(obj1 != obj2, tag1 != tag2)
5081 @given(lists(booleans()))
5082 def test_iter(self, values):
5083 class SeqOf(self.base_klass):
5085 obj = SeqOf([Boolean(value) for value in values])
5086 self.assertEqual(len(obj), len(values))
5087 for i, value in enumerate(obj):
5088 self.assertEqual(value, values[i])
5090 @given(data_strategy())
5091 def test_ready(self, d):
5092 ready = [Integer(v) for v in d.draw(lists(
5099 range(d.draw(integers(min_value=1, max_value=5)))
5102 class SeqOf(self.base_klass):
5104 values = d.draw(permutations(ready + non_ready))
5106 for value in values:
5108 self.assertFalse(seqof.ready)
5111 with self.assertRaises(ObjNotReady) as err:
5114 for i, value in enumerate(values):
5115 self.assertEqual(seqof[i], value)
5116 if not seqof[i].ready:
5117 seqof[i] = Integer(i)
5118 self.assertTrue(seqof.ready)
5122 def test_spec_mismatch(self):
5123 class SeqOf(self.base_klass):
5126 seqof.append(Integer(123))
5127 with self.assertRaises(ValueError):
5128 seqof.append(Boolean(False))
5129 with self.assertRaises(ValueError):
5130 seqof[0] = Boolean(False)
5132 @given(data_strategy())
5133 def test_bounds_satisfied(self, d):
5134 class SeqOf(self.base_klass):
5136 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5137 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5138 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5139 SeqOf(value=value, bounds=(bound_min, bound_max))
5141 @given(data_strategy())
5142 def test_bounds_unsatisfied(self, d):
5143 class SeqOf(self.base_klass):
5145 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5146 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5147 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5148 with self.assertRaises(BoundsError) as err:
5149 SeqOf(value=value, bounds=(bound_min, bound_max))
5151 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5152 SeqOf(bounds=(bound_min, bound_max)).decode(
5153 SeqOf(value).encode()
5156 value = [Boolean(True)] * d.draw(integers(
5157 min_value=bound_max + 1,
5158 max_value=bound_max + 10,
5160 with self.assertRaises(BoundsError) as err:
5161 SeqOf(value=value, bounds=(bound_min, bound_max))
5163 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5164 SeqOf(bounds=(bound_min, bound_max)).decode(
5165 SeqOf(value).encode()
5169 @given(integers(min_value=1, max_value=10))
5170 def test_out_of_bounds(self, bound_max):
5171 class SeqOf(self.base_klass):
5173 bounds = (0, bound_max)
5175 for _ in range(bound_max):
5176 seqof.append(Integer(123))
5177 with self.assertRaises(BoundsError):
5178 seqof.append(Integer(123))
5180 @given(data_strategy())
5181 def test_call(self, d):
5191 ) = d.draw(seqof_values_strategy())
5193 class SeqOf(self.base_klass):
5194 schema = schema_initial
5195 obj_initial = SeqOf(
5196 value=value_initial,
5197 bounds=bounds_initial,
5200 default=default_initial,
5201 optional=optional_initial or False,
5202 _decoded=_decoded_initial,
5213 ) = d.draw(seqof_values_strategy(
5214 schema=schema_initial,
5215 do_expl=impl_initial is None,
5217 if (default is None) and (obj_initial.default is not None):
5220 (bounds is None) and
5221 (value is not None) and
5222 (bounds_initial is not None) and
5223 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5227 (bounds is None) and
5228 (default is not None) and
5229 (bounds_initial is not None) and
5230 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5242 value_expected = default if value is None else value
5244 default_initial if value_expected is None
5247 value_expected = () if value_expected is None else value_expected
5248 self.assertEqual(obj, value_expected)
5249 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5250 self.assertEqual(obj.expl_tag, expl or expl_initial)
5253 default_initial if default is None else default,
5255 if obj.default is None:
5256 optional = optional_initial if optional is None else optional
5257 optional = False if optional is None else optional
5260 self.assertEqual(obj.optional, optional)
5262 (obj._bound_min, obj._bound_max),
5263 bounds or bounds_initial or (0, float("+inf")),
5266 @given(seqof_values_strategy())
5267 def test_copy(self, values):
5268 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5270 class SeqOf(self.base_klass):
5278 optional=optional or False,
5281 obj_copied = obj.copy()
5282 self.assert_copied_basic_fields(obj, obj_copied)
5283 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5284 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5285 self.assertEqual(obj._value, obj_copied._value)
5289 integers(min_value=1).map(tag_encode),
5291 def test_stripped(self, values, tag_impl):
5292 class SeqOf(self.base_klass):
5293 schema = OctetString()
5294 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5295 with self.assertRaises(NotEnoughData):
5296 obj.decode(obj.encode()[:-1])
5300 integers(min_value=1).map(tag_ctxc),
5302 def test_stripped_expl(self, values, tag_expl):
5303 class SeqOf(self.base_klass):
5304 schema = OctetString()
5305 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5306 with self.assertRaises(NotEnoughData):
5307 obj.decode(obj.encode()[:-1])
5310 integers(min_value=31),
5311 integers(min_value=0),
5314 def test_bad_tag(self, tag, offset, decode_path):
5315 with self.assertRaises(DecodeError) as err:
5316 self.base_klass().decode(
5317 tag_encode(tag)[:-1],
5319 decode_path=decode_path,
5322 self.assertEqual(err.exception.offset, offset)
5323 self.assertEqual(err.exception.decode_path, decode_path)
5326 integers(min_value=128),
5327 integers(min_value=0),
5330 def test_bad_len(self, l, offset, decode_path):
5331 with self.assertRaises(DecodeError) as err:
5332 self.base_klass().decode(
5333 self.base_klass.tag_default + len_encode(l)[:-1],
5335 decode_path=decode_path,
5338 self.assertEqual(err.exception.offset, offset)
5339 self.assertEqual(err.exception.decode_path, decode_path)
5341 @given(binary(min_size=1))
5342 def test_tag_mismatch(self, impl):
5343 assume(impl != self.base_klass.tag_default)
5344 with self.assertRaises(TagMismatch):
5345 self.base_klass(impl=impl).decode(self.base_klass().encode())
5347 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5349 seqof_values_strategy(schema=Integer()),
5350 lists(integers().map(Integer)),
5351 integers(min_value=1).map(tag_ctxc),
5352 integers(min_value=0),
5355 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5356 _, _, _, _, _, default, optional, _decoded = values
5358 class SeqOf(self.base_klass):
5368 self.assertFalse(obj.expled)
5369 obj_encoded = obj.encode()
5370 obj_expled = obj(value, expl=tag_expl)
5371 self.assertTrue(obj_expled.expled)
5374 obj_expled_encoded = obj_expled.encode()
5375 obj_decoded, tail = obj_expled.decode(
5376 obj_expled_encoded + tail_junk,
5381 self.assertEqual(tail, tail_junk)
5382 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5383 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5384 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5385 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5387 obj_decoded.expl_llen,
5388 len(len_encode(len(obj_encoded))),
5390 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5391 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5394 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5396 self.assertEqual(obj_decoded.expl_offset, offset)
5397 for obj_inner in obj_decoded:
5398 self.assertIn(obj_inner, obj_decoded)
5399 self.assertSequenceEqual(
5402 obj_inner.offset - offset:
5403 obj_inner.offset + obj_inner.tlvlen - offset
5407 t, _, lv = tag_strip(obj_encoded)
5408 _, _, v = len_decode(lv)
5409 obj_encoded_lenindef = t + LENINDEF + v + EOC
5410 obj_decoded_lenindef, tail_lenindef = obj.decode(
5411 obj_encoded_lenindef + tail_junk,
5412 ctx={"bered": True},
5414 self.assertTrue(obj_decoded_lenindef.lenindef)
5415 repr(obj_decoded_lenindef)
5416 pprint(obj_decoded_lenindef)
5417 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5418 with self.assertRaises(DecodeError):
5419 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5420 with self.assertRaises(DecodeError):
5421 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5424 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5425 class SeqOf(SequenceOf):
5429 def _test_symmetric_compare_objs(self, obj1, obj2):
5430 self.assertEqual(obj1, obj2)
5431 self.assertSequenceEqual(list(obj1), list(obj2))
5434 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5439 def _test_symmetric_compare_objs(self, obj1, obj2):
5440 self.assertSetEqual(
5441 set(int(v) for v in obj1),
5442 set(int(v) for v in obj2),
5445 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5446 @given(data_strategy())
5447 def test_sorted(self, d):
5448 values = [OctetString(v) for v in d.draw(lists(binary()))]
5451 schema = OctetString()
5453 seq_encoded = seq.encode()
5454 seq_decoded, _ = seq.decode(seq_encoded)
5455 self.assertSequenceEqual(
5456 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5457 b"".join(sorted([v.encode() for v in values])),
5460 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5461 @given(data_strategy())
5462 def test_unsorted(self, d):
5463 values = [OctetString(v).encode() for v in d.draw(sets(
5464 binary(min_size=1, max_size=5),
5468 values = d.draw(permutations(values))
5469 assume(values != sorted(values))
5470 encoded = b"".join(values)
5471 seq_encoded = b"".join((
5473 len_encode(len(encoded)),
5478 schema = OctetString()
5480 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5481 seq.decode(seq_encoded)
5483 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5484 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5485 self.assertTrue(seq_decoded.bered)
5486 self.assertSequenceEqual(
5487 [obj.encode() for obj in seq_decoded],
5492 class TestGoMarshalVectors(TestCase):
5494 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5495 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5496 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5497 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5498 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5500 class Seq(Sequence):
5502 ("erste", Integer()),
5503 ("zweite", Integer(optional=True))
5506 seq["erste"] = Integer(64)
5507 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5508 seq["erste"] = Integer(0x123456)
5509 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5510 seq["erste"] = Integer(64)
5511 seq["zweite"] = Integer(65)
5512 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5514 class NestedSeq(Sequence):
5518 seq["erste"] = Integer(127)
5519 seq["zweite"] = None
5520 nested = NestedSeq()
5521 nested["nest"] = seq
5522 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5524 self.assertSequenceEqual(
5525 OctetString(b"\x01\x02\x03").encode(),
5526 hexdec("0403010203"),
5529 class Seq(Sequence):
5531 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5534 seq["erste"] = Integer(64)
5535 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5537 class Seq(Sequence):
5539 ("erste", Integer(expl=tag_ctxc(5))),
5542 seq["erste"] = Integer(64)
5543 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5545 class Seq(Sequence):
5548 impl=tag_encode(0, klass=TagClassContext),
5553 seq["erste"] = Null()
5554 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5556 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5558 self.assertSequenceEqual(
5559 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5560 hexdec("170d3730303130313030303030305a"),
5562 self.assertSequenceEqual(
5563 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5564 hexdec("170d3039313131353232353631365a"),
5566 self.assertSequenceEqual(
5567 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5568 hexdec("180f32313030303430353132303130315a"),
5571 class Seq(Sequence):
5573 ("erste", GeneralizedTime()),
5576 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5577 self.assertSequenceEqual(
5579 hexdec("3011180f32303039313131353232353631365a"),
5582 self.assertSequenceEqual(
5583 BitString((1, b"\x80")).encode(),
5586 self.assertSequenceEqual(
5587 BitString((12, b"\x81\xF0")).encode(),
5588 hexdec("03030481f0"),
5591 self.assertSequenceEqual(
5592 ObjectIdentifier("1.2.3.4").encode(),
5593 hexdec("06032a0304"),
5595 self.assertSequenceEqual(
5596 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5597 hexdec("06092a864888932d010105"),
5599 self.assertSequenceEqual(
5600 ObjectIdentifier("2.100.3").encode(),
5601 hexdec("0603813403"),
5604 self.assertSequenceEqual(
5605 PrintableString("test").encode(),
5606 hexdec("130474657374"),
5608 self.assertSequenceEqual(
5609 PrintableString("x" * 127).encode(),
5610 hexdec("137F" + "78" * 127),
5612 self.assertSequenceEqual(
5613 PrintableString("x" * 128).encode(),
5614 hexdec("138180" + "78" * 128),
5616 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5618 class Seq(Sequence):
5620 ("erste", IA5String()),
5623 seq["erste"] = IA5String("test")
5624 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5626 class Seq(Sequence):
5628 ("erste", PrintableString()),
5631 seq["erste"] = PrintableString("test")
5632 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5633 seq["erste"] = PrintableString("test*")
5634 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5636 class Seq(Sequence):
5638 ("erste", Any(optional=True)),
5639 ("zweite", Integer()),
5642 seq["zweite"] = Integer(64)
5643 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5648 seq.append(Integer(10))
5649 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5651 class _SeqOf(SequenceOf):
5652 schema = PrintableString()
5654 class SeqOf(SequenceOf):
5657 _seqof.append(PrintableString("1"))
5659 seqof.append(_seqof)
5660 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5662 class Seq(Sequence):
5664 ("erste", Integer(default=1)),
5667 seq["erste"] = Integer(0)
5668 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5669 seq["erste"] = Integer(1)
5670 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5671 seq["erste"] = Integer(2)
5672 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5675 class TestPP(TestCase):
5676 @given(data_strategy())
5677 def test_oid_printing(self, d):
5679 str(ObjectIdentifier(k)): v * 2
5680 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5682 chosen = d.draw(sampled_from(sorted(oids)))
5683 chosen_id = oids[chosen]
5684 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5685 self.assertNotIn(chosen_id, pp_console_row(pp))
5686 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5689 class TestAutoAddSlots(TestCase):
5691 class Inher(Integer):
5694 with self.assertRaises(AttributeError):
5696 inher.unexistent = "whatever"
5699 class TestOIDDefines(TestCase):
5700 @given(data_strategy())
5701 def runTest(self, d):
5702 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5703 value_name_chosen = d.draw(sampled_from(value_names))
5705 ObjectIdentifier(oid)
5706 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5708 oid_chosen = d.draw(sampled_from(oids))
5709 values = d.draw(lists(
5711 min_size=len(value_names),
5712 max_size=len(value_names),
5715 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5716 oid: Integer() for oid in oids[:-1]
5719 for i, value_name in enumerate(value_names):
5720 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5722 class Seq(Sequence):
5725 for value_name, value in zip(value_names, values):
5726 seq[value_name] = Any(Integer(value).encode())
5727 seq["type"] = oid_chosen
5728 seq, _ = Seq().decode(seq.encode())
5729 for value_name in value_names:
5730 if value_name == value_name_chosen:
5732 self.assertIsNone(seq[value_name].defined)
5733 if value_name_chosen in oids[:-1]:
5734 self.assertIsNotNone(seq[value_name_chosen].defined)
5735 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5736 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5739 class TestDefinesByPath(TestCase):
5740 def test_generated(self):
5741 class Seq(Sequence):
5743 ("type", ObjectIdentifier()),
5744 ("value", OctetString(expl=tag_ctxc(123))),
5747 class SeqInner(Sequence):
5749 ("typeInner", ObjectIdentifier()),
5750 ("valueInner", Any()),
5753 class PairValue(SetOf):
5756 class Pair(Sequence):
5758 ("type", ObjectIdentifier()),
5759 ("value", PairValue()),
5762 class Pairs(SequenceOf):
5769 type_octet_stringed,
5771 ObjectIdentifier(oid)
5772 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5774 seq_integered = Seq()
5775 seq_integered["type"] = type_integered
5776 seq_integered["value"] = OctetString(Integer(123).encode())
5777 seq_integered_raw = seq_integered.encode()
5781 (type_octet_stringed, OctetString(b"whatever")),
5782 (type_integered, Integer(123)),
5783 (type_octet_stringed, OctetString(b"whenever")),
5784 (type_integered, Integer(234)),
5786 for t, v in pairs_input:
5789 pair["value"] = PairValue((Any(v),))
5791 seq_inner = SeqInner()
5792 seq_inner["typeInner"] = type_innered
5793 seq_inner["valueInner"] = Any(pairs)
5794 seq_sequenced = Seq()
5795 seq_sequenced["type"] = type_sequenced
5796 seq_sequenced["value"] = OctetString(seq_inner.encode())
5797 seq_sequenced_raw = seq_sequenced.encode()
5799 defines_by_path = []
5800 seq_integered, _ = Seq().decode(seq_integered_raw)
5801 self.assertIsNone(seq_integered["value"].defined)
5802 defines_by_path.append(
5803 (("type",), ((("value",), {
5804 type_integered: Integer(),
5805 type_sequenced: SeqInner(),
5808 seq_integered, _ = Seq().decode(
5810 ctx={"defines_by_path": defines_by_path},
5812 self.assertIsNotNone(seq_integered["value"].defined)
5813 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5814 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5815 self.assertTrue(seq_integered_raw[
5816 seq_integered["value"].defined[1].offset:
5817 ].startswith(Integer(123).encode()))
5819 seq_sequenced, _ = Seq().decode(
5821 ctx={"defines_by_path": defines_by_path},
5823 self.assertIsNotNone(seq_sequenced["value"].defined)
5824 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5825 seq_inner = seq_sequenced["value"].defined[1]
5826 self.assertIsNone(seq_inner["valueInner"].defined)
5828 defines_by_path.append((
5829 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5830 ((("valueInner",), {type_innered: Pairs()}),),
5832 seq_sequenced, _ = Seq().decode(
5834 ctx={"defines_by_path": defines_by_path},
5836 self.assertIsNotNone(seq_sequenced["value"].defined)
5837 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5838 seq_inner = seq_sequenced["value"].defined[1]
5839 self.assertIsNotNone(seq_inner["valueInner"].defined)
5840 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5841 pairs = seq_inner["valueInner"].defined[1]
5843 self.assertIsNone(pair["value"][0].defined)
5845 defines_by_path.append((
5848 DecodePathDefBy(type_sequenced),
5850 DecodePathDefBy(type_innered),
5855 type_integered: Integer(),
5856 type_octet_stringed: OctetString(),
5859 seq_sequenced, _ = Seq().decode(
5861 ctx={"defines_by_path": defines_by_path},
5863 self.assertIsNotNone(seq_sequenced["value"].defined)
5864 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5865 seq_inner = seq_sequenced["value"].defined[1]
5866 self.assertIsNotNone(seq_inner["valueInner"].defined)
5867 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5868 pairs_got = seq_inner["valueInner"].defined[1]
5869 for pair_input, pair_got in zip(pairs_input, pairs_got):
5870 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5871 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5873 @given(oid_strategy(), integers())
5874 def test_simple(self, oid, tgt):
5875 class Inner(Sequence):
5877 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5878 ObjectIdentifier(oid): Integer(),
5882 class Outer(Sequence):
5885 ("tgt", OctetString()),
5889 inner["oid"] = ObjectIdentifier(oid)
5891 outer["inner"] = inner
5892 outer["tgt"] = OctetString(Integer(tgt).encode())
5893 decoded, _ = Outer().decode(outer.encode())
5894 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5897 class TestAbsDecodePath(TestCase):
5899 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5900 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5902 def test_concat(self, decode_path, rel_path):
5903 self.assertSequenceEqual(
5904 abs_decode_path(decode_path, rel_path),
5905 decode_path + rel_path,
5909 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5910 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5912 def test_abs(self, decode_path, rel_path):
5913 self.assertSequenceEqual(
5914 abs_decode_path(decode_path, ("/",) + rel_path),
5919 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5920 integers(min_value=1, max_value=3),
5921 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5923 def test_dots(self, decode_path, number_of_dots, rel_path):
5924 self.assertSequenceEqual(
5925 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5926 decode_path[:-number_of_dots] + rel_path,
5930 class TestStrictDefaultExistence(TestCase):
5931 @given(data_strategy())
5932 def runTest(self, d):
5933 count = d.draw(integers(min_value=1, max_value=10))
5934 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5936 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5937 for i in range(count)
5939 for klass in (Sequence, Set):
5943 for i in range(count):
5944 seq["int%d" % i] = Integer(123)
5946 chosen_choice = "int%d" % chosen
5947 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
5948 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5950 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
5951 self.assertTrue(decoded.bered)
5952 decoded, _ = seq.decode(raw, ctx={"bered": True})
5953 self.assertTrue(decoded.bered)
5956 class TestX690PrefixedType(TestCase):
5958 self.assertSequenceEqual(
5959 VisibleString("Jones").encode(),
5960 hexdec("1A054A6F6E6573"),
5962 self.assertSequenceEqual(
5965 impl=tag_encode(3, klass=TagClassApplication),
5967 hexdec("43054A6F6E6573"),
5969 self.assertSequenceEqual(
5973 impl=tag_encode(3, klass=TagClassApplication),
5977 hexdec("A20743054A6F6E6573"),
5979 self.assertSequenceEqual(
5983 impl=tag_encode(3, klass=TagClassApplication),
5985 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5987 hexdec("670743054A6F6E6573"),
5989 self.assertSequenceEqual(
5990 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5991 hexdec("82054A6F6E6573"),
5995 class TestExplOOB(TestCase):
5997 expl = tag_ctxc(123)
5998 raw = Integer(123).encode() + Integer(234).encode()
5999 raw = b"".join((expl, len_encode(len(raw)), raw))
6000 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6001 Integer(expl=expl).decode(raw)
6002 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})