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 NotEnoughData
81 from pyderasn import Null
82 from pyderasn import NumericString
83 from pyderasn import ObjectIdentifier
84 from pyderasn import ObjNotReady
85 from pyderasn import ObjUnknown
86 from pyderasn import OctetString
87 from pyderasn import pp_console_row
88 from pyderasn import pprint
89 from pyderasn import PrintableString
90 from pyderasn import Sequence
91 from pyderasn import SequenceOf
92 from pyderasn import Set
93 from pyderasn import SetOf
94 from pyderasn import tag_ctxc
95 from pyderasn import tag_ctxp
96 from pyderasn import tag_decode
97 from pyderasn import tag_encode
98 from pyderasn import tag_strip
99 from pyderasn import TagClassApplication
100 from pyderasn import TagClassContext
101 from pyderasn import TagClassPrivate
102 from pyderasn import TagClassUniversal
103 from pyderasn import TagFormConstructed
104 from pyderasn import TagFormPrimitive
105 from pyderasn import TagMismatch
106 from pyderasn import TeletexString
107 from pyderasn import UniversalString
108 from pyderasn import UTCTime
109 from pyderasn import UTF8String
110 from pyderasn import VideotexString
111 from pyderasn import VisibleString
114 settings.register_profile("local", settings(
116 perform_health_check=False,
118 settings.load_profile("local")
119 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
121 tag_classes = sampled_from((
127 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
130 class TestHex(TestCase):
132 def test_symmetric(self, data):
133 self.assertEqual(hexdec(hexenc(data)), data)
136 class TestTagCoder(TestCase):
137 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
141 integers(min_value=0, max_value=30),
144 def test_short(self, klass, form, num, junk):
145 raw = tag_encode(klass=klass, form=form, num=num)
146 self.assertEqual(tag_decode(raw), (klass, form, num))
147 self.assertEqual(len(raw), 1)
149 byte2int(tag_encode(klass=klass, form=form, num=0)),
150 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
152 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
153 self.assertSequenceEqual(stripped.tobytes(), raw)
154 self.assertEqual(tlen, len(raw))
155 self.assertSequenceEqual(tail, junk)
157 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
161 integers(min_value=31),
164 def test_long(self, klass, form, num, junk):
165 raw = tag_encode(klass=klass, form=form, num=num)
166 self.assertEqual(tag_decode(raw), (klass, form, num))
167 self.assertGreater(len(raw), 1)
169 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
172 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
173 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
174 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
175 self.assertSequenceEqual(stripped.tobytes(), raw)
176 self.assertEqual(tlen, len(raw))
177 self.assertSequenceEqual(tail, junk)
179 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
180 @given(integers(min_value=31))
181 def test_unfinished_tag(self, num):
182 raw = bytearray(tag_encode(num=num))
183 for i in range(1, len(raw)):
185 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
186 tag_strip(bytes(raw))
188 def test_go_vectors_valid(self):
189 for data, (eklass, etag, elen, eform) in (
190 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
191 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
192 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
193 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
194 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
195 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
196 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
197 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
198 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
199 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
201 tag, _, len_encoded = tag_strip(memoryview(data))
202 klass, form, num = tag_decode(tag)
203 _len, _, tail = len_decode(len_encoded)
204 self.assertSequenceEqual(tail, b"")
205 self.assertEqual(klass, eklass)
206 self.assertEqual(num, etag)
207 self.assertEqual(_len, elen)
208 self.assertEqual(form, eform)
210 def test_go_vectors_invalid(self):
218 with self.assertRaises(DecodeError):
219 _, _, len_encoded = tag_strip(memoryview(data))
220 len_decode(len_encoded)
223 integers(min_value=0, max_value=127),
224 integers(min_value=0, max_value=2),
226 def test_long_instead_of_short(self, l, dummy_num):
227 octets = (b"\x00" * dummy_num) + int2byte(l)
228 octets = int2byte((dummy_num + 1) | 0x80) + octets
229 with self.assertRaises(DecodeError):
233 class TestLenCoder(TestCase):
234 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
236 integers(min_value=0, max_value=127),
239 def test_short(self, l, junk):
240 raw = len_encode(l) + junk
241 decoded, llen, tail = len_decode(memoryview(raw))
242 self.assertEqual(decoded, l)
243 self.assertEqual(llen, 1)
244 self.assertEqual(len(raw), 1 + len(junk))
245 self.assertEqual(tail.tobytes(), junk)
247 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
249 integers(min_value=128),
252 def test_long(self, l, junk):
253 raw = len_encode(l) + junk
254 decoded, llen, tail = len_decode(memoryview(raw))
255 self.assertEqual(decoded, l)
256 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
257 self.assertEqual(llen, len(raw) - len(junk))
258 self.assertNotEqual(indexbytes(raw, 1), 0)
259 self.assertSequenceEqual(tail.tobytes(), junk)
261 def test_empty(self):
262 with self.assertRaises(NotEnoughData):
265 @given(integers(min_value=128))
266 def test_stripped(self, _len):
267 with self.assertRaises(NotEnoughData):
268 len_decode(len_encode(_len)[:-1])
271 text_printable = text(alphabet=printable, min_size=1)
275 def text_letters(draw):
276 result = draw(text(alphabet=ascii_letters, min_size=1))
278 result = result.encode("ascii")
282 class CommonMixin(object):
283 def test_tag_default(self):
284 obj = self.base_klass()
285 self.assertEqual(obj.tag, obj.tag_default)
287 def test_simultaneous_impl_expl(self):
288 with self.assertRaises(ValueError):
289 self.base_klass(impl=b"whatever", expl=b"whenever")
291 @given(binary(min_size=1), integers(), integers(), integers())
292 def test_decoded(self, impl, offset, llen, vlen):
293 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
294 self.assertEqual(obj.offset, offset)
295 self.assertEqual(obj.llen, llen)
296 self.assertEqual(obj.vlen, vlen)
297 self.assertEqual(obj.tlen, len(impl))
298 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
300 @given(binary(min_size=1))
301 def test_impl_inherited(self, impl_tag):
302 class Inherited(self.base_klass):
305 self.assertSequenceEqual(obj.impl, impl_tag)
306 self.assertFalse(obj.expled)
309 def test_expl_inherited(self, expl_tag):
310 class Inherited(self.base_klass):
313 self.assertSequenceEqual(obj.expl, expl_tag)
314 self.assertTrue(obj.expled)
316 def assert_copied_basic_fields(self, obj, obj_copied):
317 self.assertEqual(obj, obj_copied)
318 self.assertSequenceEqual(obj.tag, obj_copied.tag)
319 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
320 self.assertEqual(obj.default, obj_copied.default)
321 self.assertEqual(obj.optional, obj_copied.optional)
322 self.assertEqual(obj.offset, obj_copied.offset)
323 self.assertEqual(obj.llen, obj_copied.llen)
324 self.assertEqual(obj.vlen, obj_copied.vlen)
328 def boolean_values_strategy(draw, do_expl=False):
329 value = draw(one_of(none(), booleans()))
333 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
335 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
336 default = draw(one_of(none(), booleans()))
337 optional = draw(one_of(none(), booleans()))
339 draw(integers(min_value=0)),
340 draw(integers(min_value=0)),
341 draw(integers(min_value=0)),
343 return (value, impl, expl, default, optional, _decoded)
346 class BooleanInherited(Boolean):
350 class TestBoolean(CommonMixin, TestCase):
353 def test_invalid_value_type(self):
354 with self.assertRaises(InvalidValueType) as err:
359 def test_optional(self, optional):
360 obj = Boolean(default=Boolean(False), optional=optional)
361 self.assertTrue(obj.optional)
364 def test_ready(self, value):
366 self.assertFalse(obj.ready)
369 with self.assertRaises(ObjNotReady) as err:
373 self.assertTrue(obj.ready)
377 @given(booleans(), booleans(), binary(), binary())
378 def test_comparison(self, value1, value2, tag1, tag2):
379 for klass in (Boolean, BooleanInherited):
382 self.assertEqual(obj1 == obj2, value1 == value2)
383 self.assertEqual(obj1 != obj2, value1 != value2)
384 self.assertEqual(obj1 == bool(obj2), value1 == value2)
385 obj1 = klass(value1, impl=tag1)
386 obj2 = klass(value1, impl=tag2)
387 self.assertEqual(obj1 == obj2, tag1 == tag2)
388 self.assertEqual(obj1 != obj2, tag1 != tag2)
390 @given(data_strategy())
391 def test_call(self, d):
392 for klass in (Boolean, BooleanInherited):
400 ) = d.draw(boolean_values_strategy())
406 optional_initial or False,
416 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
417 obj = obj_initial(value, impl, expl, default, optional)
419 value_expected = default if value is None else value
421 default_initial if value_expected is None
424 self.assertEqual(obj, value_expected)
425 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
426 self.assertEqual(obj.expl_tag, expl or expl_initial)
429 default_initial if default is None else default,
431 if obj.default is None:
432 optional = optional_initial if optional is None else optional
433 optional = False if optional is None else optional
436 self.assertEqual(obj.optional, optional)
438 @given(boolean_values_strategy())
439 def test_copy(self, values):
440 for klass in (Boolean, BooleanInherited):
442 obj_copied = obj.copy()
443 self.assert_copied_basic_fields(obj, obj_copied)
447 integers(min_value=1).map(tag_encode),
449 def test_stripped(self, value, tag_impl):
450 obj = Boolean(value, impl=tag_impl)
451 with self.assertRaises(NotEnoughData):
452 obj.decode(obj.encode()[:-1])
456 integers(min_value=1).map(tag_ctxc),
458 def test_stripped_expl(self, value, tag_expl):
459 obj = Boolean(value, expl=tag_expl)
460 with self.assertRaises(NotEnoughData):
461 obj.decode(obj.encode()[:-1])
464 integers(min_value=31),
465 integers(min_value=0),
468 def test_bad_tag(self, tag, offset, decode_path):
469 decode_path = tuple(str(i) for i in decode_path)
470 with self.assertRaises(DecodeError) as err:
472 tag_encode(tag)[:-1],
474 decode_path=decode_path,
477 self.assertEqual(err.exception.offset, offset)
478 self.assertEqual(err.exception.decode_path, decode_path)
481 integers(min_value=31),
482 integers(min_value=0),
485 def test_bad_expl_tag(self, tag, offset, decode_path):
486 decode_path = tuple(str(i) for i in decode_path)
487 with self.assertRaises(DecodeError) as err:
488 Boolean(expl=Boolean.tag_default).decode(
489 tag_encode(tag)[:-1],
491 decode_path=decode_path,
494 self.assertEqual(err.exception.offset, offset)
495 self.assertEqual(err.exception.decode_path, decode_path)
498 integers(min_value=128),
499 integers(min_value=0),
502 def test_bad_len(self, l, offset, decode_path):
503 decode_path = tuple(str(i) for i in decode_path)
504 with self.assertRaises(DecodeError) as err:
506 Boolean.tag_default + len_encode(l)[:-1],
508 decode_path=decode_path,
511 self.assertEqual(err.exception.offset, offset)
512 self.assertEqual(err.exception.decode_path, decode_path)
515 integers(min_value=128),
516 integers(min_value=0),
519 def test_bad_expl_len(self, l, offset, decode_path):
520 decode_path = tuple(str(i) for i in decode_path)
521 with self.assertRaises(DecodeError) as err:
522 Boolean(expl=Boolean.tag_default).decode(
523 Boolean.tag_default + len_encode(l)[:-1],
525 decode_path=decode_path,
528 self.assertEqual(err.exception.offset, offset)
529 self.assertEqual(err.exception.decode_path, decode_path)
531 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
533 boolean_values_strategy(),
535 integers(min_value=1).map(tag_ctxc),
536 integers(min_value=0),
539 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
540 for klass in (Boolean, BooleanInherited):
541 _, _, _, default, optional, _decoded = values
550 self.assertFalse(obj.expled)
551 obj_encoded = obj.encode()
552 obj_expled = obj(value, expl=tag_expl)
553 self.assertTrue(obj_expled.expled)
556 obj_expled_encoded = obj_expled.encode()
557 obj_decoded, tail = obj_expled.decode(
558 obj_expled_encoded + tail_junk,
563 self.assertEqual(tail, tail_junk)
564 self.assertEqual(obj_decoded, obj_expled)
565 self.assertNotEqual(obj_decoded, obj)
566 self.assertEqual(bool(obj_decoded), bool(obj_expled))
567 self.assertEqual(bool(obj_decoded), bool(obj))
568 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
569 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
570 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
572 obj_decoded.expl_llen,
573 len(len_encode(len(obj_encoded))),
575 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
576 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
579 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
581 self.assertEqual(obj_decoded.expl_offset, offset)
583 @given(integers(min_value=2))
584 def test_invalid_len(self, l):
585 with self.assertRaises(InvalidLength):
586 Boolean().decode(b"".join((
592 @given(integers(min_value=0 + 1, max_value=255 - 1))
593 def test_ber_value(self, value):
594 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
595 Boolean().decode(b"".join((
600 obj, _ = Boolean().decode(
608 self.assertTrue(bool(obj))
609 self.assertTrue(obj.bered)
610 self.assertFalse(obj.lenindef)
613 integers(min_value=1).map(tag_ctxc),
620 def test_ber_expl(self, expl, values):
626 Boolean(value).encode() +
629 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
631 class SeqOf(SequenceOf):
632 schema = Boolean(expl=expl)
633 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
634 self.assertSequenceEqual(tail, b"")
635 self.assertSequenceEqual([bool(v) for v in seqof], values)
650 len(expl) + 1 + 3 + EOC_LEN,
661 def integer_values_strategy(draw, do_expl=False):
662 bound_min, value, default, bound_max = sorted(draw(sets(
671 _specs = draw(sets(text_letters()))
674 min_size=len(_specs),
675 max_size=len(_specs),
677 _specs = list(zip(_specs, values))
680 bounds = (bound_min, bound_max)
684 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
686 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
689 optional = draw(one_of(none(), booleans()))
691 draw(integers(min_value=0)),
692 draw(integers(min_value=0)),
693 draw(integers(min_value=0)),
695 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
698 class IntegerInherited(Integer):
702 class TestInteger(CommonMixin, TestCase):
705 def test_invalid_value_type(self):
706 with self.assertRaises(InvalidValueType) as err:
710 @given(sets(text_letters(), min_size=2))
711 def test_unknown_name(self, names_input):
712 missing = names_input.pop()
715 schema = [(n, 123) for n in names_input]
716 with self.assertRaises(ObjUnknown) as err:
720 @given(sets(text_letters(), min_size=2))
721 def test_known_name(self, names_input):
723 schema = [(n, 123) for n in names_input]
724 Int(names_input.pop())
727 def test_optional(self, optional):
728 obj = Integer(default=Integer(0), optional=optional)
729 self.assertTrue(obj.optional)
732 def test_ready(self, value):
734 self.assertFalse(obj.ready)
737 with self.assertRaises(ObjNotReady) as err:
741 self.assertTrue(obj.ready)
746 @given(integers(), integers(), binary(), binary())
747 def test_comparison(self, value1, value2, tag1, tag2):
748 for klass in (Integer, IntegerInherited):
751 self.assertEqual(obj1 == obj2, value1 == value2)
752 self.assertEqual(obj1 != obj2, value1 != value2)
753 self.assertEqual(obj1 == int(obj2), value1 == value2)
754 obj1 = klass(value1, impl=tag1)
755 obj2 = klass(value1, impl=tag2)
756 self.assertEqual(obj1 == obj2, tag1 == tag2)
757 self.assertEqual(obj1 != obj2, tag1 != tag2)
759 @given(lists(integers()))
760 def test_sorted_works(self, values):
761 self.assertSequenceEqual(
762 [int(v) for v in sorted(Integer(v) for v in values)],
766 @given(data_strategy())
767 def test_named(self, d):
768 names_input = list(d.draw(sets(text_letters(), min_size=1)))
769 values_input = list(d.draw(sets(
771 min_size=len(names_input),
772 max_size=len(names_input),
774 chosen_name = d.draw(sampled_from(names_input))
775 names_input = dict(zip(names_input, values_input))
779 _int = Int(chosen_name)
780 self.assertEqual(_int.named, chosen_name)
781 self.assertEqual(int(_int), names_input[chosen_name])
783 @given(integers(), integers(min_value=0), integers(min_value=0))
784 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
785 value = bound_min + value_delta
786 bound_max = value + bound_delta
787 Integer(value=value, bounds=(bound_min, bound_max))
789 @given(sets(integers(), min_size=3, max_size=3))
790 def test_bounds_unsatisfied(self, values):
791 values = sorted(values)
792 with self.assertRaises(BoundsError) as err:
793 Integer(value=values[0], bounds=(values[1], values[2]))
795 with self.assertRaises(BoundsError) as err:
796 Integer(value=values[2], bounds=(values[0], values[1]))
799 @given(data_strategy())
800 def test_call(self, d):
801 for klass in (Integer, IntegerInherited):
811 ) = d.draw(integer_values_strategy())
818 optional_initial or False,
831 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
832 if (default is None) and (obj_initial.default is not None):
836 (value is not None) and
837 (bounds_initial is not None) and
838 not (bounds_initial[0] <= value <= bounds_initial[1])
843 (default is not None) and
844 (bounds_initial is not None) and
845 not (bounds_initial[0] <= default <= bounds_initial[1])
848 obj = obj_initial(value, bounds, impl, expl, default, optional)
850 value_expected = default if value is None else value
852 default_initial if value_expected is None
855 self.assertEqual(obj, value_expected)
856 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
857 self.assertEqual(obj.expl_tag, expl or expl_initial)
860 default_initial if default is None else default,
862 if obj.default is None:
863 optional = optional_initial if optional is None else optional
864 optional = False if optional is None else optional
867 self.assertEqual(obj.optional, optional)
869 (obj._bound_min, obj._bound_max),
870 bounds or bounds_initial or (float("-inf"), float("+inf")),
874 {} if _specs_initial is None else dict(_specs_initial),
877 @given(integer_values_strategy())
878 def test_copy(self, values):
879 for klass in (Integer, IntegerInherited):
881 obj_copied = obj.copy()
882 self.assert_copied_basic_fields(obj, obj_copied)
883 self.assertEqual(obj.specs, obj_copied.specs)
884 self.assertEqual(obj._bound_min, obj_copied._bound_min)
885 self.assertEqual(obj._bound_max, obj_copied._bound_max)
886 self.assertEqual(obj._value, obj_copied._value)
890 integers(min_value=1).map(tag_encode),
892 def test_stripped(self, value, tag_impl):
893 obj = Integer(value, impl=tag_impl)
894 with self.assertRaises(NotEnoughData):
895 obj.decode(obj.encode()[:-1])
899 integers(min_value=1).map(tag_ctxc),
901 def test_stripped_expl(self, value, tag_expl):
902 obj = Integer(value, expl=tag_expl)
903 with self.assertRaises(NotEnoughData):
904 obj.decode(obj.encode()[:-1])
906 def test_zero_len(self):
907 with self.assertRaises(NotEnoughData):
908 Integer().decode(b"".join((
914 integers(min_value=31),
915 integers(min_value=0),
918 def test_bad_tag(self, tag, offset, decode_path):
919 decode_path = tuple(str(i) for i in decode_path)
920 with self.assertRaises(DecodeError) as err:
922 tag_encode(tag)[:-1],
924 decode_path=decode_path,
927 self.assertEqual(err.exception.offset, offset)
928 self.assertEqual(err.exception.decode_path, decode_path)
931 integers(min_value=128),
932 integers(min_value=0),
935 def test_bad_len(self, l, offset, decode_path):
936 decode_path = tuple(str(i) for i in decode_path)
937 with self.assertRaises(DecodeError) as err:
939 Integer.tag_default + len_encode(l)[:-1],
941 decode_path=decode_path,
944 self.assertEqual(err.exception.offset, offset)
945 self.assertEqual(err.exception.decode_path, decode_path)
948 sets(integers(), min_size=2, max_size=2),
949 integers(min_value=0),
952 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
953 decode_path = tuple(str(i) for i in decode_path)
954 value, bound_min = list(sorted(ints))
957 bounds = (bound_min, bound_min)
958 with self.assertRaises(DecodeError) as err:
960 Integer(value).encode(),
962 decode_path=decode_path,
965 self.assertEqual(err.exception.offset, offset)
966 self.assertEqual(err.exception.decode_path, decode_path)
968 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
970 integer_values_strategy(),
972 integers(min_value=1).map(tag_ctxc),
973 integers(min_value=0),
976 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
977 for klass in (Integer, IntegerInherited):
978 _, _, _, _, default, optional, _, _decoded = values
987 self.assertFalse(obj.expled)
988 obj_encoded = obj.encode()
989 obj_expled = obj(value, expl=tag_expl)
990 self.assertTrue(obj_expled.expled)
993 obj_expled_encoded = obj_expled.encode()
994 obj_decoded, tail = obj_expled.decode(
995 obj_expled_encoded + tail_junk,
1000 self.assertEqual(tail, tail_junk)
1001 self.assertEqual(obj_decoded, obj_expled)
1002 self.assertNotEqual(obj_decoded, obj)
1003 self.assertEqual(int(obj_decoded), int(obj_expled))
1004 self.assertEqual(int(obj_decoded), int(obj))
1005 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1006 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1007 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1009 obj_decoded.expl_llen,
1010 len(len_encode(len(obj_encoded))),
1012 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1013 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1016 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1018 self.assertEqual(obj_decoded.expl_offset, offset)
1020 def test_go_vectors_valid(self):
1021 for data, expect in ((
1025 (b"\xff\x7f", -129),
1029 (b"\xff\x00", -256),
1033 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1034 (b"\x80\x00\x00\x00", -2147483648),
1037 Integer().decode(b"".join((
1038 Integer.tag_default,
1039 len_encode(len(data)),
1045 def test_go_vectors_invalid(self):
1050 with self.assertRaises(DecodeError):
1051 Integer().decode(b"".join((
1052 Integer.tag_default,
1053 len_encode(len(data)),
1059 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1062 if draw(booleans()):
1063 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1065 integers(min_value=0, max_value=255),
1066 min_size=len(schema),
1067 max_size=len(schema),
1069 schema = list(zip(schema, bits))
1071 def _value(value_required):
1072 if not value_required and draw(booleans()):
1074 generation_choice = 0
1076 generation_choice = draw(sampled_from((1, 2, 3)))
1077 if generation_choice == 1 or draw(booleans()):
1078 return "'%s'B" % "".join(draw(lists(
1079 sampled_from(("0", "1")),
1080 max_size=len(schema),
1082 elif generation_choice == 2 or draw(booleans()):
1083 return draw(binary(max_size=len(schema) // 8))
1084 elif generation_choice == 3 or draw(booleans()):
1085 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1087 value = _value(value_required)
1088 default = _value(value_required=False)
1092 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1094 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1095 optional = draw(one_of(none(), booleans()))
1097 draw(integers(min_value=0)),
1098 draw(integers(min_value=0)),
1099 draw(integers(min_value=0)),
1101 return (schema, value, impl, expl, default, optional, _decoded)
1104 class BitStringInherited(BitString):
1108 class TestBitString(CommonMixin, TestCase):
1109 base_klass = BitString
1111 @given(lists(booleans()))
1112 def test_b_encoding(self, bits):
1113 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1114 self.assertEqual(obj.bit_len, len(bits))
1115 self.assertSequenceEqual(list(obj), bits)
1116 for i, bit in enumerate(bits):
1117 self.assertEqual(obj[i], bit)
1119 @given(lists(booleans()))
1120 def test_out_of_bounds_bits(self, bits):
1121 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1122 for i in range(len(bits), len(bits) * 2):
1123 self.assertFalse(obj[i])
1125 def test_bad_b_encoding(self):
1126 with self.assertRaises(ValueError):
1127 BitString("'010120101'B")
1130 integers(min_value=1, max_value=255),
1131 integers(min_value=1, max_value=255),
1133 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1134 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1135 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1136 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1138 class BS(BitString):
1139 schema = (("whatever", 0),)
1140 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1141 self.assertEqual(obj.bit_len, leading_zeros + 1)
1142 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1144 def test_zero_len(self):
1145 with self.assertRaises(NotEnoughData):
1146 BitString().decode(b"".join((
1147 BitString.tag_default,
1151 def test_invalid_value_type(self):
1152 with self.assertRaises(InvalidValueType) as err:
1155 with self.assertRaises(InvalidValueType) as err:
1159 def test_obj_unknown(self):
1160 with self.assertRaises(ObjUnknown) as err:
1161 BitString(b"whatever")["whenever"]
1164 def test_get_invalid_type(self):
1165 with self.assertRaises(InvalidValueType) as err:
1166 BitString(b"whatever")[(1, 2, 3)]
1169 @given(data_strategy())
1170 def test_unknown_name(self, d):
1171 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1172 missing = _schema.pop()
1174 class BS(BitString):
1175 schema = [(n, i) for i, n in enumerate(_schema)]
1176 with self.assertRaises(ObjUnknown) as err:
1181 def test_optional(self, optional):
1182 obj = BitString(default=BitString(b""), optional=optional)
1183 self.assertTrue(obj.optional)
1186 def test_ready(self, value):
1188 self.assertFalse(obj.ready)
1191 with self.assertRaises(ObjNotReady) as err:
1194 obj = BitString(value)
1195 self.assertTrue(obj.ready)
1200 tuples(integers(min_value=0), binary()),
1201 tuples(integers(min_value=0), binary()),
1205 def test_comparison(self, value1, value2, tag1, tag2):
1206 for klass in (BitString, BitStringInherited):
1207 obj1 = klass(value1)
1208 obj2 = klass(value2)
1209 self.assertEqual(obj1 == obj2, value1 == value2)
1210 self.assertEqual(obj1 != obj2, value1 != value2)
1211 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1212 obj1 = klass(value1, impl=tag1)
1213 obj2 = klass(value1, impl=tag2)
1214 self.assertEqual(obj1 == obj2, tag1 == tag2)
1215 self.assertEqual(obj1 != obj2, tag1 != tag2)
1217 @given(data_strategy())
1218 def test_call(self, d):
1219 for klass in (BitString, BitStringInherited):
1228 ) = d.draw(bit_string_values_strategy())
1231 schema = schema_initial
1233 value=value_initial,
1236 default=default_initial,
1237 optional=optional_initial or False,
1238 _decoded=_decoded_initial,
1248 ) = d.draw(bit_string_values_strategy(
1249 schema=schema_initial,
1250 do_expl=impl_initial is None,
1259 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1260 self.assertEqual(obj.expl_tag, expl or expl_initial)
1261 if obj.default is None:
1262 optional = optional_initial if optional is None else optional
1263 optional = False if optional is None else optional
1266 self.assertEqual(obj.optional, optional)
1267 self.assertEqual(obj.specs, obj_initial.specs)
1269 @given(bit_string_values_strategy())
1270 def test_copy(self, values):
1271 for klass in (BitString, BitStringInherited):
1272 _schema, value, impl, expl, default, optional, _decoded = values
1281 optional=optional or False,
1284 obj_copied = obj.copy()
1285 self.assert_copied_basic_fields(obj, obj_copied)
1286 self.assertEqual(obj.specs, obj_copied.specs)
1287 self.assertEqual(obj._value, obj_copied._value)
1291 integers(min_value=1).map(tag_encode),
1293 def test_stripped(self, value, tag_impl):
1294 obj = BitString(value, impl=tag_impl)
1295 with self.assertRaises(NotEnoughData):
1296 obj.decode(obj.encode()[:-1])
1300 integers(min_value=1).map(tag_ctxc),
1302 def test_stripped_expl(self, value, tag_expl):
1303 obj = BitString(value, expl=tag_expl)
1304 with self.assertRaises(NotEnoughData):
1305 obj.decode(obj.encode()[:-1])
1308 integers(min_value=31),
1309 integers(min_value=0),
1312 def test_bad_tag(self, tag, offset, decode_path):
1313 decode_path = tuple(str(i) for i in decode_path)
1314 with self.assertRaises(DecodeError) as err:
1316 tag_encode(tag)[:-1],
1318 decode_path=decode_path,
1321 self.assertEqual(err.exception.offset, offset)
1322 self.assertEqual(err.exception.decode_path, decode_path)
1325 integers(min_value=128),
1326 integers(min_value=0),
1329 def test_bad_len(self, l, offset, decode_path):
1330 decode_path = tuple(str(i) for i in decode_path)
1331 with self.assertRaises(DecodeError) as err:
1333 BitString.tag_default + len_encode(l)[:-1],
1335 decode_path=decode_path,
1338 self.assertEqual(err.exception.offset, offset)
1339 self.assertEqual(err.exception.decode_path, decode_path)
1341 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1342 @given(data_strategy())
1343 def test_symmetric(self, d):
1352 ) = d.draw(bit_string_values_strategy(value_required=True))
1353 tail_junk = d.draw(binary(max_size=5))
1354 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1355 offset = d.draw(integers(min_value=0))
1356 for klass in (BitString, BitStringInherited):
1367 self.assertFalse(obj.expled)
1368 obj_encoded = obj.encode()
1369 obj_expled = obj(value, expl=tag_expl)
1370 self.assertTrue(obj_expled.expled)
1373 obj_expled_encoded = obj_expled.encode()
1374 obj_decoded, tail = obj_expled.decode(
1375 obj_expled_encoded + tail_junk,
1380 self.assertEqual(tail, tail_junk)
1381 self.assertEqual(obj_decoded, obj_expled)
1382 self.assertNotEqual(obj_decoded, obj)
1383 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1384 self.assertEqual(bytes(obj_decoded), bytes(obj))
1385 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1386 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1387 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1389 obj_decoded.expl_llen,
1390 len(len_encode(len(obj_encoded))),
1392 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1393 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1396 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1398 self.assertEqual(obj_decoded.expl_offset, offset)
1399 if isinstance(value, tuple):
1400 self.assertSetEqual(set(value), set(obj_decoded.named))
1404 @given(integers(min_value=1, max_value=255))
1405 def test_bad_zero_value(self, pad_size):
1406 with self.assertRaises(DecodeError):
1407 BitString().decode(b"".join((
1408 BitString.tag_default,
1413 def test_go_vectors_invalid(self):
1419 with self.assertRaises(DecodeError):
1420 BitString().decode(b"".join((
1421 BitString.tag_default,
1426 def test_go_vectors_valid(self):
1427 obj, _ = BitString().decode(b"".join((
1428 BitString.tag_default,
1432 self.assertEqual(bytes(obj), b"")
1433 self.assertEqual(obj.bit_len, 0)
1435 obj, _ = BitString().decode(b"".join((
1436 BitString.tag_default,
1440 self.assertEqual(bytes(obj), b"\x00")
1441 self.assertEqual(obj.bit_len, 1)
1443 obj = BitString((16, b"\x82\x40"))
1444 self.assertTrue(obj[0])
1445 self.assertFalse(obj[1])
1446 self.assertTrue(obj[6])
1447 self.assertTrue(obj[9])
1448 self.assertFalse(obj[17])
1451 integers(min_value=1, max_value=30),
1454 binary(min_size=1, max_size=5),
1456 binary(min_size=1, max_size=5),
1464 lists(booleans(), min_size=1),
1466 def test_constructed(self, impl, chunk_inputs, chunk_last_bits):
1467 def chunk_constructed(contents):
1469 tag_encode(form=TagFormConstructed, num=3) +
1471 b"".join(BitString(content).encode() for content in contents) +
1475 payload_expected = b""
1476 bit_len_expected = 0
1477 for chunk_input in chunk_inputs:
1478 if isinstance(chunk_input, binary_type):
1479 chunks.append(BitString(chunk_input).encode())
1480 payload_expected += chunk_input
1481 bit_len_expected += len(chunk_input) * 8
1483 chunks.append(chunk_constructed(chunk_input))
1484 payload = b"".join(chunk_input)
1485 payload_expected += payload
1486 bit_len_expected += len(payload) * 8
1487 chunk_last = BitString("'%s'B" % "".join(
1488 "1" if bit else "0" for bit in chunk_last_bits
1490 payload_expected += bytes(chunk_last)
1491 bit_len_expected += chunk_last.bit_len
1492 encoded_indefinite = (
1493 tag_encode(form=TagFormConstructed, num=impl) +
1496 chunk_last.encode() +
1499 encoded_definite = (
1500 tag_encode(form=TagFormConstructed, num=impl) +
1501 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1505 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1506 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1507 for lenindef_expected, encoded in (
1508 (True, encoded_indefinite),
1509 (False, encoded_definite),
1511 obj, tail = BitString(impl=tag_encode(impl)).decode(
1512 encoded, ctx={"bered": True}
1514 self.assertSequenceEqual(tail, b"")
1515 self.assertEqual(obj.bit_len, bit_len_expected)
1516 self.assertSequenceEqual(bytes(obj), payload_expected)
1517 self.assertTrue(obj.bered)
1518 self.assertEqual(obj.lenindef, lenindef_expected)
1519 self.assertEqual(len(encoded), obj.tlvlen)
1521 def test_x690_vector(self):
1522 vector = BitString("'0A3B5F291CD'H")
1523 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1524 self.assertSequenceEqual(tail, b"")
1525 self.assertEqual(obj, vector)
1526 obj, tail = BitString().decode(
1527 hexdec("23800303000A3B0305045F291CD00000"),
1528 ctx={"bered": True},
1530 self.assertSequenceEqual(tail, b"")
1531 self.assertEqual(obj, vector)
1532 self.assertTrue(obj.bered)
1533 self.assertTrue(obj.lenindef)
1537 def octet_string_values_strategy(draw, do_expl=False):
1538 bound_min, bound_max = sorted(draw(sets(
1539 integers(min_value=0, max_value=1 << 7),
1543 value = draw(one_of(
1545 binary(min_size=bound_min, max_size=bound_max),
1547 default = draw(one_of(
1549 binary(min_size=bound_min, max_size=bound_max),
1552 if draw(booleans()):
1553 bounds = (bound_min, bound_max)
1557 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1559 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1560 optional = draw(one_of(none(), booleans()))
1562 draw(integers(min_value=0)),
1563 draw(integers(min_value=0)),
1564 draw(integers(min_value=0)),
1566 return (value, bounds, impl, expl, default, optional, _decoded)
1569 class OctetStringInherited(OctetString):
1573 class TestOctetString(CommonMixin, TestCase):
1574 base_klass = OctetString
1576 def test_invalid_value_type(self):
1577 with self.assertRaises(InvalidValueType) as err:
1578 OctetString(text_type(123))
1582 def test_optional(self, optional):
1583 obj = OctetString(default=OctetString(b""), optional=optional)
1584 self.assertTrue(obj.optional)
1587 def test_ready(self, value):
1589 self.assertFalse(obj.ready)
1592 with self.assertRaises(ObjNotReady) as err:
1595 obj = OctetString(value)
1596 self.assertTrue(obj.ready)
1600 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1601 def test_comparison(self, value1, value2, tag1, tag2):
1602 for klass in (OctetString, OctetStringInherited):
1603 obj1 = klass(value1)
1604 obj2 = klass(value2)
1605 self.assertEqual(obj1 == obj2, value1 == value2)
1606 self.assertEqual(obj1 != obj2, value1 != value2)
1607 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1608 obj1 = klass(value1, impl=tag1)
1609 obj2 = klass(value1, impl=tag2)
1610 self.assertEqual(obj1 == obj2, tag1 == tag2)
1611 self.assertEqual(obj1 != obj2, tag1 != tag2)
1613 @given(lists(binary()))
1614 def test_sorted_works(self, values):
1615 self.assertSequenceEqual(
1616 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1620 @given(data_strategy())
1621 def test_bounds_satisfied(self, d):
1622 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1623 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1624 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1625 OctetString(value=value, bounds=(bound_min, bound_max))
1627 @given(data_strategy())
1628 def test_bounds_unsatisfied(self, d):
1629 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1630 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1631 value = d.draw(binary(max_size=bound_min - 1))
1632 with self.assertRaises(BoundsError) as err:
1633 OctetString(value=value, bounds=(bound_min, bound_max))
1635 value = d.draw(binary(min_size=bound_max + 1))
1636 with self.assertRaises(BoundsError) as err:
1637 OctetString(value=value, bounds=(bound_min, bound_max))
1640 @given(data_strategy())
1641 def test_call(self, d):
1642 for klass in (OctetString, OctetStringInherited):
1651 ) = d.draw(octet_string_values_strategy())
1652 obj_initial = klass(
1658 optional_initial or False,
1669 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1670 if (default is None) and (obj_initial.default is not None):
1673 (bounds is None) and
1674 (value is not None) and
1675 (bounds_initial is not None) and
1676 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1680 (bounds is None) and
1681 (default is not None) and
1682 (bounds_initial is not None) and
1683 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1686 obj = obj_initial(value, bounds, impl, expl, default, optional)
1688 value_expected = default if value is None else value
1690 default_initial if value_expected is None
1693 self.assertEqual(obj, value_expected)
1694 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1695 self.assertEqual(obj.expl_tag, expl or expl_initial)
1698 default_initial if default is None else default,
1700 if obj.default is None:
1701 optional = optional_initial if optional is None else optional
1702 optional = False if optional is None else optional
1705 self.assertEqual(obj.optional, optional)
1707 (obj._bound_min, obj._bound_max),
1708 bounds or bounds_initial or (0, float("+inf")),
1711 @given(octet_string_values_strategy())
1712 def test_copy(self, values):
1713 for klass in (OctetString, OctetStringInherited):
1714 obj = klass(*values)
1715 obj_copied = obj.copy()
1716 self.assert_copied_basic_fields(obj, obj_copied)
1717 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1718 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1719 self.assertEqual(obj._value, obj_copied._value)
1723 integers(min_value=1).map(tag_encode),
1725 def test_stripped(self, value, tag_impl):
1726 obj = OctetString(value, impl=tag_impl)
1727 with self.assertRaises(NotEnoughData):
1728 obj.decode(obj.encode()[:-1])
1732 integers(min_value=1).map(tag_ctxc),
1734 def test_stripped_expl(self, value, tag_expl):
1735 obj = OctetString(value, expl=tag_expl)
1736 with self.assertRaises(NotEnoughData):
1737 obj.decode(obj.encode()[:-1])
1740 integers(min_value=31),
1741 integers(min_value=0),
1744 def test_bad_tag(self, tag, offset, decode_path):
1745 decode_path = tuple(str(i) for i in decode_path)
1746 with self.assertRaises(DecodeError) as err:
1747 OctetString().decode(
1748 tag_encode(tag)[:-1],
1750 decode_path=decode_path,
1753 self.assertEqual(err.exception.offset, offset)
1754 self.assertEqual(err.exception.decode_path, decode_path)
1757 integers(min_value=128),
1758 integers(min_value=0),
1761 def test_bad_len(self, l, offset, decode_path):
1762 decode_path = tuple(str(i) for i in decode_path)
1763 with self.assertRaises(DecodeError) as err:
1764 OctetString().decode(
1765 OctetString.tag_default + len_encode(l)[:-1],
1767 decode_path=decode_path,
1770 self.assertEqual(err.exception.offset, offset)
1771 self.assertEqual(err.exception.decode_path, decode_path)
1774 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1775 integers(min_value=0),
1778 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1779 decode_path = tuple(str(i) for i in decode_path)
1780 value, bound_min = list(sorted(ints))
1782 class String(OctetString):
1783 bounds = (bound_min, bound_min)
1784 with self.assertRaises(DecodeError) as err:
1786 OctetString(b"\x00" * value).encode(),
1788 decode_path=decode_path,
1791 self.assertEqual(err.exception.offset, offset)
1792 self.assertEqual(err.exception.decode_path, decode_path)
1794 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1796 octet_string_values_strategy(),
1798 integers(min_value=1).map(tag_ctxc),
1799 integers(min_value=0),
1802 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1803 for klass in (OctetString, OctetStringInherited):
1804 _, _, _, _, default, optional, _decoded = values
1813 self.assertFalse(obj.expled)
1814 obj_encoded = obj.encode()
1815 obj_expled = obj(value, expl=tag_expl)
1816 self.assertTrue(obj_expled.expled)
1819 obj_expled_encoded = obj_expled.encode()
1820 obj_decoded, tail = obj_expled.decode(
1821 obj_expled_encoded + tail_junk,
1826 self.assertEqual(tail, tail_junk)
1827 self.assertEqual(obj_decoded, obj_expled)
1828 self.assertNotEqual(obj_decoded, obj)
1829 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1830 self.assertEqual(bytes(obj_decoded), bytes(obj))
1831 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1832 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1833 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1835 obj_decoded.expl_llen,
1836 len(len_encode(len(obj_encoded))),
1838 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1839 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1842 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1844 self.assertEqual(obj_decoded.expl_offset, offset)
1847 integers(min_value=1, max_value=30),
1850 binary(min_size=1, max_size=5),
1852 binary(min_size=1, max_size=5),
1861 def test_constructed(self, impl, chunk_inputs):
1862 def chunk_constructed(contents):
1864 tag_encode(form=TagFormConstructed, num=4) +
1866 b"".join(OctetString(content).encode() for content in contents) +
1870 payload_expected = b""
1871 for chunk_input in chunk_inputs:
1872 if isinstance(chunk_input, binary_type):
1873 chunks.append(OctetString(chunk_input).encode())
1874 payload_expected += chunk_input
1876 chunks.append(chunk_constructed(chunk_input))
1877 payload = b"".join(chunk_input)
1878 payload_expected += payload
1879 encoded_indefinite = (
1880 tag_encode(form=TagFormConstructed, num=impl) +
1885 encoded_definite = (
1886 tag_encode(form=TagFormConstructed, num=impl) +
1887 len_encode(len(b"".join(chunks))) +
1890 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1891 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
1892 for lenindef_expected, encoded in (
1893 (True, encoded_indefinite),
1894 (False, encoded_definite),
1896 obj, tail = OctetString(impl=tag_encode(impl)).decode(
1897 encoded, ctx={"bered": True}
1899 self.assertSequenceEqual(tail, b"")
1900 self.assertSequenceEqual(bytes(obj), payload_expected)
1901 self.assertTrue(obj.bered)
1902 self.assertEqual(obj.lenindef, lenindef_expected)
1903 self.assertEqual(len(encoded), obj.tlvlen)
1907 def null_values_strategy(draw, do_expl=False):
1911 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1913 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1914 optional = draw(one_of(none(), booleans()))
1916 draw(integers(min_value=0)),
1917 draw(integers(min_value=0)),
1918 draw(integers(min_value=0)),
1920 return (impl, expl, optional, _decoded)
1923 class NullInherited(Null):
1927 class TestNull(CommonMixin, TestCase):
1930 def test_ready(self):
1932 self.assertTrue(obj.ready)
1936 @given(binary(), binary())
1937 def test_comparison(self, tag1, tag2):
1938 for klass in (Null, NullInherited):
1939 obj1 = klass(impl=tag1)
1940 obj2 = klass(impl=tag2)
1941 self.assertEqual(obj1 == obj2, tag1 == tag2)
1942 self.assertEqual(obj1 != obj2, tag1 != tag2)
1943 self.assertNotEqual(obj1, tag2)
1945 @given(data_strategy())
1946 def test_call(self, d):
1947 for klass in (Null, NullInherited):
1953 ) = d.draw(null_values_strategy())
1954 obj_initial = klass(
1957 optional=optional_initial or False,
1958 _decoded=_decoded_initial,
1965 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
1966 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1967 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1968 self.assertEqual(obj.expl_tag, expl or expl_initial)
1969 optional = optional_initial if optional is None else optional
1970 optional = False if optional is None else optional
1971 self.assertEqual(obj.optional, optional)
1973 @given(null_values_strategy())
1974 def test_copy(self, values):
1975 for klass in (Null, NullInherited):
1976 impl, expl, optional, _decoded = values
1980 optional=optional or False,
1983 obj_copied = obj.copy()
1984 self.assert_copied_basic_fields(obj, obj_copied)
1986 @given(integers(min_value=1).map(tag_encode))
1987 def test_stripped(self, tag_impl):
1988 obj = Null(impl=tag_impl)
1989 with self.assertRaises(NotEnoughData):
1990 obj.decode(obj.encode()[:-1])
1992 @given(integers(min_value=1).map(tag_ctxc))
1993 def test_stripped_expl(self, tag_expl):
1994 obj = Null(expl=tag_expl)
1995 with self.assertRaises(NotEnoughData):
1996 obj.decode(obj.encode()[:-1])
1999 integers(min_value=31),
2000 integers(min_value=0),
2003 def test_bad_tag(self, tag, offset, decode_path):
2004 decode_path = tuple(str(i) for i in decode_path)
2005 with self.assertRaises(DecodeError) as err:
2007 tag_encode(tag)[:-1],
2009 decode_path=decode_path,
2012 self.assertEqual(err.exception.offset, offset)
2013 self.assertEqual(err.exception.decode_path, decode_path)
2016 integers(min_value=128),
2017 integers(min_value=0),
2020 def test_bad_len(self, l, offset, decode_path):
2021 decode_path = tuple(str(i) for i in decode_path)
2022 with self.assertRaises(DecodeError) as err:
2024 Null.tag_default + len_encode(l)[:-1],
2026 decode_path=decode_path,
2029 self.assertEqual(err.exception.offset, offset)
2030 self.assertEqual(err.exception.decode_path, decode_path)
2032 @given(binary(min_size=1))
2033 def test_tag_mismatch(self, impl):
2034 assume(impl != Null.tag_default)
2035 with self.assertRaises(TagMismatch):
2036 Null(impl=impl).decode(Null().encode())
2039 null_values_strategy(),
2040 integers(min_value=1).map(tag_ctxc),
2041 integers(min_value=0),
2044 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2045 for klass in (Null, NullInherited):
2046 _, _, optional, _decoded = values
2047 obj = klass(optional=optional, _decoded=_decoded)
2050 self.assertFalse(obj.expled)
2051 obj_encoded = obj.encode()
2052 obj_expled = obj(expl=tag_expl)
2053 self.assertTrue(obj_expled.expled)
2056 obj_expled_encoded = obj_expled.encode()
2057 obj_decoded, tail = obj_expled.decode(
2058 obj_expled_encoded + tail_junk,
2063 self.assertEqual(tail, tail_junk)
2064 self.assertEqual(obj_decoded, obj_expled)
2065 self.assertNotEqual(obj_decoded, obj)
2066 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2067 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2068 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2070 obj_decoded.expl_llen,
2071 len(len_encode(len(obj_encoded))),
2073 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2074 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2077 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2079 self.assertEqual(obj_decoded.expl_offset, offset)
2081 @given(integers(min_value=1))
2082 def test_invalid_len(self, l):
2083 with self.assertRaises(InvalidLength):
2084 Null().decode(b"".join((
2091 def oid_strategy(draw):
2092 first_arc = draw(integers(min_value=0, max_value=2))
2094 if first_arc in (0, 1):
2095 second_arc = draw(integers(min_value=0, max_value=39))
2097 second_arc = draw(integers(min_value=0))
2098 other_arcs = draw(lists(integers(min_value=0)))
2099 return tuple([first_arc, second_arc] + other_arcs)
2103 def oid_values_strategy(draw, do_expl=False):
2104 value = draw(one_of(none(), oid_strategy()))
2108 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2110 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2111 default = draw(one_of(none(), oid_strategy()))
2112 optional = draw(one_of(none(), booleans()))
2114 draw(integers(min_value=0)),
2115 draw(integers(min_value=0)),
2116 draw(integers(min_value=0)),
2118 return (value, impl, expl, default, optional, _decoded)
2121 class ObjectIdentifierInherited(ObjectIdentifier):
2125 class TestObjectIdentifier(CommonMixin, TestCase):
2126 base_klass = ObjectIdentifier
2128 def test_invalid_value_type(self):
2129 with self.assertRaises(InvalidValueType) as err:
2130 ObjectIdentifier(123)
2134 def test_optional(self, optional):
2135 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2136 self.assertTrue(obj.optional)
2138 @given(oid_strategy())
2139 def test_ready(self, value):
2140 obj = ObjectIdentifier()
2141 self.assertFalse(obj.ready)
2144 with self.assertRaises(ObjNotReady) as err:
2147 obj = ObjectIdentifier(value)
2148 self.assertTrue(obj.ready)
2153 @given(oid_strategy(), oid_strategy(), binary(), binary())
2154 def test_comparison(self, value1, value2, tag1, tag2):
2155 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2156 obj1 = klass(value1)
2157 obj2 = klass(value2)
2158 self.assertEqual(obj1 == obj2, value1 == value2)
2159 self.assertEqual(obj1 != obj2, value1 != value2)
2160 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2161 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2162 obj1 = klass(value1, impl=tag1)
2163 obj2 = klass(value1, impl=tag2)
2164 self.assertEqual(obj1 == obj2, tag1 == tag2)
2165 self.assertEqual(obj1 != obj2, tag1 != tag2)
2167 @given(lists(oid_strategy()))
2168 def test_sorted_works(self, values):
2169 self.assertSequenceEqual(
2170 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2174 @given(data_strategy())
2175 def test_call(self, d):
2176 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2184 ) = d.draw(oid_values_strategy())
2185 obj_initial = klass(
2186 value=value_initial,
2189 default=default_initial,
2190 optional=optional_initial or False,
2191 _decoded=_decoded_initial,
2200 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2209 value_expected = default if value is None else value
2211 default_initial if value_expected is None
2214 self.assertEqual(obj, value_expected)
2215 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2216 self.assertEqual(obj.expl_tag, expl or expl_initial)
2219 default_initial if default is None else default,
2221 if obj.default is None:
2222 optional = optional_initial if optional is None else optional
2223 optional = False if optional is None else optional
2226 self.assertEqual(obj.optional, optional)
2228 @given(oid_values_strategy())
2229 def test_copy(self, values):
2230 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2247 obj_copied = obj.copy()
2248 self.assert_copied_basic_fields(obj, obj_copied)
2249 self.assertEqual(obj._value, obj_copied._value)
2251 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2254 integers(min_value=1).map(tag_encode),
2256 def test_stripped(self, value, tag_impl):
2257 obj = ObjectIdentifier(value, impl=tag_impl)
2258 with self.assertRaises(NotEnoughData):
2259 obj.decode(obj.encode()[:-1])
2263 integers(min_value=1).map(tag_ctxc),
2265 def test_stripped_expl(self, value, tag_expl):
2266 obj = ObjectIdentifier(value, expl=tag_expl)
2267 with self.assertRaises(NotEnoughData):
2268 obj.decode(obj.encode()[:-1])
2271 integers(min_value=31),
2272 integers(min_value=0),
2275 def test_bad_tag(self, tag, offset, decode_path):
2276 decode_path = tuple(str(i) for i in decode_path)
2277 with self.assertRaises(DecodeError) as err:
2278 ObjectIdentifier().decode(
2279 tag_encode(tag)[:-1],
2281 decode_path=decode_path,
2284 self.assertEqual(err.exception.offset, offset)
2285 self.assertEqual(err.exception.decode_path, decode_path)
2288 integers(min_value=128),
2289 integers(min_value=0),
2292 def test_bad_len(self, l, offset, decode_path):
2293 decode_path = tuple(str(i) for i in decode_path)
2294 with self.assertRaises(DecodeError) as err:
2295 ObjectIdentifier().decode(
2296 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2298 decode_path=decode_path,
2301 self.assertEqual(err.exception.offset, offset)
2302 self.assertEqual(err.exception.decode_path, decode_path)
2304 def test_zero_oid(self):
2305 with self.assertRaises(NotEnoughData):
2306 ObjectIdentifier().decode(
2307 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2310 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2311 @given(oid_strategy())
2312 def test_unfinished_oid(self, value):
2313 assume(list(value)[-1] > 255)
2314 obj_encoded = ObjectIdentifier(value).encode()
2315 obj, _ = ObjectIdentifier().decode(obj_encoded)
2316 data = obj_encoded[obj.tlen + obj.llen:-1]
2318 ObjectIdentifier.tag_default,
2319 len_encode(len(data)),
2322 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2325 @given(integers(min_value=0))
2326 def test_invalid_short(self, value):
2327 with self.assertRaises(InvalidOID):
2328 ObjectIdentifier((value,))
2329 with self.assertRaises(InvalidOID):
2330 ObjectIdentifier("%d" % value)
2332 @given(integers(min_value=3), integers(min_value=0))
2333 def test_invalid_first_arc(self, first_arc, second_arc):
2334 with self.assertRaises(InvalidOID):
2335 ObjectIdentifier((first_arc, second_arc))
2336 with self.assertRaises(InvalidOID):
2337 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2339 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2340 def test_invalid_second_arc(self, first_arc, second_arc):
2341 with self.assertRaises(InvalidOID):
2342 ObjectIdentifier((first_arc, second_arc))
2343 with self.assertRaises(InvalidOID):
2344 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2346 @given(text(alphabet=ascii_letters + ".", min_size=1))
2347 def test_junk(self, oid):
2348 with self.assertRaises(InvalidOID):
2349 ObjectIdentifier(oid)
2351 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2352 @given(oid_strategy())
2353 def test_validness(self, oid):
2354 obj = ObjectIdentifier(oid)
2355 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2360 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2362 oid_values_strategy(),
2364 integers(min_value=1).map(tag_ctxc),
2365 integers(min_value=0),
2368 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2369 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2370 _, _, _, default, optional, _decoded = values
2379 self.assertFalse(obj.expled)
2380 obj_encoded = obj.encode()
2381 obj_expled = obj(value, expl=tag_expl)
2382 self.assertTrue(obj_expled.expled)
2385 obj_expled_encoded = obj_expled.encode()
2386 obj_decoded, tail = obj_expled.decode(
2387 obj_expled_encoded + tail_junk,
2392 self.assertEqual(tail, tail_junk)
2393 self.assertEqual(obj_decoded, obj_expled)
2394 self.assertNotEqual(obj_decoded, obj)
2395 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2396 self.assertEqual(tuple(obj_decoded), tuple(obj))
2397 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2398 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2399 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2401 obj_decoded.expl_llen,
2402 len(len_encode(len(obj_encoded))),
2404 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2405 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2408 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2410 self.assertEqual(obj_decoded.expl_offset, offset)
2413 oid_strategy().map(ObjectIdentifier),
2414 oid_strategy().map(ObjectIdentifier),
2416 def test_add(self, oid1, oid2):
2417 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2418 for oid_to_add in (oid2, tuple(oid2)):
2419 self.assertEqual(oid1 + oid_to_add, oid_expect)
2420 with self.assertRaises(InvalidValueType):
2423 def test_go_vectors_valid(self):
2424 for data, expect in (
2426 (b"\x55\x02", (2, 5, 2)),
2427 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2428 (b"\x81\x34\x03", (2, 100, 3)),
2431 ObjectIdentifier().decode(b"".join((
2432 ObjectIdentifier.tag_default,
2433 len_encode(len(data)),
2439 def test_go_vectors_invalid(self):
2440 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2441 with self.assertRaises(DecodeError):
2442 ObjectIdentifier().decode(b"".join((
2443 Integer.tag_default,
2444 len_encode(len(data)),
2448 def test_x690_vector(self):
2450 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2451 ObjectIdentifier((2, 999, 3)),
2456 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2458 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2459 values = list(draw(sets(
2461 min_size=len(schema),
2462 max_size=len(schema),
2464 schema = list(zip(schema, values))
2465 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2469 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2471 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2472 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2473 optional = draw(one_of(none(), booleans()))
2475 draw(integers(min_value=0)),
2476 draw(integers(min_value=0)),
2477 draw(integers(min_value=0)),
2479 return (schema, value, impl, expl, default, optional, _decoded)
2482 class TestEnumerated(CommonMixin, TestCase):
2483 class EWhatever(Enumerated):
2484 schema = (("whatever", 0),)
2486 base_klass = EWhatever
2488 def test_schema_required(self):
2489 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2492 def test_invalid_value_type(self):
2493 with self.assertRaises(InvalidValueType) as err:
2494 self.base_klass((1, 2))
2497 @given(sets(text_letters(), min_size=2))
2498 def test_unknown_name(self, schema_input):
2499 missing = schema_input.pop()
2501 class E(Enumerated):
2502 schema = [(n, 123) for n in schema_input]
2503 with self.assertRaises(ObjUnknown) as err:
2508 sets(text_letters(), min_size=2),
2509 sets(integers(), min_size=2),
2511 def test_unknown_value(self, schema_input, values_input):
2513 missing_value = values_input.pop()
2514 _input = list(zip(schema_input, values_input))
2516 class E(Enumerated):
2518 with self.assertRaises(DecodeError) as err:
2523 def test_optional(self, optional):
2524 obj = self.base_klass(default="whatever", optional=optional)
2525 self.assertTrue(obj.optional)
2527 def test_ready(self):
2528 obj = self.base_klass()
2529 self.assertFalse(obj.ready)
2532 with self.assertRaises(ObjNotReady) as err:
2535 obj = self.base_klass("whatever")
2536 self.assertTrue(obj.ready)
2540 @given(integers(), integers(), binary(), binary())
2541 def test_comparison(self, value1, value2, tag1, tag2):
2542 class E(Enumerated):
2544 ("whatever0", value1),
2545 ("whatever1", value2),
2548 class EInherited(E):
2550 for klass in (E, EInherited):
2551 obj1 = klass(value1)
2552 obj2 = klass(value2)
2553 self.assertEqual(obj1 == obj2, value1 == value2)
2554 self.assertEqual(obj1 != obj2, value1 != value2)
2555 self.assertEqual(obj1 == int(obj2), value1 == value2)
2556 obj1 = klass(value1, impl=tag1)
2557 obj2 = klass(value1, impl=tag2)
2558 self.assertEqual(obj1 == obj2, tag1 == tag2)
2559 self.assertEqual(obj1 != obj2, tag1 != tag2)
2561 @given(data_strategy())
2562 def test_call(self, d):
2571 ) = d.draw(enumerated_values_strategy())
2573 class E(Enumerated):
2574 schema = schema_initial
2576 value=value_initial,
2579 default=default_initial,
2580 optional=optional_initial or False,
2581 _decoded=_decoded_initial,
2591 ) = d.draw(enumerated_values_strategy(
2592 schema=schema_initial,
2593 do_expl=impl_initial is None,
2603 value_expected = default if value is None else value
2605 default_initial if value_expected is None
2610 dict(schema_initial).get(value_expected, value_expected),
2612 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2613 self.assertEqual(obj.expl_tag, expl or expl_initial)
2616 default_initial if default is None else default,
2618 if obj.default is None:
2619 optional = optional_initial if optional is None else optional
2620 optional = False if optional is None else optional
2623 self.assertEqual(obj.optional, optional)
2624 self.assertEqual(obj.specs, dict(schema_initial))
2626 @given(enumerated_values_strategy())
2627 def test_copy(self, values):
2628 schema_input, value, impl, expl, default, optional, _decoded = values
2630 class E(Enumerated):
2631 schema = schema_input
2640 obj_copied = obj.copy()
2641 self.assert_copied_basic_fields(obj, obj_copied)
2642 self.assertEqual(obj.specs, obj_copied.specs)
2644 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2645 @given(data_strategy())
2646 def test_symmetric(self, d):
2647 schema_input, _, _, _, default, optional, _decoded = d.draw(
2648 enumerated_values_strategy(),
2650 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2651 offset = d.draw(integers(min_value=0))
2652 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2653 tail_junk = d.draw(binary(max_size=5))
2655 class E(Enumerated):
2656 schema = schema_input
2665 self.assertFalse(obj.expled)
2666 obj_encoded = obj.encode()
2667 obj_expled = obj(value, expl=tag_expl)
2668 self.assertTrue(obj_expled.expled)
2671 obj_expled_encoded = obj_expled.encode()
2672 obj_decoded, tail = obj_expled.decode(
2673 obj_expled_encoded + tail_junk,
2678 self.assertEqual(tail, tail_junk)
2679 self.assertEqual(obj_decoded, obj_expled)
2680 self.assertNotEqual(obj_decoded, obj)
2681 self.assertEqual(int(obj_decoded), int(obj_expled))
2682 self.assertEqual(int(obj_decoded), int(obj))
2683 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2684 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2685 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2687 obj_decoded.expl_llen,
2688 len(len_encode(len(obj_encoded))),
2690 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2691 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2694 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2696 self.assertEqual(obj_decoded.expl_offset, offset)
2700 def string_values_strategy(draw, alphabet, do_expl=False):
2701 bound_min, bound_max = sorted(draw(sets(
2702 integers(min_value=0, max_value=1 << 7),
2706 value = draw(one_of(
2708 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2710 default = draw(one_of(
2712 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2715 if draw(booleans()):
2716 bounds = (bound_min, bound_max)
2720 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2722 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2723 optional = draw(one_of(none(), booleans()))
2725 draw(integers(min_value=0)),
2726 draw(integers(min_value=0)),
2727 draw(integers(min_value=0)),
2729 return (value, bounds, impl, expl, default, optional, _decoded)
2732 class StringMixin(object):
2733 def test_invalid_value_type(self):
2734 with self.assertRaises(InvalidValueType) as err:
2735 self.base_klass((1, 2))
2738 def text_alphabet(self):
2739 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2740 return printable + whitespace
2744 def test_optional(self, optional):
2745 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2746 self.assertTrue(obj.optional)
2748 @given(data_strategy())
2749 def test_ready(self, d):
2750 obj = self.base_klass()
2751 self.assertFalse(obj.ready)
2755 with self.assertRaises(ObjNotReady) as err:
2758 value = d.draw(text(alphabet=self.text_alphabet()))
2759 obj = self.base_klass(value)
2760 self.assertTrue(obj.ready)
2765 @given(data_strategy())
2766 def test_comparison(self, d):
2767 value1 = d.draw(text(alphabet=self.text_alphabet()))
2768 value2 = d.draw(text(alphabet=self.text_alphabet()))
2769 tag1 = d.draw(binary(min_size=1))
2770 tag2 = d.draw(binary(min_size=1))
2771 obj1 = self.base_klass(value1)
2772 obj2 = self.base_klass(value2)
2773 self.assertEqual(obj1 == obj2, value1 == value2)
2774 self.assertEqual(obj1 != obj2, value1 != value2)
2775 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2776 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2777 obj1 = self.base_klass(value1, impl=tag1)
2778 obj2 = self.base_klass(value1, impl=tag2)
2779 self.assertEqual(obj1 == obj2, tag1 == tag2)
2780 self.assertEqual(obj1 != obj2, tag1 != tag2)
2782 @given(data_strategy())
2783 def test_bounds_satisfied(self, d):
2784 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2785 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2786 value = d.draw(text(
2787 alphabet=self.text_alphabet(),
2791 self.base_klass(value=value, bounds=(bound_min, bound_max))
2793 @given(data_strategy())
2794 def test_bounds_unsatisfied(self, d):
2795 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2796 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2797 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2798 with self.assertRaises(BoundsError) as err:
2799 self.base_klass(value=value, bounds=(bound_min, bound_max))
2801 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2802 with self.assertRaises(BoundsError) as err:
2803 self.base_klass(value=value, bounds=(bound_min, bound_max))
2806 @given(data_strategy())
2807 def test_call(self, d):
2816 ) = d.draw(string_values_strategy(self.text_alphabet()))
2817 obj_initial = self.base_klass(
2823 optional_initial or False,
2834 ) = d.draw(string_values_strategy(
2835 self.text_alphabet(),
2836 do_expl=impl_initial is None,
2838 if (default is None) and (obj_initial.default is not None):
2841 (bounds is None) and
2842 (value is not None) and
2843 (bounds_initial is not None) and
2844 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2848 (bounds is None) and
2849 (default is not None) and
2850 (bounds_initial is not None) and
2851 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2854 obj = obj_initial(value, bounds, impl, expl, default, optional)
2856 value_expected = default if value is None else value
2858 default_initial if value_expected is None
2861 self.assertEqual(obj, value_expected)
2862 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2863 self.assertEqual(obj.expl_tag, expl or expl_initial)
2866 default_initial if default is None else default,
2868 if obj.default is None:
2869 optional = optional_initial if optional is None else optional
2870 optional = False if optional is None else optional
2873 self.assertEqual(obj.optional, optional)
2875 (obj._bound_min, obj._bound_max),
2876 bounds or bounds_initial or (0, float("+inf")),
2879 @given(data_strategy())
2880 def test_copy(self, d):
2881 values = d.draw(string_values_strategy(self.text_alphabet()))
2882 obj = self.base_klass(*values)
2883 obj_copied = obj.copy()
2884 self.assert_copied_basic_fields(obj, obj_copied)
2885 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2886 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2887 self.assertEqual(obj._value, obj_copied._value)
2889 @given(data_strategy())
2890 def test_stripped(self, d):
2891 value = d.draw(text(alphabet=self.text_alphabet()))
2892 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2893 obj = self.base_klass(value, impl=tag_impl)
2894 with self.assertRaises(NotEnoughData):
2895 obj.decode(obj.encode()[:-1])
2897 @given(data_strategy())
2898 def test_stripped_expl(self, d):
2899 value = d.draw(text(alphabet=self.text_alphabet()))
2900 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2901 obj = self.base_klass(value, expl=tag_expl)
2902 with self.assertRaises(NotEnoughData):
2903 obj.decode(obj.encode()[:-1])
2906 integers(min_value=31),
2907 integers(min_value=0),
2910 def test_bad_tag(self, tag, offset, decode_path):
2911 decode_path = tuple(str(i) for i in decode_path)
2912 with self.assertRaises(DecodeError) as err:
2913 self.base_klass().decode(
2914 tag_encode(tag)[:-1],
2916 decode_path=decode_path,
2919 self.assertEqual(err.exception.offset, offset)
2920 self.assertEqual(err.exception.decode_path, decode_path)
2923 integers(min_value=128),
2924 integers(min_value=0),
2927 def test_bad_len(self, l, offset, decode_path):
2928 decode_path = tuple(str(i) for i in decode_path)
2929 with self.assertRaises(DecodeError) as err:
2930 self.base_klass().decode(
2931 self.base_klass.tag_default + len_encode(l)[:-1],
2933 decode_path=decode_path,
2936 self.assertEqual(err.exception.offset, offset)
2937 self.assertEqual(err.exception.decode_path, decode_path)
2940 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2941 integers(min_value=0),
2944 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2945 decode_path = tuple(str(i) for i in decode_path)
2946 value, bound_min = list(sorted(ints))
2948 class String(self.base_klass):
2949 # Multiply this value by four, to satisfy UTF-32 bounds
2950 # (4 bytes per character) validation
2951 bounds = (bound_min * 4, bound_min * 4)
2952 with self.assertRaises(DecodeError) as err:
2954 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2956 decode_path=decode_path,
2959 self.assertEqual(err.exception.offset, offset)
2960 self.assertEqual(err.exception.decode_path, decode_path)
2962 @given(data_strategy())
2963 def test_symmetric(self, d):
2964 values = d.draw(string_values_strategy(self.text_alphabet()))
2965 value = d.draw(text(alphabet=self.text_alphabet()))
2966 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2967 offset = d.draw(integers(min_value=0))
2968 tail_junk = d.draw(binary(max_size=5))
2969 _, _, _, _, default, optional, _decoded = values
2970 obj = self.base_klass(
2978 self.assertFalse(obj.expled)
2979 obj_encoded = obj.encode()
2980 obj_expled = obj(value, expl=tag_expl)
2981 self.assertTrue(obj_expled.expled)
2984 obj_expled_encoded = obj_expled.encode()
2985 obj_decoded, tail = obj_expled.decode(
2986 obj_expled_encoded + tail_junk,
2991 self.assertEqual(tail, tail_junk)
2992 self.assertEqual(obj_decoded, obj_expled)
2993 self.assertNotEqual(obj_decoded, obj)
2994 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2995 self.assertEqual(bytes(obj_decoded), bytes(obj))
2996 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2997 self.assertEqual(text_type(obj_decoded), text_type(obj))
2998 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2999 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3000 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3002 obj_decoded.expl_llen,
3003 len(len_encode(len(obj_encoded))),
3005 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3006 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3009 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3011 self.assertEqual(obj_decoded.expl_offset, offset)
3014 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3015 base_klass = UTF8String
3018 class UnicodeDecodeErrorMixin(object):
3020 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3024 def test_unicode_decode_error(self, cyrillic_text):
3025 with self.assertRaises(DecodeError):
3026 self.base_klass(cyrillic_text)
3029 class TestNumericString(StringMixin, CommonMixin, TestCase):
3030 base_klass = NumericString
3032 def text_alphabet(self):
3035 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3036 def test_non_numeric(self, cyrillic_text):
3037 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3038 self.base_klass(cyrillic_text)
3041 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3042 integers(min_value=0),
3045 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3046 decode_path = tuple(str(i) for i in decode_path)
3047 value, bound_min = list(sorted(ints))
3049 class String(self.base_klass):
3050 bounds = (bound_min, bound_min)
3051 with self.assertRaises(DecodeError) as err:
3053 self.base_klass(b"1" * value).encode(),
3055 decode_path=decode_path,
3058 self.assertEqual(err.exception.offset, offset)
3059 self.assertEqual(err.exception.decode_path, decode_path)
3062 class TestPrintableString(
3063 UnicodeDecodeErrorMixin,
3068 base_klass = PrintableString
3071 class TestTeletexString(
3072 UnicodeDecodeErrorMixin,
3077 base_klass = TeletexString
3080 class TestVideotexString(
3081 UnicodeDecodeErrorMixin,
3086 base_klass = VideotexString
3089 class TestIA5String(
3090 UnicodeDecodeErrorMixin,
3095 base_klass = IA5String
3098 class TestGraphicString(
3099 UnicodeDecodeErrorMixin,
3104 base_klass = GraphicString
3107 class TestVisibleString(
3108 UnicodeDecodeErrorMixin,
3113 base_klass = VisibleString
3115 def test_x690_vector(self):
3116 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3117 self.assertSequenceEqual(tail, b"")
3118 self.assertEqual(str(obj), "Jones")
3119 self.assertFalse(obj.bered)
3120 self.assertFalse(obj.lenindef)
3122 obj, tail = VisibleString().decode(
3123 hexdec("3A0904034A6F6E04026573"),
3124 ctx={"bered": True},
3126 self.assertSequenceEqual(tail, b"")
3127 self.assertEqual(str(obj), "Jones")
3128 self.assertTrue(obj.bered)
3129 self.assertFalse(obj.lenindef)
3131 obj, tail = VisibleString().decode(
3132 hexdec("3A8004034A6F6E040265730000"),
3133 ctx={"bered": True},
3135 self.assertSequenceEqual(tail, b"")
3136 self.assertEqual(str(obj), "Jones")
3137 self.assertTrue(obj.bered)
3138 self.assertTrue(obj.lenindef)
3141 class TestGeneralString(
3142 UnicodeDecodeErrorMixin,
3147 base_klass = GeneralString
3150 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3151 base_klass = UniversalString
3154 class TestBMPString(StringMixin, CommonMixin, TestCase):
3155 base_klass = BMPString
3159 def generalized_time_values_strategy(
3167 if draw(booleans()):
3168 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3170 value = value.replace(microsecond=0)
3172 if draw(booleans()):
3173 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3175 default = default.replace(microsecond=0)
3179 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3181 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3182 optional = draw(one_of(none(), booleans()))
3184 draw(integers(min_value=0)),
3185 draw(integers(min_value=0)),
3186 draw(integers(min_value=0)),
3188 return (value, impl, expl, default, optional, _decoded)
3191 class TimeMixin(object):
3192 def test_invalid_value_type(self):
3193 with self.assertRaises(InvalidValueType) as err:
3194 self.base_klass(datetime.now().timetuple())
3197 @given(data_strategy())
3198 def test_optional(self, d):
3199 default = d.draw(datetimes(
3200 min_value=self.min_datetime,
3201 max_value=self.max_datetime,
3203 optional = d.draw(booleans())
3204 obj = self.base_klass(default=default, optional=optional)
3205 self.assertTrue(obj.optional)
3207 @given(data_strategy())
3208 def test_ready(self, d):
3209 obj = self.base_klass()
3210 self.assertFalse(obj.ready)
3213 with self.assertRaises(ObjNotReady) as err:
3216 value = d.draw(datetimes(min_value=self.min_datetime))
3217 obj = self.base_klass(value)
3218 self.assertTrue(obj.ready)
3222 @given(data_strategy())
3223 def test_comparison(self, d):
3224 value1 = d.draw(datetimes(
3225 min_value=self.min_datetime,
3226 max_value=self.max_datetime,
3228 value2 = d.draw(datetimes(
3229 min_value=self.min_datetime,
3230 max_value=self.max_datetime,
3232 tag1 = d.draw(binary(min_size=1))
3233 tag2 = d.draw(binary(min_size=1))
3235 value1 = value1.replace(microsecond=0)
3236 value2 = value2.replace(microsecond=0)
3237 obj1 = self.base_klass(value1)
3238 obj2 = self.base_klass(value2)
3239 self.assertEqual(obj1 == obj2, value1 == value2)
3240 self.assertEqual(obj1 != obj2, value1 != value2)
3241 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3242 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3243 obj1 = self.base_klass(value1, impl=tag1)
3244 obj2 = self.base_klass(value1, impl=tag2)
3245 self.assertEqual(obj1 == obj2, tag1 == tag2)
3246 self.assertEqual(obj1 != obj2, tag1 != tag2)
3248 @given(data_strategy())
3249 def test_call(self, d):
3257 ) = d.draw(generalized_time_values_strategy(
3258 min_datetime=self.min_datetime,
3259 max_datetime=self.max_datetime,
3260 omit_ms=self.omit_ms,
3262 obj_initial = self.base_klass(
3263 value=value_initial,
3266 default=default_initial,
3267 optional=optional_initial or False,
3268 _decoded=_decoded_initial,
3277 ) = d.draw(generalized_time_values_strategy(
3278 min_datetime=self.min_datetime,
3279 max_datetime=self.max_datetime,
3280 omit_ms=self.omit_ms,
3281 do_expl=impl_initial is None,
3291 value_expected = default if value is None else value
3293 default_initial if value_expected is None
3296 self.assertEqual(obj, value_expected)
3297 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3298 self.assertEqual(obj.expl_tag, expl or expl_initial)
3301 default_initial if default is None else default,
3303 if obj.default is None:
3304 optional = optional_initial if optional is None else optional
3305 optional = False if optional is None else optional
3308 self.assertEqual(obj.optional, optional)
3310 @given(data_strategy())
3311 def test_copy(self, d):
3312 values = d.draw(generalized_time_values_strategy(
3313 min_datetime=self.min_datetime,
3314 max_datetime=self.max_datetime,
3316 obj = self.base_klass(*values)
3317 obj_copied = obj.copy()
3318 self.assert_copied_basic_fields(obj, obj_copied)
3319 self.assertEqual(obj._value, obj_copied._value)
3321 @given(data_strategy())
3322 def test_stripped(self, d):
3323 value = d.draw(datetimes(
3324 min_value=self.min_datetime,
3325 max_value=self.max_datetime,
3327 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3328 obj = self.base_klass(value, impl=tag_impl)
3329 with self.assertRaises(NotEnoughData):
3330 obj.decode(obj.encode()[:-1])
3332 @given(data_strategy())
3333 def test_stripped_expl(self, d):
3334 value = d.draw(datetimes(
3335 min_value=self.min_datetime,
3336 max_value=self.max_datetime,
3338 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3339 obj = self.base_klass(value, expl=tag_expl)
3340 with self.assertRaises(NotEnoughData):
3341 obj.decode(obj.encode()[:-1])
3343 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3344 @given(data_strategy())
3345 def test_symmetric(self, d):
3346 values = d.draw(generalized_time_values_strategy(
3347 min_datetime=self.min_datetime,
3348 max_datetime=self.max_datetime,
3350 value = d.draw(datetimes(
3351 min_value=self.min_datetime,
3352 max_value=self.max_datetime,
3354 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3355 offset = d.draw(integers(min_value=0))
3356 tail_junk = d.draw(binary(max_size=5))
3357 _, _, _, default, optional, _decoded = values
3358 obj = self.base_klass(
3366 self.assertFalse(obj.expled)
3367 obj_encoded = obj.encode()
3368 obj_expled = obj(value, expl=tag_expl)
3369 self.assertTrue(obj_expled.expled)
3372 obj_expled_encoded = obj_expled.encode()
3373 obj_decoded, tail = obj_expled.decode(
3374 obj_expled_encoded + tail_junk,
3379 self.assertEqual(tail, tail_junk)
3380 self.assertEqual(obj_decoded, obj_expled)
3381 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3382 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3383 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3384 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3385 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3387 obj_decoded.expl_llen,
3388 len(len_encode(len(obj_encoded))),
3390 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3391 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3394 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3396 self.assertEqual(obj_decoded.expl_offset, offset)
3399 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3400 base_klass = GeneralizedTime
3402 min_datetime = datetime(1900, 1, 1)
3403 max_datetime = datetime(9999, 12, 31)
3405 def test_go_vectors_invalid(self):
3417 b"-20100102030410Z",
3418 b"2010-0102030410Z",
3419 b"2010-0002030410Z",
3420 b"201001-02030410Z",
3421 b"20100102-030410Z",
3422 b"2010010203-0410Z",
3423 b"201001020304-10Z",
3424 # These ones are INVALID in *DER*, but accepted
3425 # by Go's encoding/asn1
3426 b"20100102030405+0607",
3427 b"20100102030405-0607",
3429 with self.assertRaises(DecodeError) as err:
3430 GeneralizedTime(data)
3433 def test_go_vectors_valid(self):
3435 GeneralizedTime(b"20100102030405Z").todatetime(),
3436 datetime(2010, 1, 2, 3, 4, 5, 0),
3440 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3441 base_klass = UTCTime
3443 min_datetime = datetime(2000, 1, 1)
3444 max_datetime = datetime(2049, 12, 31)
3446 def test_go_vectors_invalid(self):
3472 # These ones are INVALID in *DER*, but accepted
3473 # by Go's encoding/asn1
3474 b"910506164540-0700",
3475 b"910506164540+0730",
3479 with self.assertRaises(DecodeError) as err:
3483 def test_go_vectors_valid(self):
3485 UTCTime(b"910506234540Z").todatetime(),
3486 datetime(1991, 5, 6, 23, 45, 40, 0),
3489 @given(integers(min_value=0, max_value=49))
3490 def test_pre50(self, year):
3492 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3496 @given(integers(min_value=50, max_value=99))
3497 def test_post50(self, year):
3499 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3505 def any_values_strategy(draw, do_expl=False):
3506 value = draw(one_of(none(), binary()))
3509 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3510 optional = draw(one_of(none(), booleans()))
3512 draw(integers(min_value=0)),
3513 draw(integers(min_value=0)),
3514 draw(integers(min_value=0)),
3516 return (value, expl, optional, _decoded)
3519 class AnyInherited(Any):
3523 class TestAny(CommonMixin, TestCase):
3526 def test_invalid_value_type(self):
3527 with self.assertRaises(InvalidValueType) as err:
3532 def test_optional(self, optional):
3533 obj = Any(optional=optional)
3534 self.assertEqual(obj.optional, optional)
3537 def test_ready(self, value):
3539 self.assertFalse(obj.ready)
3542 with self.assertRaises(ObjNotReady) as err:
3546 self.assertTrue(obj.ready)
3551 def test_basic(self, value):
3552 integer_encoded = Integer(value).encode()
3554 Any(integer_encoded),
3555 Any(Integer(value)),
3556 Any(Any(Integer(value))),
3558 self.assertSequenceEqual(bytes(obj), integer_encoded)
3560 obj.decode(obj.encode())[0].vlen,
3561 len(integer_encoded),
3565 self.assertSequenceEqual(obj.encode(), integer_encoded)
3567 @given(binary(), binary())
3568 def test_comparison(self, value1, value2):
3569 for klass in (Any, AnyInherited):
3570 obj1 = klass(value1)
3571 obj2 = klass(value2)
3572 self.assertEqual(obj1 == obj2, value1 == value2)
3573 self.assertEqual(obj1 != obj2, value1 != value2)
3574 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3576 @given(data_strategy())
3577 def test_call(self, d):
3578 for klass in (Any, AnyInherited):
3584 ) = d.draw(any_values_strategy())
3585 obj_initial = klass(
3588 optional_initial or False,
3596 ) = d.draw(any_values_strategy(do_expl=True))
3597 obj = obj_initial(value, expl, optional)
3599 value_expected = None if value is None else value
3600 self.assertEqual(obj, value_expected)
3601 self.assertEqual(obj.expl_tag, expl or expl_initial)
3602 if obj.default is None:
3603 optional = optional_initial if optional is None else optional
3604 optional = False if optional is None else optional
3605 self.assertEqual(obj.optional, optional)
3607 def test_simultaneous_impl_expl(self):
3608 # override it, as Any does not have implicit tag
3611 def test_decoded(self):
3612 # override it, as Any does not have implicit tag
3615 @given(any_values_strategy())
3616 def test_copy(self, values):
3617 for klass in (Any, AnyInherited):
3618 obj = klass(*values)
3619 obj_copied = obj.copy()
3620 self.assert_copied_basic_fields(obj, obj_copied)
3621 self.assertEqual(obj._value, obj_copied._value)
3623 @given(binary().map(OctetString))
3624 def test_stripped(self, value):
3626 with self.assertRaises(NotEnoughData):
3627 obj.decode(obj.encode()[:-1])
3631 integers(min_value=1).map(tag_ctxc),
3633 def test_stripped_expl(self, value, tag_expl):
3634 obj = Any(value, expl=tag_expl)
3635 with self.assertRaises(NotEnoughData):
3636 obj.decode(obj.encode()[:-1])
3639 integers(min_value=31),
3640 integers(min_value=0),
3643 def test_bad_tag(self, tag, offset, decode_path):
3644 decode_path = tuple(str(i) for i in decode_path)
3645 with self.assertRaises(DecodeError) as err:
3647 tag_encode(tag)[:-1],
3649 decode_path=decode_path,
3652 self.assertEqual(err.exception.offset, offset)
3653 self.assertEqual(err.exception.decode_path, decode_path)
3656 integers(min_value=128),
3657 integers(min_value=0),
3660 def test_bad_len(self, l, offset, decode_path):
3661 decode_path = tuple(str(i) for i in decode_path)
3662 with self.assertRaises(DecodeError) as err:
3664 Any.tag_default + len_encode(l)[:-1],
3666 decode_path=decode_path,
3669 self.assertEqual(err.exception.offset, offset)
3670 self.assertEqual(err.exception.decode_path, decode_path)
3672 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3674 any_values_strategy(),
3675 integers().map(lambda x: Integer(x).encode()),
3676 integers(min_value=1).map(tag_ctxc),
3677 integers(min_value=0),
3680 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3681 for klass in (Any, AnyInherited):
3682 _, _, optional, _decoded = values
3683 obj = klass(value=value, optional=optional, _decoded=_decoded)
3686 self.assertFalse(obj.expled)
3687 obj_encoded = obj.encode()
3688 obj_expled = obj(value, expl=tag_expl)
3689 self.assertTrue(obj_expled.expled)
3692 obj_expled_encoded = obj_expled.encode()
3693 obj_decoded, tail = obj_expled.decode(
3694 obj_expled_encoded + tail_junk,
3699 self.assertEqual(tail, tail_junk)
3700 self.assertEqual(obj_decoded, obj_expled)
3701 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3702 self.assertEqual(bytes(obj_decoded), bytes(obj))
3703 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3704 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3705 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3707 obj_decoded.expl_llen,
3708 len(len_encode(len(obj_encoded))),
3710 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3711 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3714 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3716 self.assertEqual(obj_decoded.expl_offset, offset)
3717 self.assertEqual(obj_decoded.tlen, 0)
3718 self.assertEqual(obj_decoded.llen, 0)
3719 self.assertEqual(obj_decoded.vlen, len(value))
3723 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3725 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3726 tags = [tag_encode(tag) for tag in draw(sets(
3727 integers(min_value=0),
3728 min_size=len(names),
3729 max_size=len(names),
3731 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3733 if value_required or draw(booleans()):
3734 value = draw(tuples(
3735 sampled_from([name for name, _ in schema]),
3736 integers().map(Integer),
3740 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3741 default = draw(one_of(
3743 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3745 optional = draw(one_of(none(), booleans()))
3747 draw(integers(min_value=0)),
3748 draw(integers(min_value=0)),
3749 draw(integers(min_value=0)),
3751 return (schema, value, expl, default, optional, _decoded)
3754 class ChoiceInherited(Choice):
3758 class TestChoice(CommonMixin, TestCase):
3760 schema = (("whatever", Boolean()),)
3763 def test_schema_required(self):
3764 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3767 def test_impl_forbidden(self):
3768 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3769 Choice(impl=b"whatever")
3771 def test_invalid_value_type(self):
3772 with self.assertRaises(InvalidValueType) as err:
3773 self.base_klass(123)
3775 with self.assertRaises(ObjUnknown) as err:
3776 self.base_klass(("whenever", Boolean(False)))
3778 with self.assertRaises(InvalidValueType) as err:
3779 self.base_klass(("whatever", Integer(123)))
3783 def test_optional(self, optional):
3784 obj = self.base_klass(
3785 default=self.base_klass(("whatever", Boolean(False))),
3788 self.assertTrue(obj.optional)
3791 def test_ready(self, value):
3792 obj = self.base_klass()
3793 self.assertFalse(obj.ready)
3796 self.assertIsNone(obj["whatever"])
3797 with self.assertRaises(ObjNotReady) as err:
3800 obj["whatever"] = Boolean()
3801 self.assertFalse(obj.ready)
3804 obj["whatever"] = Boolean(value)
3805 self.assertTrue(obj.ready)
3809 @given(booleans(), booleans())
3810 def test_comparison(self, value1, value2):
3811 class WahlInherited(self.base_klass):
3813 for klass in (self.base_klass, WahlInherited):
3814 obj1 = klass(("whatever", Boolean(value1)))
3815 obj2 = klass(("whatever", Boolean(value2)))
3816 self.assertEqual(obj1 == obj2, value1 == value2)
3817 self.assertEqual(obj1 != obj2, value1 != value2)
3818 self.assertEqual(obj1 == obj2._value, value1 == value2)
3819 self.assertFalse(obj1 == obj2._value[1])
3821 @given(data_strategy())
3822 def test_call(self, d):
3823 for klass in (Choice, ChoiceInherited):
3831 ) = d.draw(choice_values_strategy())
3834 schema = schema_initial
3836 value=value_initial,
3838 default=default_initial,
3839 optional=optional_initial or False,
3840 _decoded=_decoded_initial,
3849 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
3850 obj = obj_initial(value, expl, default, optional)
3852 value_expected = default if value is None else value
3854 default_initial if value_expected is None
3857 self.assertEqual(obj.choice, value_expected[0])
3858 self.assertEqual(obj.value, int(value_expected[1]))
3859 self.assertEqual(obj.expl_tag, expl or expl_initial)
3860 default_expect = default_initial if default is None else default
3861 if default_expect is not None:
3862 self.assertEqual(obj.default.choice, default_expect[0])
3863 self.assertEqual(obj.default.value, int(default_expect[1]))
3864 if obj.default is None:
3865 optional = optional_initial if optional is None else optional
3866 optional = False if optional is None else optional
3869 self.assertEqual(obj.optional, optional)
3870 self.assertEqual(obj.specs, obj_initial.specs)
3872 def test_simultaneous_impl_expl(self):
3873 # override it, as Any does not have implicit tag
3876 def test_decoded(self):
3877 # override it, as Any does not have implicit tag
3880 @given(choice_values_strategy())
3881 def test_copy(self, values):
3882 _schema, value, expl, default, optional, _decoded = values
3884 class Wahl(self.base_klass):
3890 optional=optional or False,
3893 obj_copied = obj.copy()
3894 self.assertIsNone(obj.tag)
3895 self.assertIsNone(obj_copied.tag)
3896 # hack for assert_copied_basic_fields
3897 obj.tag = "whatever"
3898 obj_copied.tag = "whatever"
3899 self.assert_copied_basic_fields(obj, obj_copied)
3900 self.assertEqual(obj._value, obj_copied._value)
3901 self.assertEqual(obj.specs, obj_copied.specs)
3904 def test_stripped(self, value):
3905 obj = self.base_klass(("whatever", Boolean(value)))
3906 with self.assertRaises(NotEnoughData):
3907 obj.decode(obj.encode()[:-1])
3911 integers(min_value=1).map(tag_ctxc),
3913 def test_stripped_expl(self, value, tag_expl):
3914 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3915 with self.assertRaises(NotEnoughData):
3916 obj.decode(obj.encode()[:-1])
3918 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3919 @given(data_strategy())
3920 def test_symmetric(self, d):
3921 _schema, value, _, default, optional, _decoded = d.draw(
3922 choice_values_strategy(value_required=True)
3924 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3925 offset = d.draw(integers(min_value=0))
3926 tail_junk = d.draw(binary(max_size=5))
3928 class Wahl(self.base_klass):
3938 self.assertFalse(obj.expled)
3939 obj_encoded = obj.encode()
3940 obj_expled = obj(value, expl=tag_expl)
3941 self.assertTrue(obj_expled.expled)
3944 obj_expled_encoded = obj_expled.encode()
3945 obj_decoded, tail = obj_expled.decode(
3946 obj_expled_encoded + tail_junk,
3951 self.assertEqual(tail, tail_junk)
3952 self.assertEqual(obj_decoded, obj_expled)
3953 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3954 self.assertEqual(obj_decoded.value, obj_expled.value)
3955 self.assertEqual(obj_decoded.choice, obj.choice)
3956 self.assertEqual(obj_decoded.value, obj.value)
3957 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3958 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3959 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3961 obj_decoded.expl_llen,
3962 len(len_encode(len(obj_encoded))),
3964 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3965 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3968 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3970 self.assertEqual(obj_decoded.expl_offset, offset)
3971 self.assertSequenceEqual(
3973 obj_decoded.value.offset - offset:
3974 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3980 def test_set_get(self, value):
3983 ("erste", Boolean()),
3984 ("zweite", Integer()),
3987 with self.assertRaises(ObjUnknown) as err:
3988 obj["whatever"] = "whenever"
3989 with self.assertRaises(InvalidValueType) as err:
3990 obj["zweite"] = Boolean(False)
3991 obj["zweite"] = Integer(value)
3993 with self.assertRaises(ObjUnknown) as err:
3996 self.assertIsNone(obj["erste"])
3997 self.assertEqual(obj["zweite"], Integer(value))
3999 def test_tag_mismatch(self):
4002 ("erste", Boolean()),
4004 int_encoded = Integer(123).encode()
4005 bool_encoded = Boolean(False).encode()
4007 obj.decode(bool_encoded)
4008 with self.assertRaises(TagMismatch):
4009 obj.decode(int_encoded)
4011 def test_tag_mismatch_underlying(self):
4012 class SeqOfBoolean(SequenceOf):
4015 class SeqOfInteger(SequenceOf):
4020 ("erste", SeqOfBoolean()),
4023 int_encoded = SeqOfInteger((Integer(123),)).encode()
4024 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4026 obj.decode(bool_encoded)
4027 with self.assertRaises(TagMismatch) as err:
4028 obj.decode(int_encoded)
4029 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4033 def seq_values_strategy(draw, seq_klass, do_expl=False):
4035 if draw(booleans()):
4038 k: v for k, v in draw(dictionaries(
4041 booleans().map(Boolean),
4042 integers().map(Integer),
4047 if draw(booleans()):
4048 schema = list(draw(dictionaries(
4051 booleans().map(Boolean),
4052 integers().map(Integer),
4058 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4060 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4062 if draw(booleans()):
4063 default = seq_klass()
4065 k: v for k, v in draw(dictionaries(
4068 booleans().map(Boolean),
4069 integers().map(Integer),
4073 optional = draw(one_of(none(), booleans()))
4075 draw(integers(min_value=0)),
4076 draw(integers(min_value=0)),
4077 draw(integers(min_value=0)),
4079 return (value, schema, impl, expl, default, optional, _decoded)
4083 def sequence_strategy(draw, seq_klass):
4084 inputs = draw(lists(
4086 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4087 tuples(just(Integer), integers(), one_of(none(), integers())),
4092 integers(min_value=1),
4093 min_size=len(inputs),
4094 max_size=len(inputs),
4097 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4098 for tag, expled in zip(tags, draw(lists(
4100 min_size=len(inputs),
4101 max_size=len(inputs),
4105 for i, optional in enumerate(draw(lists(
4106 sampled_from(("required", "optional", "empty")),
4107 min_size=len(inputs),
4108 max_size=len(inputs),
4110 if optional in ("optional", "empty"):
4111 inits[i]["optional"] = True
4112 if optional == "empty":
4114 empties = set(empties)
4115 names = list(draw(sets(
4117 min_size=len(inputs),
4118 max_size=len(inputs),
4121 for i, (klass, value, default) in enumerate(inputs):
4122 schema.append((names[i], klass(default=default, **inits[i])))
4123 seq_name = draw(text_letters())
4124 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4127 for i, (klass, value, default) in enumerate(inputs):
4134 "default_value": None if spec.default is None else default,
4138 expect["optional"] = True
4140 expect["presented"] = True
4141 expect["value"] = value
4143 expect["optional"] = True
4144 if default is not None and default == value:
4145 expect["presented"] = False
4146 seq[name] = klass(value)
4147 expects.append(expect)
4152 def sequences_strategy(draw, seq_klass):
4153 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4155 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4156 for tag, expled in zip(tags, draw(lists(
4163 i for i, is_default in enumerate(draw(lists(
4169 names = list(draw(sets(
4174 seq_expectses = draw(lists(
4175 sequence_strategy(seq_klass=seq_klass),
4179 seqs = [seq for seq, _ in seq_expectses]
4181 for i, (name, seq) in enumerate(zip(names, seqs)):
4184 seq(default=(seq if i in defaulted else None), **inits[i]),
4186 seq_name = draw(text_letters())
4187 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4190 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4193 "expects": expects_inner,
4196 seq_outer[name] = seq_inner
4197 if seq_outer.specs[name].default is None:
4198 expect["presented"] = True
4199 expect_outers.append(expect)
4200 return seq_outer, expect_outers
4203 class SeqMixing(object):
4204 def test_invalid_value_type(self):
4205 with self.assertRaises(InvalidValueType) as err:
4206 self.base_klass(123)
4209 def test_invalid_value_type_set(self):
4210 class Seq(self.base_klass):
4211 schema = (("whatever", Boolean()),)
4213 with self.assertRaises(InvalidValueType) as err:
4214 seq["whatever"] = Integer(123)
4218 def test_optional(self, optional):
4219 obj = self.base_klass(default=self.base_klass(), optional=optional)
4220 self.assertTrue(obj.optional)
4222 @given(data_strategy())
4223 def test_ready(self, d):
4225 str(i): v for i, v in enumerate(d.draw(lists(
4232 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4239 for name in d.draw(permutations(
4240 list(ready.keys()) + list(non_ready.keys()),
4242 schema_input.append((name, Boolean()))
4244 class Seq(self.base_klass):
4245 schema = tuple(schema_input)
4247 for name in ready.keys():
4249 seq[name] = Boolean()
4250 self.assertFalse(seq.ready)
4253 for name, value in ready.items():
4254 seq[name] = Boolean(value)
4255 self.assertFalse(seq.ready)
4258 with self.assertRaises(ObjNotReady) as err:
4261 for name, value in non_ready.items():
4262 seq[name] = Boolean(value)
4263 self.assertTrue(seq.ready)
4267 @given(data_strategy())
4268 def test_call(self, d):
4269 class SeqInherited(self.base_klass):
4271 for klass in (self.base_klass, SeqInherited):
4280 ) = d.draw(seq_values_strategy(seq_klass=klass))
4281 obj_initial = klass(
4287 optional_initial or False,
4298 ) = d.draw(seq_values_strategy(
4300 do_expl=impl_initial is None,
4302 obj = obj_initial(value, impl, expl, default, optional)
4303 value_expected = default if value is None else value
4305 default_initial if value_expected is None
4308 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4309 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4310 self.assertEqual(obj.expl_tag, expl or expl_initial)
4312 {} if obj.default is None else obj.default._value,
4313 getattr(default_initial if default is None else default, "_value", {}),
4315 if obj.default is None:
4316 optional = optional_initial if optional is None else optional
4317 optional = False if optional is None else optional
4320 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4321 self.assertEqual(obj.optional, optional)
4323 @given(data_strategy())
4324 def test_copy(self, d):
4325 class SeqInherited(self.base_klass):
4327 for klass in (self.base_klass, SeqInherited):
4328 values = d.draw(seq_values_strategy(seq_klass=klass))
4329 obj = klass(*values)
4330 obj_copied = obj.copy()
4331 self.assert_copied_basic_fields(obj, obj_copied)
4332 self.assertEqual(obj.specs, obj_copied.specs)
4333 self.assertEqual(obj._value, obj_copied._value)
4335 @given(data_strategy())
4336 def test_stripped(self, d):
4337 value = d.draw(integers())
4338 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4340 class Seq(self.base_klass):
4342 schema = (("whatever", Integer()),)
4344 seq["whatever"] = Integer(value)
4345 with self.assertRaises(NotEnoughData):
4346 seq.decode(seq.encode()[:-1])
4348 @given(data_strategy())
4349 def test_stripped_expl(self, d):
4350 value = d.draw(integers())
4351 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4353 class Seq(self.base_klass):
4355 schema = (("whatever", Integer()),)
4357 seq["whatever"] = Integer(value)
4358 with self.assertRaises(NotEnoughData):
4359 seq.decode(seq.encode()[:-1])
4361 @given(binary(min_size=2))
4362 def test_non_tag_mismatch_raised(self, junk):
4364 _, _, len_encoded = tag_strip(memoryview(junk))
4365 len_decode(len_encoded)
4371 class Seq(self.base_klass):
4373 ("whatever", Integer()),
4375 ("whenever", Integer()),
4378 seq["whatever"] = Integer(123)
4379 seq["junk"] = Any(junk)
4380 seq["whenever"] = Integer(123)
4381 with self.assertRaises(DecodeError):
4382 seq.decode(seq.encode())
4385 integers(min_value=31),
4386 integers(min_value=0),
4389 def test_bad_tag(self, tag, offset, decode_path):
4390 decode_path = tuple(str(i) for i in decode_path)
4391 with self.assertRaises(DecodeError) as err:
4392 self.base_klass().decode(
4393 tag_encode(tag)[:-1],
4395 decode_path=decode_path,
4398 self.assertEqual(err.exception.offset, offset)
4399 self.assertEqual(err.exception.decode_path, decode_path)
4402 integers(min_value=128),
4403 integers(min_value=0),
4406 def test_bad_len(self, l, offset, decode_path):
4407 decode_path = tuple(str(i) for i in decode_path)
4408 with self.assertRaises(DecodeError) as err:
4409 self.base_klass().decode(
4410 self.base_klass.tag_default + len_encode(l)[:-1],
4412 decode_path=decode_path,
4415 self.assertEqual(err.exception.offset, offset)
4416 self.assertEqual(err.exception.decode_path, decode_path)
4418 def _assert_expects(self, seq, expects):
4419 for expect in expects:
4421 seq.specs[expect["name"]].optional,
4424 if expect["default_value"] is not None:
4426 seq.specs[expect["name"]].default,
4427 expect["default_value"],
4429 if expect["presented"]:
4430 self.assertIn(expect["name"], seq)
4431 self.assertEqual(seq[expect["name"]], expect["value"])
4433 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4434 @given(data_strategy())
4435 def test_symmetric(self, d):
4436 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4437 tail_junk = d.draw(binary(max_size=5))
4438 self.assertTrue(seq.ready)
4439 self.assertFalse(seq.decoded)
4440 self._assert_expects(seq, expects)
4443 seq_encoded = seq.encode()
4444 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4445 self.assertEqual(tail, tail_junk)
4446 self.assertTrue(seq.ready)
4447 self._assert_expects(seq_decoded, expects)
4448 self.assertEqual(seq, seq_decoded)
4449 self.assertEqual(seq_decoded.encode(), seq_encoded)
4450 for expect in expects:
4451 if not expect["presented"]:
4452 self.assertNotIn(expect["name"], seq_decoded)
4454 self.assertIn(expect["name"], seq_decoded)
4455 obj = seq_decoded[expect["name"]]
4456 self.assertTrue(obj.decoded)
4457 offset = obj.expl_offset if obj.expled else obj.offset
4458 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4459 self.assertSequenceEqual(
4460 seq_encoded[offset:offset + tlvlen],
4464 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4465 @given(data_strategy())
4466 def test_symmetric_with_seq(self, d):
4467 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4468 self.assertTrue(seq.ready)
4469 seq_encoded = seq.encode()
4470 seq_decoded, tail = seq.decode(seq_encoded)
4471 self.assertEqual(tail, b"")
4472 self.assertTrue(seq.ready)
4473 self.assertEqual(seq, seq_decoded)
4474 self.assertEqual(seq_decoded.encode(), seq_encoded)
4475 for expect_outer in expect_outers:
4476 if not expect_outer["presented"]:
4477 self.assertNotIn(expect_outer["name"], seq_decoded)
4479 self.assertIn(expect_outer["name"], seq_decoded)
4480 obj = seq_decoded[expect_outer["name"]]
4481 self.assertTrue(obj.decoded)
4482 offset = obj.expl_offset if obj.expled else obj.offset
4483 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4484 self.assertSequenceEqual(
4485 seq_encoded[offset:offset + tlvlen],
4488 self._assert_expects(obj, expect_outer["expects"])
4490 @given(data_strategy())
4491 def test_default_disappears(self, d):
4492 _schema = list(d.draw(dictionaries(
4494 sets(integers(), min_size=2, max_size=2),
4498 class Seq(self.base_klass):
4500 (n, Integer(default=d))
4501 for n, (_, d) in _schema
4504 for name, (value, _) in _schema:
4505 seq[name] = Integer(value)
4506 self.assertEqual(len(seq._value), len(_schema))
4507 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4508 self.assertGreater(len(seq.encode()), len(empty_seq))
4509 for name, (_, default) in _schema:
4510 seq[name] = Integer(default)
4511 self.assertEqual(len(seq._value), 0)
4512 self.assertSequenceEqual(seq.encode(), empty_seq)
4514 @given(data_strategy())
4515 def test_encoded_default_accepted(self, d):
4516 _schema = list(d.draw(dictionaries(
4521 tags = [tag_encode(tag) for tag in d.draw(sets(
4522 integers(min_value=0),
4523 min_size=len(_schema),
4524 max_size=len(_schema),
4527 class SeqWithoutDefault(self.base_klass):
4529 (n, Integer(impl=t))
4530 for (n, _), t in zip(_schema, tags)
4532 seq_without_default = SeqWithoutDefault()
4533 for name, value in _schema:
4534 seq_without_default[name] = Integer(value)
4535 seq_encoded = seq_without_default.encode()
4537 class SeqWithDefault(self.base_klass):
4539 (n, Integer(default=v, impl=t))
4540 for (n, v), t in zip(_schema, tags)
4542 seq_with_default = SeqWithDefault()
4543 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4544 for name, value in _schema:
4545 self.assertEqual(seq_decoded[name], seq_with_default[name])
4546 self.assertEqual(seq_decoded[name], value)
4548 @given(data_strategy())
4549 def test_missing_from_spec(self, d):
4550 names = list(d.draw(sets(text_letters(), min_size=2)))
4551 tags = [tag_encode(tag) for tag in d.draw(sets(
4552 integers(min_value=0),
4553 min_size=len(names),
4554 max_size=len(names),
4556 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4558 class SeqFull(self.base_klass):
4559 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4560 seq_full = SeqFull()
4561 for i, name in enumerate(names):
4562 seq_full[name] = Integer(i)
4563 seq_encoded = seq_full.encode()
4564 altered = names_tags[:-2] + names_tags[-1:]
4566 class SeqMissing(self.base_klass):
4567 schema = [(n, Integer(impl=t)) for n, t in altered]
4568 seq_missing = SeqMissing()
4569 with self.assertRaises(TagMismatch):
4570 seq_missing.decode(seq_encoded)
4573 class TestSequence(SeqMixing, CommonMixin, TestCase):
4574 base_klass = Sequence
4580 def test_remaining(self, value, junk):
4581 class Seq(Sequence):
4583 ("whatever", Integer()),
4585 int_encoded = Integer(value).encode()
4587 Sequence.tag_default,
4588 len_encode(len(int_encoded + junk)),
4591 with assertRaisesRegex(self, DecodeError, "remaining"):
4592 Seq().decode(junked)
4594 @given(sets(text_letters(), min_size=2))
4595 def test_obj_unknown(self, names):
4596 missing = names.pop()
4598 class Seq(Sequence):
4599 schema = [(n, Boolean()) for n in names]
4601 with self.assertRaises(ObjUnknown) as err:
4604 with self.assertRaises(ObjUnknown) as err:
4605 seq[missing] = Boolean()
4608 def test_x690_vector(self):
4609 class Seq(Sequence):
4611 ("name", IA5String()),
4614 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4615 self.assertEqual(seq["name"], "Smith")
4616 self.assertEqual(seq["ok"], True)
4619 class TestSet(SeqMixing, CommonMixin, TestCase):
4622 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4623 @given(data_strategy())
4624 def test_sorted(self, d):
4626 tag_encode(tag) for tag in
4627 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4631 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4633 for name, _ in Seq.schema:
4634 seq[name] = OctetString(b"")
4635 seq_encoded = seq.encode()
4636 seq_decoded, _ = seq.decode(seq_encoded)
4637 self.assertSequenceEqual(
4638 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4639 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4644 def seqof_values_strategy(draw, schema=None, do_expl=False):
4646 schema = draw(sampled_from((Boolean(), Integer())))
4647 bound_min, bound_max = sorted(draw(sets(
4648 integers(min_value=0, max_value=10),
4652 if isinstance(schema, Boolean):
4653 values_generator = booleans().map(Boolean)
4654 elif isinstance(schema, Integer):
4655 values_generator = integers().map(Integer)
4656 values_generator = lists(
4661 values = draw(one_of(none(), values_generator))
4665 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4667 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4668 default = draw(one_of(none(), values_generator))
4669 optional = draw(one_of(none(), booleans()))
4671 draw(integers(min_value=0)),
4672 draw(integers(min_value=0)),
4673 draw(integers(min_value=0)),
4678 (bound_min, bound_max),
4687 class SeqOfMixing(object):
4688 def test_invalid_value_type(self):
4689 with self.assertRaises(InvalidValueType) as err:
4690 self.base_klass(123)
4693 def test_invalid_values_type(self):
4694 class SeqOf(self.base_klass):
4696 with self.assertRaises(InvalidValueType) as err:
4697 SeqOf([Integer(123), Boolean(False), Integer(234)])
4700 def test_schema_required(self):
4701 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4702 self.base_klass.__mro__[1]()
4704 @given(booleans(), booleans(), binary(), binary())
4705 def test_comparison(self, value1, value2, tag1, tag2):
4706 class SeqOf(self.base_klass):
4708 obj1 = SeqOf([Boolean(value1)])
4709 obj2 = SeqOf([Boolean(value2)])
4710 self.assertEqual(obj1 == obj2, value1 == value2)
4711 self.assertEqual(obj1 != obj2, value1 != value2)
4712 self.assertEqual(obj1 == list(obj2), value1 == value2)
4713 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4714 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4715 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4716 self.assertEqual(obj1 == obj2, tag1 == tag2)
4717 self.assertEqual(obj1 != obj2, tag1 != tag2)
4719 @given(lists(booleans()))
4720 def test_iter(self, values):
4721 class SeqOf(self.base_klass):
4723 obj = SeqOf([Boolean(value) for value in values])
4724 self.assertEqual(len(obj), len(values))
4725 for i, value in enumerate(obj):
4726 self.assertEqual(value, values[i])
4728 @given(data_strategy())
4729 def test_ready(self, d):
4730 ready = [Integer(v) for v in d.draw(lists(
4737 range(d.draw(integers(min_value=1, max_value=5)))
4740 class SeqOf(self.base_klass):
4742 values = d.draw(permutations(ready + non_ready))
4744 for value in values:
4746 self.assertFalse(seqof.ready)
4749 with self.assertRaises(ObjNotReady) as err:
4752 for i, value in enumerate(values):
4753 self.assertEqual(seqof[i], value)
4754 if not seqof[i].ready:
4755 seqof[i] = Integer(i)
4756 self.assertTrue(seqof.ready)
4760 def test_spec_mismatch(self):
4761 class SeqOf(self.base_klass):
4764 seqof.append(Integer(123))
4765 with self.assertRaises(ValueError):
4766 seqof.append(Boolean(False))
4767 with self.assertRaises(ValueError):
4768 seqof[0] = Boolean(False)
4770 @given(data_strategy())
4771 def test_bounds_satisfied(self, d):
4772 class SeqOf(self.base_klass):
4774 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4775 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4776 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4777 SeqOf(value=value, bounds=(bound_min, bound_max))
4779 @given(data_strategy())
4780 def test_bounds_unsatisfied(self, d):
4781 class SeqOf(self.base_klass):
4783 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4784 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4785 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4786 with self.assertRaises(BoundsError) as err:
4787 SeqOf(value=value, bounds=(bound_min, bound_max))
4789 value = [Boolean()] * d.draw(integers(
4790 min_value=bound_max + 1,
4791 max_value=bound_max + 10,
4793 with self.assertRaises(BoundsError) as err:
4794 SeqOf(value=value, bounds=(bound_min, bound_max))
4797 @given(integers(min_value=1, max_value=10))
4798 def test_out_of_bounds(self, bound_max):
4799 class SeqOf(self.base_klass):
4801 bounds = (0, bound_max)
4803 for _ in range(bound_max):
4804 seqof.append(Integer(123))
4805 with self.assertRaises(BoundsError):
4806 seqof.append(Integer(123))
4808 @given(data_strategy())
4809 def test_call(self, d):
4819 ) = d.draw(seqof_values_strategy())
4821 class SeqOf(self.base_klass):
4822 schema = schema_initial
4823 obj_initial = SeqOf(
4824 value=value_initial,
4825 bounds=bounds_initial,
4828 default=default_initial,
4829 optional=optional_initial or False,
4830 _decoded=_decoded_initial,
4841 ) = d.draw(seqof_values_strategy(
4842 schema=schema_initial,
4843 do_expl=impl_initial is None,
4845 if (default is None) and (obj_initial.default is not None):
4848 (bounds is None) and
4849 (value is not None) and
4850 (bounds_initial is not None) and
4851 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4855 (bounds is None) and
4856 (default is not None) and
4857 (bounds_initial is not None) and
4858 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4870 value_expected = default if value is None else value
4872 default_initial if value_expected is None
4875 value_expected = () if value_expected is None else value_expected
4876 self.assertEqual(obj, value_expected)
4877 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4878 self.assertEqual(obj.expl_tag, expl or expl_initial)
4881 default_initial if default is None else default,
4883 if obj.default is None:
4884 optional = optional_initial if optional is None else optional
4885 optional = False if optional is None else optional
4888 self.assertEqual(obj.optional, optional)
4890 (obj._bound_min, obj._bound_max),
4891 bounds or bounds_initial or (0, float("+inf")),
4894 @given(seqof_values_strategy())
4895 def test_copy(self, values):
4896 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4898 class SeqOf(self.base_klass):
4906 optional=optional or False,
4909 obj_copied = obj.copy()
4910 self.assert_copied_basic_fields(obj, obj_copied)
4911 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4912 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4913 self.assertEqual(obj._value, obj_copied._value)
4917 integers(min_value=1).map(tag_encode),
4919 def test_stripped(self, values, tag_impl):
4920 class SeqOf(self.base_klass):
4921 schema = OctetString()
4922 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4923 with self.assertRaises(NotEnoughData):
4924 obj.decode(obj.encode()[:-1])
4928 integers(min_value=1).map(tag_ctxc),
4930 def test_stripped_expl(self, values, tag_expl):
4931 class SeqOf(self.base_klass):
4932 schema = OctetString()
4933 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4934 with self.assertRaises(NotEnoughData):
4935 obj.decode(obj.encode()[:-1])
4938 integers(min_value=31),
4939 integers(min_value=0),
4942 def test_bad_tag(self, tag, offset, decode_path):
4943 decode_path = tuple(str(i) for i in decode_path)
4944 with self.assertRaises(DecodeError) as err:
4945 self.base_klass().decode(
4946 tag_encode(tag)[:-1],
4948 decode_path=decode_path,
4951 self.assertEqual(err.exception.offset, offset)
4952 self.assertEqual(err.exception.decode_path, decode_path)
4955 integers(min_value=128),
4956 integers(min_value=0),
4959 def test_bad_len(self, l, offset, decode_path):
4960 decode_path = tuple(str(i) for i in decode_path)
4961 with self.assertRaises(DecodeError) as err:
4962 self.base_klass().decode(
4963 self.base_klass.tag_default + len_encode(l)[:-1],
4965 decode_path=decode_path,
4968 self.assertEqual(err.exception.offset, offset)
4969 self.assertEqual(err.exception.decode_path, decode_path)
4971 @given(binary(min_size=1))
4972 def test_tag_mismatch(self, impl):
4973 assume(impl != self.base_klass.tag_default)
4974 with self.assertRaises(TagMismatch):
4975 self.base_klass(impl=impl).decode(self.base_klass().encode())
4977 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4979 seqof_values_strategy(schema=Integer()),
4980 lists(integers().map(Integer)),
4981 integers(min_value=1).map(tag_ctxc),
4982 integers(min_value=0),
4985 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4986 _, _, _, _, _, default, optional, _decoded = values
4988 class SeqOf(self.base_klass):
4998 self.assertFalse(obj.expled)
4999 obj_encoded = obj.encode()
5000 obj_expled = obj(value, expl=tag_expl)
5001 self.assertTrue(obj_expled.expled)
5004 obj_expled_encoded = obj_expled.encode()
5005 obj_decoded, tail = obj_expled.decode(
5006 obj_expled_encoded + tail_junk,
5011 self.assertEqual(tail, tail_junk)
5012 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5013 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5014 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5015 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5017 obj_decoded.expl_llen,
5018 len(len_encode(len(obj_encoded))),
5020 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5021 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5024 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5026 self.assertEqual(obj_decoded.expl_offset, offset)
5027 for obj_inner in obj_decoded:
5028 self.assertIn(obj_inner, obj_decoded)
5029 self.assertSequenceEqual(
5032 obj_inner.offset - offset:
5033 obj_inner.offset + obj_inner.tlvlen - offset
5038 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5039 class SeqOf(SequenceOf):
5043 def _test_symmetric_compare_objs(self, obj1, obj2):
5044 self.assertEqual(obj1, obj2)
5045 self.assertSequenceEqual(list(obj1), list(obj2))
5048 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5053 def _test_symmetric_compare_objs(self, obj1, obj2):
5054 self.assertSetEqual(
5055 set(int(v) for v in obj1),
5056 set(int(v) for v in obj2),
5059 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5060 @given(data_strategy())
5061 def test_sorted(self, d):
5062 values = [OctetString(v) for v in d.draw(lists(binary()))]
5065 schema = OctetString()
5067 seq_encoded = seq.encode()
5068 seq_decoded, _ = seq.decode(seq_encoded)
5069 self.assertSequenceEqual(
5070 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5071 b"".join(sorted([v.encode() for v in values])),
5075 class TestGoMarshalVectors(TestCase):
5077 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5078 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5079 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5080 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5081 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5083 class Seq(Sequence):
5085 ("erste", Integer()),
5086 ("zweite", Integer(optional=True))
5089 seq["erste"] = Integer(64)
5090 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5091 seq["erste"] = Integer(0x123456)
5092 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5093 seq["erste"] = Integer(64)
5094 seq["zweite"] = Integer(65)
5095 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5097 class NestedSeq(Sequence):
5101 seq["erste"] = Integer(127)
5102 seq["zweite"] = None
5103 nested = NestedSeq()
5104 nested["nest"] = seq
5105 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5107 self.assertSequenceEqual(
5108 OctetString(b"\x01\x02\x03").encode(),
5109 hexdec("0403010203"),
5112 class Seq(Sequence):
5114 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5117 seq["erste"] = Integer(64)
5118 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5120 class Seq(Sequence):
5122 ("erste", Integer(expl=tag_ctxc(5))),
5125 seq["erste"] = Integer(64)
5126 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5128 class Seq(Sequence):
5131 impl=tag_encode(0, klass=TagClassContext),
5136 seq["erste"] = Null()
5137 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5139 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5141 self.assertSequenceEqual(
5142 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5143 hexdec("170d3730303130313030303030305a"),
5145 self.assertSequenceEqual(
5146 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5147 hexdec("170d3039313131353232353631365a"),
5149 self.assertSequenceEqual(
5150 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5151 hexdec("180f32313030303430353132303130315a"),
5154 class Seq(Sequence):
5156 ("erste", GeneralizedTime()),
5159 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5160 self.assertSequenceEqual(
5162 hexdec("3011180f32303039313131353232353631365a"),
5165 self.assertSequenceEqual(
5166 BitString((1, b"\x80")).encode(),
5169 self.assertSequenceEqual(
5170 BitString((12, b"\x81\xF0")).encode(),
5171 hexdec("03030481f0"),
5174 self.assertSequenceEqual(
5175 ObjectIdentifier("1.2.3.4").encode(),
5176 hexdec("06032a0304"),
5178 self.assertSequenceEqual(
5179 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5180 hexdec("06092a864888932d010105"),
5182 self.assertSequenceEqual(
5183 ObjectIdentifier("2.100.3").encode(),
5184 hexdec("0603813403"),
5187 self.assertSequenceEqual(
5188 PrintableString("test").encode(),
5189 hexdec("130474657374"),
5191 self.assertSequenceEqual(
5192 PrintableString("x" * 127).encode(),
5193 hexdec("137F" + "78" * 127),
5195 self.assertSequenceEqual(
5196 PrintableString("x" * 128).encode(),
5197 hexdec("138180" + "78" * 128),
5199 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5201 class Seq(Sequence):
5203 ("erste", IA5String()),
5206 seq["erste"] = IA5String("test")
5207 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5209 class Seq(Sequence):
5211 ("erste", PrintableString()),
5214 seq["erste"] = PrintableString("test")
5215 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5216 seq["erste"] = PrintableString("test*")
5217 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5219 class Seq(Sequence):
5221 ("erste", Any(optional=True)),
5222 ("zweite", Integer()),
5225 seq["zweite"] = Integer(64)
5226 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5231 seq.append(Integer(10))
5232 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5234 class _SeqOf(SequenceOf):
5235 schema = PrintableString()
5237 class SeqOf(SequenceOf):
5240 _seqof.append(PrintableString("1"))
5242 seqof.append(_seqof)
5243 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5245 class Seq(Sequence):
5247 ("erste", Integer(default=1)),
5250 seq["erste"] = Integer(0)
5251 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5252 seq["erste"] = Integer(1)
5253 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5254 seq["erste"] = Integer(2)
5255 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5258 class TestPP(TestCase):
5259 @given(data_strategy())
5260 def test_oid_printing(self, d):
5262 str(ObjectIdentifier(k)): v * 2
5263 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5265 chosen = d.draw(sampled_from(sorted(oids)))
5266 chosen_id = oids[chosen]
5267 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5268 self.assertNotIn(chosen_id, pp_console_row(pp))
5269 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5272 class TestAutoAddSlots(TestCase):
5274 class Inher(Integer):
5277 with self.assertRaises(AttributeError):
5279 inher.unexistent = "whatever"
5282 class TestOIDDefines(TestCase):
5283 @given(data_strategy())
5284 def runTest(self, d):
5285 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5286 value_name_chosen = d.draw(sampled_from(value_names))
5288 ObjectIdentifier(oid)
5289 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5291 oid_chosen = d.draw(sampled_from(oids))
5292 values = d.draw(lists(
5294 min_size=len(value_names),
5295 max_size=len(value_names),
5298 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5299 oid: Integer() for oid in oids[:-1]
5302 for i, value_name in enumerate(value_names):
5303 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5305 class Seq(Sequence):
5308 for value_name, value in zip(value_names, values):
5309 seq[value_name] = Any(Integer(value).encode())
5310 seq["type"] = oid_chosen
5311 seq, _ = Seq().decode(seq.encode())
5312 for value_name in value_names:
5313 if value_name == value_name_chosen:
5315 self.assertIsNone(seq[value_name].defined)
5316 if value_name_chosen in oids[:-1]:
5317 self.assertIsNotNone(seq[value_name_chosen].defined)
5318 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5319 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5322 class TestDefinesByPath(TestCase):
5323 def test_generated(self):
5324 class Seq(Sequence):
5326 ("type", ObjectIdentifier()),
5327 ("value", OctetString(expl=tag_ctxc(123))),
5330 class SeqInner(Sequence):
5332 ("typeInner", ObjectIdentifier()),
5333 ("valueInner", Any()),
5336 class PairValue(SetOf):
5339 class Pair(Sequence):
5341 ("type", ObjectIdentifier()),
5342 ("value", PairValue()),
5345 class Pairs(SequenceOf):
5352 type_octet_stringed,
5354 ObjectIdentifier(oid)
5355 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5357 seq_integered = Seq()
5358 seq_integered["type"] = type_integered
5359 seq_integered["value"] = OctetString(Integer(123).encode())
5360 seq_integered_raw = seq_integered.encode()
5364 (type_octet_stringed, OctetString(b"whatever")),
5365 (type_integered, Integer(123)),
5366 (type_octet_stringed, OctetString(b"whenever")),
5367 (type_integered, Integer(234)),
5369 for t, v in pairs_input:
5372 pair["value"] = PairValue((Any(v),))
5374 seq_inner = SeqInner()
5375 seq_inner["typeInner"] = type_innered
5376 seq_inner["valueInner"] = Any(pairs)
5377 seq_sequenced = Seq()
5378 seq_sequenced["type"] = type_sequenced
5379 seq_sequenced["value"] = OctetString(seq_inner.encode())
5380 seq_sequenced_raw = seq_sequenced.encode()
5382 defines_by_path = []
5383 seq_integered, _ = Seq().decode(seq_integered_raw)
5384 self.assertIsNone(seq_integered["value"].defined)
5385 defines_by_path.append(
5386 (("type",), ((("value",), {
5387 type_integered: Integer(),
5388 type_sequenced: SeqInner(),
5391 seq_integered, _ = Seq().decode(
5393 ctx={"defines_by_path": defines_by_path},
5395 self.assertIsNotNone(seq_integered["value"].defined)
5396 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5397 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5398 self.assertTrue(seq_integered_raw[
5399 seq_integered["value"].defined[1].offset:
5400 ].startswith(Integer(123).encode()))
5402 seq_sequenced, _ = Seq().decode(
5404 ctx={"defines_by_path": defines_by_path},
5406 self.assertIsNotNone(seq_sequenced["value"].defined)
5407 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5408 seq_inner = seq_sequenced["value"].defined[1]
5409 self.assertIsNone(seq_inner["valueInner"].defined)
5411 defines_by_path.append((
5412 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5413 ((("valueInner",), {type_innered: Pairs()}),),
5415 seq_sequenced, _ = Seq().decode(
5417 ctx={"defines_by_path": defines_by_path},
5419 self.assertIsNotNone(seq_sequenced["value"].defined)
5420 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5421 seq_inner = seq_sequenced["value"].defined[1]
5422 self.assertIsNotNone(seq_inner["valueInner"].defined)
5423 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5424 pairs = seq_inner["valueInner"].defined[1]
5426 self.assertIsNone(pair["value"][0].defined)
5428 defines_by_path.append((
5431 DecodePathDefBy(type_sequenced),
5433 DecodePathDefBy(type_innered),
5438 type_integered: Integer(),
5439 type_octet_stringed: OctetString(),
5442 seq_sequenced, _ = Seq().decode(
5444 ctx={"defines_by_path": defines_by_path},
5446 self.assertIsNotNone(seq_sequenced["value"].defined)
5447 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5448 seq_inner = seq_sequenced["value"].defined[1]
5449 self.assertIsNotNone(seq_inner["valueInner"].defined)
5450 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5451 pairs_got = seq_inner["valueInner"].defined[1]
5452 for pair_input, pair_got in zip(pairs_input, pairs_got):
5453 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5454 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5456 @given(oid_strategy(), integers())
5457 def test_simple(self, oid, tgt):
5458 class Inner(Sequence):
5460 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5461 ObjectIdentifier(oid): Integer(),
5465 class Outer(Sequence):
5468 ("tgt", OctetString()),
5472 inner["oid"] = ObjectIdentifier(oid)
5474 outer["inner"] = inner
5475 outer["tgt"] = OctetString(Integer(tgt).encode())
5476 decoded, _ = Outer().decode(outer.encode())
5477 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5480 class TestAbsDecodePath(TestCase):
5482 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5483 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5485 def test_concat(self, decode_path, rel_path):
5486 self.assertSequenceEqual(
5487 abs_decode_path(decode_path, rel_path),
5488 decode_path + rel_path,
5492 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5493 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5495 def test_abs(self, decode_path, rel_path):
5496 self.assertSequenceEqual(
5497 abs_decode_path(decode_path, ("/",) + rel_path),
5502 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5503 integers(min_value=1, max_value=3),
5504 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5506 def test_dots(self, decode_path, number_of_dots, rel_path):
5507 self.assertSequenceEqual(
5508 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5509 decode_path[:-number_of_dots] + rel_path,
5513 class TestStrictDefaultExistence(TestCase):
5514 @given(data_strategy())
5515 def runTest(self, d):
5516 count = d.draw(integers(min_value=1, max_value=10))
5517 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5519 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5520 for i in range(count)
5523 class Seq(Sequence):
5526 for i in range(count):
5527 seq["int%d" % i] = Integer(123)
5529 chosen = "int%d" % chosen
5530 seq.specs[chosen] = seq.specs[chosen](default=123)
5532 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5533 seq.decode(raw, ctx={"strict_default_existence": True})
5536 class TestX690PrefixedType(TestCase):
5538 self.assertSequenceEqual(
5539 VisibleString("Jones").encode(),
5540 hexdec("1A054A6F6E6573"),
5542 self.assertSequenceEqual(
5545 impl=tag_encode(3, klass=TagClassApplication),
5547 hexdec("43054A6F6E6573"),
5549 self.assertSequenceEqual(
5553 impl=tag_encode(3, klass=TagClassApplication),
5557 hexdec("A20743054A6F6E6573"),
5559 self.assertSequenceEqual(
5563 impl=tag_encode(3, klass=TagClassApplication),
5565 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5567 hexdec("670743054A6F6E6573"),
5569 self.assertSequenceEqual(
5570 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5571 hexdec("82054A6F6E6573"),