2 # PyDERASN -- Python ASN.1 DER 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_payload = hexdec("0A3B5F291CD0")
1523 vector = BitString((len(vector_payload) * 8 - 4, vector_payload))
1524 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1525 self.assertSequenceEqual(tail, b"")
1526 self.assertEqual(obj, vector)
1527 obj, tail = BitString().decode(
1528 hexdec("23800303000A3B0305045F291CD00000"),
1529 ctx={"bered": True},
1531 self.assertSequenceEqual(tail, b"")
1532 self.assertEqual(obj, vector)
1533 self.assertTrue(obj.bered)
1534 self.assertTrue(obj.lenindef)
1538 def octet_string_values_strategy(draw, do_expl=False):
1539 bound_min, bound_max = sorted(draw(sets(
1540 integers(min_value=0, max_value=1 << 7),
1544 value = draw(one_of(
1546 binary(min_size=bound_min, max_size=bound_max),
1548 default = draw(one_of(
1550 binary(min_size=bound_min, max_size=bound_max),
1553 if draw(booleans()):
1554 bounds = (bound_min, bound_max)
1558 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1560 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1561 optional = draw(one_of(none(), booleans()))
1563 draw(integers(min_value=0)),
1564 draw(integers(min_value=0)),
1565 draw(integers(min_value=0)),
1567 return (value, bounds, impl, expl, default, optional, _decoded)
1570 class OctetStringInherited(OctetString):
1574 class TestOctetString(CommonMixin, TestCase):
1575 base_klass = OctetString
1577 def test_invalid_value_type(self):
1578 with self.assertRaises(InvalidValueType) as err:
1579 OctetString(text_type(123))
1583 def test_optional(self, optional):
1584 obj = OctetString(default=OctetString(b""), optional=optional)
1585 self.assertTrue(obj.optional)
1588 def test_ready(self, value):
1590 self.assertFalse(obj.ready)
1593 with self.assertRaises(ObjNotReady) as err:
1596 obj = OctetString(value)
1597 self.assertTrue(obj.ready)
1601 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1602 def test_comparison(self, value1, value2, tag1, tag2):
1603 for klass in (OctetString, OctetStringInherited):
1604 obj1 = klass(value1)
1605 obj2 = klass(value2)
1606 self.assertEqual(obj1 == obj2, value1 == value2)
1607 self.assertEqual(obj1 != obj2, value1 != value2)
1608 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1609 obj1 = klass(value1, impl=tag1)
1610 obj2 = klass(value1, impl=tag2)
1611 self.assertEqual(obj1 == obj2, tag1 == tag2)
1612 self.assertEqual(obj1 != obj2, tag1 != tag2)
1614 @given(lists(binary()))
1615 def test_sorted_works(self, values):
1616 self.assertSequenceEqual(
1617 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1621 @given(data_strategy())
1622 def test_bounds_satisfied(self, d):
1623 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1624 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1625 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1626 OctetString(value=value, bounds=(bound_min, bound_max))
1628 @given(data_strategy())
1629 def test_bounds_unsatisfied(self, d):
1630 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1631 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1632 value = d.draw(binary(max_size=bound_min - 1))
1633 with self.assertRaises(BoundsError) as err:
1634 OctetString(value=value, bounds=(bound_min, bound_max))
1636 value = d.draw(binary(min_size=bound_max + 1))
1637 with self.assertRaises(BoundsError) as err:
1638 OctetString(value=value, bounds=(bound_min, bound_max))
1641 @given(data_strategy())
1642 def test_call(self, d):
1643 for klass in (OctetString, OctetStringInherited):
1652 ) = d.draw(octet_string_values_strategy())
1653 obj_initial = klass(
1659 optional_initial or False,
1670 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1671 if (default is None) and (obj_initial.default is not None):
1674 (bounds is None) and
1675 (value is not None) and
1676 (bounds_initial is not None) and
1677 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1681 (bounds is None) and
1682 (default is not None) and
1683 (bounds_initial is not None) and
1684 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1687 obj = obj_initial(value, bounds, impl, expl, default, optional)
1689 value_expected = default if value is None else value
1691 default_initial if value_expected is None
1694 self.assertEqual(obj, value_expected)
1695 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1696 self.assertEqual(obj.expl_tag, expl or expl_initial)
1699 default_initial if default is None else default,
1701 if obj.default is None:
1702 optional = optional_initial if optional is None else optional
1703 optional = False if optional is None else optional
1706 self.assertEqual(obj.optional, optional)
1708 (obj._bound_min, obj._bound_max),
1709 bounds or bounds_initial or (0, float("+inf")),
1712 @given(octet_string_values_strategy())
1713 def test_copy(self, values):
1714 for klass in (OctetString, OctetStringInherited):
1715 obj = klass(*values)
1716 obj_copied = obj.copy()
1717 self.assert_copied_basic_fields(obj, obj_copied)
1718 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1719 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1720 self.assertEqual(obj._value, obj_copied._value)
1724 integers(min_value=1).map(tag_encode),
1726 def test_stripped(self, value, tag_impl):
1727 obj = OctetString(value, impl=tag_impl)
1728 with self.assertRaises(NotEnoughData):
1729 obj.decode(obj.encode()[:-1])
1733 integers(min_value=1).map(tag_ctxc),
1735 def test_stripped_expl(self, value, tag_expl):
1736 obj = OctetString(value, expl=tag_expl)
1737 with self.assertRaises(NotEnoughData):
1738 obj.decode(obj.encode()[:-1])
1741 integers(min_value=31),
1742 integers(min_value=0),
1745 def test_bad_tag(self, tag, offset, decode_path):
1746 decode_path = tuple(str(i) for i in decode_path)
1747 with self.assertRaises(DecodeError) as err:
1748 OctetString().decode(
1749 tag_encode(tag)[:-1],
1751 decode_path=decode_path,
1754 self.assertEqual(err.exception.offset, offset)
1755 self.assertEqual(err.exception.decode_path, decode_path)
1758 integers(min_value=128),
1759 integers(min_value=0),
1762 def test_bad_len(self, l, offset, decode_path):
1763 decode_path = tuple(str(i) for i in decode_path)
1764 with self.assertRaises(DecodeError) as err:
1765 OctetString().decode(
1766 OctetString.tag_default + len_encode(l)[:-1],
1768 decode_path=decode_path,
1771 self.assertEqual(err.exception.offset, offset)
1772 self.assertEqual(err.exception.decode_path, decode_path)
1775 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1776 integers(min_value=0),
1779 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1780 decode_path = tuple(str(i) for i in decode_path)
1781 value, bound_min = list(sorted(ints))
1783 class String(OctetString):
1784 bounds = (bound_min, bound_min)
1785 with self.assertRaises(DecodeError) as err:
1787 OctetString(b"\x00" * value).encode(),
1789 decode_path=decode_path,
1792 self.assertEqual(err.exception.offset, offset)
1793 self.assertEqual(err.exception.decode_path, decode_path)
1795 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1797 octet_string_values_strategy(),
1799 integers(min_value=1).map(tag_ctxc),
1800 integers(min_value=0),
1803 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1804 for klass in (OctetString, OctetStringInherited):
1805 _, _, _, _, default, optional, _decoded = values
1814 self.assertFalse(obj.expled)
1815 obj_encoded = obj.encode()
1816 obj_expled = obj(value, expl=tag_expl)
1817 self.assertTrue(obj_expled.expled)
1820 obj_expled_encoded = obj_expled.encode()
1821 obj_decoded, tail = obj_expled.decode(
1822 obj_expled_encoded + tail_junk,
1827 self.assertEqual(tail, tail_junk)
1828 self.assertEqual(obj_decoded, obj_expled)
1829 self.assertNotEqual(obj_decoded, obj)
1830 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1831 self.assertEqual(bytes(obj_decoded), bytes(obj))
1832 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1833 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1834 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1836 obj_decoded.expl_llen,
1837 len(len_encode(len(obj_encoded))),
1839 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1840 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1843 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1845 self.assertEqual(obj_decoded.expl_offset, offset)
1848 integers(min_value=1, max_value=30),
1851 binary(min_size=1, max_size=5),
1853 binary(min_size=1, max_size=5),
1862 def test_constructed(self, impl, chunk_inputs):
1863 def chunk_constructed(contents):
1865 tag_encode(form=TagFormConstructed, num=4) +
1867 b"".join(OctetString(content).encode() for content in contents) +
1871 payload_expected = b""
1872 for chunk_input in chunk_inputs:
1873 if isinstance(chunk_input, binary_type):
1874 chunks.append(OctetString(chunk_input).encode())
1875 payload_expected += chunk_input
1877 chunks.append(chunk_constructed(chunk_input))
1878 payload = b"".join(chunk_input)
1879 payload_expected += payload
1880 encoded_indefinite = (
1881 tag_encode(form=TagFormConstructed, num=impl) +
1886 encoded_definite = (
1887 tag_encode(form=TagFormConstructed, num=impl) +
1888 len_encode(len(b"".join(chunks))) +
1891 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1892 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
1893 for lenindef_expected, encoded in (
1894 (True, encoded_indefinite),
1895 (False, encoded_definite),
1897 obj, tail = OctetString(impl=tag_encode(impl)).decode(
1898 encoded, ctx={"bered": True}
1900 self.assertSequenceEqual(tail, b"")
1901 self.assertSequenceEqual(bytes(obj), payload_expected)
1902 self.assertTrue(obj.bered)
1903 self.assertEqual(obj.lenindef, lenindef_expected)
1904 self.assertEqual(len(encoded), obj.tlvlen)
1908 def null_values_strategy(draw, do_expl=False):
1912 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1914 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1915 optional = draw(one_of(none(), booleans()))
1917 draw(integers(min_value=0)),
1918 draw(integers(min_value=0)),
1919 draw(integers(min_value=0)),
1921 return (impl, expl, optional, _decoded)
1924 class NullInherited(Null):
1928 class TestNull(CommonMixin, TestCase):
1931 def test_ready(self):
1933 self.assertTrue(obj.ready)
1937 @given(binary(), binary())
1938 def test_comparison(self, tag1, tag2):
1939 for klass in (Null, NullInherited):
1940 obj1 = klass(impl=tag1)
1941 obj2 = klass(impl=tag2)
1942 self.assertEqual(obj1 == obj2, tag1 == tag2)
1943 self.assertEqual(obj1 != obj2, tag1 != tag2)
1944 self.assertNotEqual(obj1, tag2)
1946 @given(data_strategy())
1947 def test_call(self, d):
1948 for klass in (Null, NullInherited):
1954 ) = d.draw(null_values_strategy())
1955 obj_initial = klass(
1958 optional=optional_initial or False,
1959 _decoded=_decoded_initial,
1966 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
1967 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1968 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1969 self.assertEqual(obj.expl_tag, expl or expl_initial)
1970 optional = optional_initial if optional is None else optional
1971 optional = False if optional is None else optional
1972 self.assertEqual(obj.optional, optional)
1974 @given(null_values_strategy())
1975 def test_copy(self, values):
1976 for klass in (Null, NullInherited):
1977 impl, expl, optional, _decoded = values
1981 optional=optional or False,
1984 obj_copied = obj.copy()
1985 self.assert_copied_basic_fields(obj, obj_copied)
1987 @given(integers(min_value=1).map(tag_encode))
1988 def test_stripped(self, tag_impl):
1989 obj = Null(impl=tag_impl)
1990 with self.assertRaises(NotEnoughData):
1991 obj.decode(obj.encode()[:-1])
1993 @given(integers(min_value=1).map(tag_ctxc))
1994 def test_stripped_expl(self, tag_expl):
1995 obj = Null(expl=tag_expl)
1996 with self.assertRaises(NotEnoughData):
1997 obj.decode(obj.encode()[:-1])
2000 integers(min_value=31),
2001 integers(min_value=0),
2004 def test_bad_tag(self, tag, offset, decode_path):
2005 decode_path = tuple(str(i) for i in decode_path)
2006 with self.assertRaises(DecodeError) as err:
2008 tag_encode(tag)[:-1],
2010 decode_path=decode_path,
2013 self.assertEqual(err.exception.offset, offset)
2014 self.assertEqual(err.exception.decode_path, decode_path)
2017 integers(min_value=128),
2018 integers(min_value=0),
2021 def test_bad_len(self, l, offset, decode_path):
2022 decode_path = tuple(str(i) for i in decode_path)
2023 with self.assertRaises(DecodeError) as err:
2025 Null.tag_default + len_encode(l)[:-1],
2027 decode_path=decode_path,
2030 self.assertEqual(err.exception.offset, offset)
2031 self.assertEqual(err.exception.decode_path, decode_path)
2033 @given(binary(min_size=1))
2034 def test_tag_mismatch(self, impl):
2035 assume(impl != Null.tag_default)
2036 with self.assertRaises(TagMismatch):
2037 Null(impl=impl).decode(Null().encode())
2040 null_values_strategy(),
2041 integers(min_value=1).map(tag_ctxc),
2042 integers(min_value=0),
2045 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2046 for klass in (Null, NullInherited):
2047 _, _, optional, _decoded = values
2048 obj = klass(optional=optional, _decoded=_decoded)
2051 self.assertFalse(obj.expled)
2052 obj_encoded = obj.encode()
2053 obj_expled = obj(expl=tag_expl)
2054 self.assertTrue(obj_expled.expled)
2057 obj_expled_encoded = obj_expled.encode()
2058 obj_decoded, tail = obj_expled.decode(
2059 obj_expled_encoded + tail_junk,
2064 self.assertEqual(tail, tail_junk)
2065 self.assertEqual(obj_decoded, obj_expled)
2066 self.assertNotEqual(obj_decoded, obj)
2067 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2068 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2069 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2071 obj_decoded.expl_llen,
2072 len(len_encode(len(obj_encoded))),
2074 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2075 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2078 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2080 self.assertEqual(obj_decoded.expl_offset, offset)
2082 @given(integers(min_value=1))
2083 def test_invalid_len(self, l):
2084 with self.assertRaises(InvalidLength):
2085 Null().decode(b"".join((
2092 def oid_strategy(draw):
2093 first_arc = draw(integers(min_value=0, max_value=2))
2095 if first_arc in (0, 1):
2096 second_arc = draw(integers(min_value=0, max_value=39))
2098 second_arc = draw(integers(min_value=0))
2099 other_arcs = draw(lists(integers(min_value=0)))
2100 return tuple([first_arc, second_arc] + other_arcs)
2104 def oid_values_strategy(draw, do_expl=False):
2105 value = draw(one_of(none(), oid_strategy()))
2109 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2111 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2112 default = draw(one_of(none(), oid_strategy()))
2113 optional = draw(one_of(none(), booleans()))
2115 draw(integers(min_value=0)),
2116 draw(integers(min_value=0)),
2117 draw(integers(min_value=0)),
2119 return (value, impl, expl, default, optional, _decoded)
2122 class ObjectIdentifierInherited(ObjectIdentifier):
2126 class TestObjectIdentifier(CommonMixin, TestCase):
2127 base_klass = ObjectIdentifier
2129 def test_invalid_value_type(self):
2130 with self.assertRaises(InvalidValueType) as err:
2131 ObjectIdentifier(123)
2135 def test_optional(self, optional):
2136 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2137 self.assertTrue(obj.optional)
2139 @given(oid_strategy())
2140 def test_ready(self, value):
2141 obj = ObjectIdentifier()
2142 self.assertFalse(obj.ready)
2145 with self.assertRaises(ObjNotReady) as err:
2148 obj = ObjectIdentifier(value)
2149 self.assertTrue(obj.ready)
2154 @given(oid_strategy(), oid_strategy(), binary(), binary())
2155 def test_comparison(self, value1, value2, tag1, tag2):
2156 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2157 obj1 = klass(value1)
2158 obj2 = klass(value2)
2159 self.assertEqual(obj1 == obj2, value1 == value2)
2160 self.assertEqual(obj1 != obj2, value1 != value2)
2161 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2162 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2163 obj1 = klass(value1, impl=tag1)
2164 obj2 = klass(value1, impl=tag2)
2165 self.assertEqual(obj1 == obj2, tag1 == tag2)
2166 self.assertEqual(obj1 != obj2, tag1 != tag2)
2168 @given(lists(oid_strategy()))
2169 def test_sorted_works(self, values):
2170 self.assertSequenceEqual(
2171 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2175 @given(data_strategy())
2176 def test_call(self, d):
2177 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2185 ) = d.draw(oid_values_strategy())
2186 obj_initial = klass(
2187 value=value_initial,
2190 default=default_initial,
2191 optional=optional_initial or False,
2192 _decoded=_decoded_initial,
2201 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2210 value_expected = default if value is None else value
2212 default_initial if value_expected is None
2215 self.assertEqual(obj, value_expected)
2216 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2217 self.assertEqual(obj.expl_tag, expl or expl_initial)
2220 default_initial if default is None else default,
2222 if obj.default is None:
2223 optional = optional_initial if optional is None else optional
2224 optional = False if optional is None else optional
2227 self.assertEqual(obj.optional, optional)
2229 @given(oid_values_strategy())
2230 def test_copy(self, values):
2231 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2248 obj_copied = obj.copy()
2249 self.assert_copied_basic_fields(obj, obj_copied)
2250 self.assertEqual(obj._value, obj_copied._value)
2252 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2255 integers(min_value=1).map(tag_encode),
2257 def test_stripped(self, value, tag_impl):
2258 obj = ObjectIdentifier(value, impl=tag_impl)
2259 with self.assertRaises(NotEnoughData):
2260 obj.decode(obj.encode()[:-1])
2264 integers(min_value=1).map(tag_ctxc),
2266 def test_stripped_expl(self, value, tag_expl):
2267 obj = ObjectIdentifier(value, expl=tag_expl)
2268 with self.assertRaises(NotEnoughData):
2269 obj.decode(obj.encode()[:-1])
2272 integers(min_value=31),
2273 integers(min_value=0),
2276 def test_bad_tag(self, tag, offset, decode_path):
2277 decode_path = tuple(str(i) for i in decode_path)
2278 with self.assertRaises(DecodeError) as err:
2279 ObjectIdentifier().decode(
2280 tag_encode(tag)[:-1],
2282 decode_path=decode_path,
2285 self.assertEqual(err.exception.offset, offset)
2286 self.assertEqual(err.exception.decode_path, decode_path)
2289 integers(min_value=128),
2290 integers(min_value=0),
2293 def test_bad_len(self, l, offset, decode_path):
2294 decode_path = tuple(str(i) for i in decode_path)
2295 with self.assertRaises(DecodeError) as err:
2296 ObjectIdentifier().decode(
2297 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2299 decode_path=decode_path,
2302 self.assertEqual(err.exception.offset, offset)
2303 self.assertEqual(err.exception.decode_path, decode_path)
2305 def test_zero_oid(self):
2306 with self.assertRaises(NotEnoughData):
2307 ObjectIdentifier().decode(
2308 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2311 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2312 @given(oid_strategy())
2313 def test_unfinished_oid(self, value):
2314 assume(list(value)[-1] > 255)
2315 obj_encoded = ObjectIdentifier(value).encode()
2316 obj, _ = ObjectIdentifier().decode(obj_encoded)
2317 data = obj_encoded[obj.tlen + obj.llen:-1]
2319 ObjectIdentifier.tag_default,
2320 len_encode(len(data)),
2323 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2326 @given(integers(min_value=0))
2327 def test_invalid_short(self, value):
2328 with self.assertRaises(InvalidOID):
2329 ObjectIdentifier((value,))
2330 with self.assertRaises(InvalidOID):
2331 ObjectIdentifier("%d" % value)
2333 @given(integers(min_value=3), integers(min_value=0))
2334 def test_invalid_first_arc(self, first_arc, second_arc):
2335 with self.assertRaises(InvalidOID):
2336 ObjectIdentifier((first_arc, second_arc))
2337 with self.assertRaises(InvalidOID):
2338 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2340 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2341 def test_invalid_second_arc(self, first_arc, second_arc):
2342 with self.assertRaises(InvalidOID):
2343 ObjectIdentifier((first_arc, second_arc))
2344 with self.assertRaises(InvalidOID):
2345 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2347 @given(text(alphabet=ascii_letters + ".", min_size=1))
2348 def test_junk(self, oid):
2349 with self.assertRaises(InvalidOID):
2350 ObjectIdentifier(oid)
2352 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2353 @given(oid_strategy())
2354 def test_validness(self, oid):
2355 obj = ObjectIdentifier(oid)
2356 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2361 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2363 oid_values_strategy(),
2365 integers(min_value=1).map(tag_ctxc),
2366 integers(min_value=0),
2369 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2370 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2371 _, _, _, default, optional, _decoded = values
2380 self.assertFalse(obj.expled)
2381 obj_encoded = obj.encode()
2382 obj_expled = obj(value, expl=tag_expl)
2383 self.assertTrue(obj_expled.expled)
2386 obj_expled_encoded = obj_expled.encode()
2387 obj_decoded, tail = obj_expled.decode(
2388 obj_expled_encoded + tail_junk,
2393 self.assertEqual(tail, tail_junk)
2394 self.assertEqual(obj_decoded, obj_expled)
2395 self.assertNotEqual(obj_decoded, obj)
2396 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2397 self.assertEqual(tuple(obj_decoded), tuple(obj))
2398 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2399 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2400 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2402 obj_decoded.expl_llen,
2403 len(len_encode(len(obj_encoded))),
2405 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2406 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2409 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2411 self.assertEqual(obj_decoded.expl_offset, offset)
2414 oid_strategy().map(ObjectIdentifier),
2415 oid_strategy().map(ObjectIdentifier),
2417 def test_add(self, oid1, oid2):
2418 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2419 for oid_to_add in (oid2, tuple(oid2)):
2420 self.assertEqual(oid1 + oid_to_add, oid_expect)
2421 with self.assertRaises(InvalidValueType):
2424 def test_go_vectors_valid(self):
2425 for data, expect in (
2427 (b"\x55\x02", (2, 5, 2)),
2428 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2429 (b"\x81\x34\x03", (2, 100, 3)),
2432 ObjectIdentifier().decode(b"".join((
2433 ObjectIdentifier.tag_default,
2434 len_encode(len(data)),
2440 def test_go_vectors_invalid(self):
2441 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2442 with self.assertRaises(DecodeError):
2443 ObjectIdentifier().decode(b"".join((
2444 Integer.tag_default,
2445 len_encode(len(data)),
2449 def test_x690_vector(self):
2451 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2452 ObjectIdentifier((2, 999, 3)),
2457 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2459 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2460 values = list(draw(sets(
2462 min_size=len(schema),
2463 max_size=len(schema),
2465 schema = list(zip(schema, values))
2466 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2470 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2472 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2473 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2474 optional = draw(one_of(none(), booleans()))
2476 draw(integers(min_value=0)),
2477 draw(integers(min_value=0)),
2478 draw(integers(min_value=0)),
2480 return (schema, value, impl, expl, default, optional, _decoded)
2483 class TestEnumerated(CommonMixin, TestCase):
2484 class EWhatever(Enumerated):
2485 schema = (("whatever", 0),)
2487 base_klass = EWhatever
2489 def test_schema_required(self):
2490 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2493 def test_invalid_value_type(self):
2494 with self.assertRaises(InvalidValueType) as err:
2495 self.base_klass((1, 2))
2498 @given(sets(text_letters(), min_size=2))
2499 def test_unknown_name(self, schema_input):
2500 missing = schema_input.pop()
2502 class E(Enumerated):
2503 schema = [(n, 123) for n in schema_input]
2504 with self.assertRaises(ObjUnknown) as err:
2509 sets(text_letters(), min_size=2),
2510 sets(integers(), min_size=2),
2512 def test_unknown_value(self, schema_input, values_input):
2514 missing_value = values_input.pop()
2515 _input = list(zip(schema_input, values_input))
2517 class E(Enumerated):
2519 with self.assertRaises(DecodeError) as err:
2524 def test_optional(self, optional):
2525 obj = self.base_klass(default="whatever", optional=optional)
2526 self.assertTrue(obj.optional)
2528 def test_ready(self):
2529 obj = self.base_klass()
2530 self.assertFalse(obj.ready)
2533 with self.assertRaises(ObjNotReady) as err:
2536 obj = self.base_klass("whatever")
2537 self.assertTrue(obj.ready)
2541 @given(integers(), integers(), binary(), binary())
2542 def test_comparison(self, value1, value2, tag1, tag2):
2543 class E(Enumerated):
2545 ("whatever0", value1),
2546 ("whatever1", value2),
2549 class EInherited(E):
2551 for klass in (E, EInherited):
2552 obj1 = klass(value1)
2553 obj2 = klass(value2)
2554 self.assertEqual(obj1 == obj2, value1 == value2)
2555 self.assertEqual(obj1 != obj2, value1 != value2)
2556 self.assertEqual(obj1 == int(obj2), value1 == value2)
2557 obj1 = klass(value1, impl=tag1)
2558 obj2 = klass(value1, impl=tag2)
2559 self.assertEqual(obj1 == obj2, tag1 == tag2)
2560 self.assertEqual(obj1 != obj2, tag1 != tag2)
2562 @given(data_strategy())
2563 def test_call(self, d):
2572 ) = d.draw(enumerated_values_strategy())
2574 class E(Enumerated):
2575 schema = schema_initial
2577 value=value_initial,
2580 default=default_initial,
2581 optional=optional_initial or False,
2582 _decoded=_decoded_initial,
2592 ) = d.draw(enumerated_values_strategy(
2593 schema=schema_initial,
2594 do_expl=impl_initial is None,
2604 value_expected = default if value is None else value
2606 default_initial if value_expected is None
2611 dict(schema_initial).get(value_expected, value_expected),
2613 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2614 self.assertEqual(obj.expl_tag, expl or expl_initial)
2617 default_initial if default is None else default,
2619 if obj.default is None:
2620 optional = optional_initial if optional is None else optional
2621 optional = False if optional is None else optional
2624 self.assertEqual(obj.optional, optional)
2625 self.assertEqual(obj.specs, dict(schema_initial))
2627 @given(enumerated_values_strategy())
2628 def test_copy(self, values):
2629 schema_input, value, impl, expl, default, optional, _decoded = values
2631 class E(Enumerated):
2632 schema = schema_input
2641 obj_copied = obj.copy()
2642 self.assert_copied_basic_fields(obj, obj_copied)
2643 self.assertEqual(obj.specs, obj_copied.specs)
2645 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2646 @given(data_strategy())
2647 def test_symmetric(self, d):
2648 schema_input, _, _, _, default, optional, _decoded = d.draw(
2649 enumerated_values_strategy(),
2651 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2652 offset = d.draw(integers(min_value=0))
2653 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2654 tail_junk = d.draw(binary(max_size=5))
2656 class E(Enumerated):
2657 schema = schema_input
2666 self.assertFalse(obj.expled)
2667 obj_encoded = obj.encode()
2668 obj_expled = obj(value, expl=tag_expl)
2669 self.assertTrue(obj_expled.expled)
2672 obj_expled_encoded = obj_expled.encode()
2673 obj_decoded, tail = obj_expled.decode(
2674 obj_expled_encoded + tail_junk,
2679 self.assertEqual(tail, tail_junk)
2680 self.assertEqual(obj_decoded, obj_expled)
2681 self.assertNotEqual(obj_decoded, obj)
2682 self.assertEqual(int(obj_decoded), int(obj_expled))
2683 self.assertEqual(int(obj_decoded), int(obj))
2684 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2685 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2686 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2688 obj_decoded.expl_llen,
2689 len(len_encode(len(obj_encoded))),
2691 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2692 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2695 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2697 self.assertEqual(obj_decoded.expl_offset, offset)
2701 def string_values_strategy(draw, alphabet, do_expl=False):
2702 bound_min, bound_max = sorted(draw(sets(
2703 integers(min_value=0, max_value=1 << 7),
2707 value = draw(one_of(
2709 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2711 default = draw(one_of(
2713 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2716 if draw(booleans()):
2717 bounds = (bound_min, bound_max)
2721 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2723 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2724 optional = draw(one_of(none(), booleans()))
2726 draw(integers(min_value=0)),
2727 draw(integers(min_value=0)),
2728 draw(integers(min_value=0)),
2730 return (value, bounds, impl, expl, default, optional, _decoded)
2733 class StringMixin(object):
2734 def test_invalid_value_type(self):
2735 with self.assertRaises(InvalidValueType) as err:
2736 self.base_klass((1, 2))
2739 def text_alphabet(self):
2740 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2741 return printable + whitespace
2745 def test_optional(self, optional):
2746 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2747 self.assertTrue(obj.optional)
2749 @given(data_strategy())
2750 def test_ready(self, d):
2751 obj = self.base_klass()
2752 self.assertFalse(obj.ready)
2756 with self.assertRaises(ObjNotReady) as err:
2759 value = d.draw(text(alphabet=self.text_alphabet()))
2760 obj = self.base_klass(value)
2761 self.assertTrue(obj.ready)
2766 @given(data_strategy())
2767 def test_comparison(self, d):
2768 value1 = d.draw(text(alphabet=self.text_alphabet()))
2769 value2 = d.draw(text(alphabet=self.text_alphabet()))
2770 tag1 = d.draw(binary(min_size=1))
2771 tag2 = d.draw(binary(min_size=1))
2772 obj1 = self.base_klass(value1)
2773 obj2 = self.base_klass(value2)
2774 self.assertEqual(obj1 == obj2, value1 == value2)
2775 self.assertEqual(obj1 != obj2, value1 != value2)
2776 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2777 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2778 obj1 = self.base_klass(value1, impl=tag1)
2779 obj2 = self.base_klass(value1, impl=tag2)
2780 self.assertEqual(obj1 == obj2, tag1 == tag2)
2781 self.assertEqual(obj1 != obj2, tag1 != tag2)
2783 @given(data_strategy())
2784 def test_bounds_satisfied(self, d):
2785 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2786 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2787 value = d.draw(text(
2788 alphabet=self.text_alphabet(),
2792 self.base_klass(value=value, bounds=(bound_min, bound_max))
2794 @given(data_strategy())
2795 def test_bounds_unsatisfied(self, d):
2796 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2797 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2798 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2799 with self.assertRaises(BoundsError) as err:
2800 self.base_klass(value=value, bounds=(bound_min, bound_max))
2802 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2803 with self.assertRaises(BoundsError) as err:
2804 self.base_klass(value=value, bounds=(bound_min, bound_max))
2807 @given(data_strategy())
2808 def test_call(self, d):
2817 ) = d.draw(string_values_strategy(self.text_alphabet()))
2818 obj_initial = self.base_klass(
2824 optional_initial or False,
2835 ) = d.draw(string_values_strategy(
2836 self.text_alphabet(),
2837 do_expl=impl_initial is None,
2839 if (default is None) and (obj_initial.default is not None):
2842 (bounds is None) and
2843 (value is not None) and
2844 (bounds_initial is not None) and
2845 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2849 (bounds is None) and
2850 (default is not None) and
2851 (bounds_initial is not None) and
2852 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2855 obj = obj_initial(value, bounds, impl, expl, default, optional)
2857 value_expected = default if value is None else value
2859 default_initial if value_expected is None
2862 self.assertEqual(obj, value_expected)
2863 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2864 self.assertEqual(obj.expl_tag, expl or expl_initial)
2867 default_initial if default is None else default,
2869 if obj.default is None:
2870 optional = optional_initial if optional is None else optional
2871 optional = False if optional is None else optional
2874 self.assertEqual(obj.optional, optional)
2876 (obj._bound_min, obj._bound_max),
2877 bounds or bounds_initial or (0, float("+inf")),
2880 @given(data_strategy())
2881 def test_copy(self, d):
2882 values = d.draw(string_values_strategy(self.text_alphabet()))
2883 obj = self.base_klass(*values)
2884 obj_copied = obj.copy()
2885 self.assert_copied_basic_fields(obj, obj_copied)
2886 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2887 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2888 self.assertEqual(obj._value, obj_copied._value)
2890 @given(data_strategy())
2891 def test_stripped(self, d):
2892 value = d.draw(text(alphabet=self.text_alphabet()))
2893 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2894 obj = self.base_klass(value, impl=tag_impl)
2895 with self.assertRaises(NotEnoughData):
2896 obj.decode(obj.encode()[:-1])
2898 @given(data_strategy())
2899 def test_stripped_expl(self, d):
2900 value = d.draw(text(alphabet=self.text_alphabet()))
2901 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2902 obj = self.base_klass(value, expl=tag_expl)
2903 with self.assertRaises(NotEnoughData):
2904 obj.decode(obj.encode()[:-1])
2907 integers(min_value=31),
2908 integers(min_value=0),
2911 def test_bad_tag(self, tag, offset, decode_path):
2912 decode_path = tuple(str(i) for i in decode_path)
2913 with self.assertRaises(DecodeError) as err:
2914 self.base_klass().decode(
2915 tag_encode(tag)[:-1],
2917 decode_path=decode_path,
2920 self.assertEqual(err.exception.offset, offset)
2921 self.assertEqual(err.exception.decode_path, decode_path)
2924 integers(min_value=128),
2925 integers(min_value=0),
2928 def test_bad_len(self, l, offset, decode_path):
2929 decode_path = tuple(str(i) for i in decode_path)
2930 with self.assertRaises(DecodeError) as err:
2931 self.base_klass().decode(
2932 self.base_klass.tag_default + len_encode(l)[:-1],
2934 decode_path=decode_path,
2937 self.assertEqual(err.exception.offset, offset)
2938 self.assertEqual(err.exception.decode_path, decode_path)
2941 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2942 integers(min_value=0),
2945 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2946 decode_path = tuple(str(i) for i in decode_path)
2947 value, bound_min = list(sorted(ints))
2949 class String(self.base_klass):
2950 # Multiply this value by four, to satisfy UTF-32 bounds
2951 # (4 bytes per character) validation
2952 bounds = (bound_min * 4, bound_min * 4)
2953 with self.assertRaises(DecodeError) as err:
2955 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2957 decode_path=decode_path,
2960 self.assertEqual(err.exception.offset, offset)
2961 self.assertEqual(err.exception.decode_path, decode_path)
2963 @given(data_strategy())
2964 def test_symmetric(self, d):
2965 values = d.draw(string_values_strategy(self.text_alphabet()))
2966 value = d.draw(text(alphabet=self.text_alphabet()))
2967 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2968 offset = d.draw(integers(min_value=0))
2969 tail_junk = d.draw(binary(max_size=5))
2970 _, _, _, _, default, optional, _decoded = values
2971 obj = self.base_klass(
2979 self.assertFalse(obj.expled)
2980 obj_encoded = obj.encode()
2981 obj_expled = obj(value, expl=tag_expl)
2982 self.assertTrue(obj_expled.expled)
2985 obj_expled_encoded = obj_expled.encode()
2986 obj_decoded, tail = obj_expled.decode(
2987 obj_expled_encoded + tail_junk,
2992 self.assertEqual(tail, tail_junk)
2993 self.assertEqual(obj_decoded, obj_expled)
2994 self.assertNotEqual(obj_decoded, obj)
2995 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2996 self.assertEqual(bytes(obj_decoded), bytes(obj))
2997 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2998 self.assertEqual(text_type(obj_decoded), text_type(obj))
2999 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3000 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3001 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3003 obj_decoded.expl_llen,
3004 len(len_encode(len(obj_encoded))),
3006 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3007 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3010 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3012 self.assertEqual(obj_decoded.expl_offset, offset)
3015 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3016 base_klass = UTF8String
3019 class UnicodeDecodeErrorMixin(object):
3021 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3025 def test_unicode_decode_error(self, cyrillic_text):
3026 with self.assertRaises(DecodeError):
3027 self.base_klass(cyrillic_text)
3030 class TestNumericString(StringMixin, CommonMixin, TestCase):
3031 base_klass = NumericString
3033 def text_alphabet(self):
3036 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3037 def test_non_numeric(self, cyrillic_text):
3038 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3039 self.base_klass(cyrillic_text)
3042 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3043 integers(min_value=0),
3046 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3047 decode_path = tuple(str(i) for i in decode_path)
3048 value, bound_min = list(sorted(ints))
3050 class String(self.base_klass):
3051 bounds = (bound_min, bound_min)
3052 with self.assertRaises(DecodeError) as err:
3054 self.base_klass(b"1" * value).encode(),
3056 decode_path=decode_path,
3059 self.assertEqual(err.exception.offset, offset)
3060 self.assertEqual(err.exception.decode_path, decode_path)
3063 class TestPrintableString(
3064 UnicodeDecodeErrorMixin,
3069 base_klass = PrintableString
3072 class TestTeletexString(
3073 UnicodeDecodeErrorMixin,
3078 base_klass = TeletexString
3081 class TestVideotexString(
3082 UnicodeDecodeErrorMixin,
3087 base_klass = VideotexString
3090 class TestIA5String(
3091 UnicodeDecodeErrorMixin,
3096 base_klass = IA5String
3099 class TestGraphicString(
3100 UnicodeDecodeErrorMixin,
3105 base_klass = GraphicString
3108 class TestVisibleString(
3109 UnicodeDecodeErrorMixin,
3114 base_klass = VisibleString
3116 def test_x690_vector(self):
3117 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3118 self.assertSequenceEqual(tail, b"")
3119 self.assertEqual(str(obj), "Jones")
3120 self.assertFalse(obj.bered)
3121 self.assertFalse(obj.lenindef)
3123 obj, tail = VisibleString().decode(
3124 hexdec("3A0904034A6F6E04026573"),
3125 ctx={"bered": True},
3127 self.assertSequenceEqual(tail, b"")
3128 self.assertEqual(str(obj), "Jones")
3129 self.assertTrue(obj.bered)
3130 self.assertFalse(obj.lenindef)
3132 obj, tail = VisibleString().decode(
3133 hexdec("3A8004034A6F6E040265730000"),
3134 ctx={"bered": True},
3136 self.assertSequenceEqual(tail, b"")
3137 self.assertEqual(str(obj), "Jones")
3138 self.assertTrue(obj.bered)
3139 self.assertTrue(obj.lenindef)
3142 class TestGeneralString(
3143 UnicodeDecodeErrorMixin,
3148 base_klass = GeneralString
3151 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3152 base_klass = UniversalString
3155 class TestBMPString(StringMixin, CommonMixin, TestCase):
3156 base_klass = BMPString
3160 def generalized_time_values_strategy(
3168 if draw(booleans()):
3169 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3171 value = value.replace(microsecond=0)
3173 if draw(booleans()):
3174 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3176 default = default.replace(microsecond=0)
3180 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3182 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3183 optional = draw(one_of(none(), booleans()))
3185 draw(integers(min_value=0)),
3186 draw(integers(min_value=0)),
3187 draw(integers(min_value=0)),
3189 return (value, impl, expl, default, optional, _decoded)
3192 class TimeMixin(object):
3193 def test_invalid_value_type(self):
3194 with self.assertRaises(InvalidValueType) as err:
3195 self.base_klass(datetime.now().timetuple())
3198 @given(data_strategy())
3199 def test_optional(self, d):
3200 default = d.draw(datetimes(
3201 min_value=self.min_datetime,
3202 max_value=self.max_datetime,
3204 optional = d.draw(booleans())
3205 obj = self.base_klass(default=default, optional=optional)
3206 self.assertTrue(obj.optional)
3208 @given(data_strategy())
3209 def test_ready(self, d):
3210 obj = self.base_klass()
3211 self.assertFalse(obj.ready)
3214 with self.assertRaises(ObjNotReady) as err:
3217 value = d.draw(datetimes(min_value=self.min_datetime))
3218 obj = self.base_klass(value)
3219 self.assertTrue(obj.ready)
3223 @given(data_strategy())
3224 def test_comparison(self, d):
3225 value1 = d.draw(datetimes(
3226 min_value=self.min_datetime,
3227 max_value=self.max_datetime,
3229 value2 = d.draw(datetimes(
3230 min_value=self.min_datetime,
3231 max_value=self.max_datetime,
3233 tag1 = d.draw(binary(min_size=1))
3234 tag2 = d.draw(binary(min_size=1))
3236 value1 = value1.replace(microsecond=0)
3237 value2 = value2.replace(microsecond=0)
3238 obj1 = self.base_klass(value1)
3239 obj2 = self.base_klass(value2)
3240 self.assertEqual(obj1 == obj2, value1 == value2)
3241 self.assertEqual(obj1 != obj2, value1 != value2)
3242 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3243 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3244 obj1 = self.base_klass(value1, impl=tag1)
3245 obj2 = self.base_klass(value1, impl=tag2)
3246 self.assertEqual(obj1 == obj2, tag1 == tag2)
3247 self.assertEqual(obj1 != obj2, tag1 != tag2)
3249 @given(data_strategy())
3250 def test_call(self, d):
3258 ) = d.draw(generalized_time_values_strategy(
3259 min_datetime=self.min_datetime,
3260 max_datetime=self.max_datetime,
3261 omit_ms=self.omit_ms,
3263 obj_initial = self.base_klass(
3264 value=value_initial,
3267 default=default_initial,
3268 optional=optional_initial or False,
3269 _decoded=_decoded_initial,
3278 ) = d.draw(generalized_time_values_strategy(
3279 min_datetime=self.min_datetime,
3280 max_datetime=self.max_datetime,
3281 omit_ms=self.omit_ms,
3282 do_expl=impl_initial is None,
3292 value_expected = default if value is None else value
3294 default_initial if value_expected is None
3297 self.assertEqual(obj, value_expected)
3298 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3299 self.assertEqual(obj.expl_tag, expl or expl_initial)
3302 default_initial if default is None else default,
3304 if obj.default is None:
3305 optional = optional_initial if optional is None else optional
3306 optional = False if optional is None else optional
3309 self.assertEqual(obj.optional, optional)
3311 @given(data_strategy())
3312 def test_copy(self, d):
3313 values = d.draw(generalized_time_values_strategy(
3314 min_datetime=self.min_datetime,
3315 max_datetime=self.max_datetime,
3317 obj = self.base_klass(*values)
3318 obj_copied = obj.copy()
3319 self.assert_copied_basic_fields(obj, obj_copied)
3320 self.assertEqual(obj._value, obj_copied._value)
3322 @given(data_strategy())
3323 def test_stripped(self, d):
3324 value = d.draw(datetimes(
3325 min_value=self.min_datetime,
3326 max_value=self.max_datetime,
3328 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3329 obj = self.base_klass(value, impl=tag_impl)
3330 with self.assertRaises(NotEnoughData):
3331 obj.decode(obj.encode()[:-1])
3333 @given(data_strategy())
3334 def test_stripped_expl(self, d):
3335 value = d.draw(datetimes(
3336 min_value=self.min_datetime,
3337 max_value=self.max_datetime,
3339 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3340 obj = self.base_klass(value, expl=tag_expl)
3341 with self.assertRaises(NotEnoughData):
3342 obj.decode(obj.encode()[:-1])
3344 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3345 @given(data_strategy())
3346 def test_symmetric(self, d):
3347 values = d.draw(generalized_time_values_strategy(
3348 min_datetime=self.min_datetime,
3349 max_datetime=self.max_datetime,
3351 value = d.draw(datetimes(
3352 min_value=self.min_datetime,
3353 max_value=self.max_datetime,
3355 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3356 offset = d.draw(integers(min_value=0))
3357 tail_junk = d.draw(binary(max_size=5))
3358 _, _, _, default, optional, _decoded = values
3359 obj = self.base_klass(
3367 self.assertFalse(obj.expled)
3368 obj_encoded = obj.encode()
3369 obj_expled = obj(value, expl=tag_expl)
3370 self.assertTrue(obj_expled.expled)
3373 obj_expled_encoded = obj_expled.encode()
3374 obj_decoded, tail = obj_expled.decode(
3375 obj_expled_encoded + tail_junk,
3380 self.assertEqual(tail, tail_junk)
3381 self.assertEqual(obj_decoded, obj_expled)
3382 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3383 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3384 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3385 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3386 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3388 obj_decoded.expl_llen,
3389 len(len_encode(len(obj_encoded))),
3391 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3392 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3395 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3397 self.assertEqual(obj_decoded.expl_offset, offset)
3400 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3401 base_klass = GeneralizedTime
3403 min_datetime = datetime(1900, 1, 1)
3404 max_datetime = datetime(9999, 12, 31)
3406 def test_go_vectors_invalid(self):
3418 b"-20100102030410Z",
3419 b"2010-0102030410Z",
3420 b"2010-0002030410Z",
3421 b"201001-02030410Z",
3422 b"20100102-030410Z",
3423 b"2010010203-0410Z",
3424 b"201001020304-10Z",
3425 # These ones are INVALID in *DER*, but accepted
3426 # by Go's encoding/asn1
3427 b"20100102030405+0607",
3428 b"20100102030405-0607",
3430 with self.assertRaises(DecodeError) as err:
3431 GeneralizedTime(data)
3434 def test_go_vectors_valid(self):
3436 GeneralizedTime(b"20100102030405Z").todatetime(),
3437 datetime(2010, 1, 2, 3, 4, 5, 0),
3441 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3442 base_klass = UTCTime
3444 min_datetime = datetime(2000, 1, 1)
3445 max_datetime = datetime(2049, 12, 31)
3447 def test_go_vectors_invalid(self):
3473 # These ones are INVALID in *DER*, but accepted
3474 # by Go's encoding/asn1
3475 b"910506164540-0700",
3476 b"910506164540+0730",
3480 with self.assertRaises(DecodeError) as err:
3484 def test_go_vectors_valid(self):
3486 UTCTime(b"910506234540Z").todatetime(),
3487 datetime(1991, 5, 6, 23, 45, 40, 0),
3490 @given(integers(min_value=0, max_value=49))
3491 def test_pre50(self, year):
3493 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3497 @given(integers(min_value=50, max_value=99))
3498 def test_post50(self, year):
3500 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3506 def any_values_strategy(draw, do_expl=False):
3507 value = draw(one_of(none(), binary()))
3510 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3511 optional = draw(one_of(none(), booleans()))
3513 draw(integers(min_value=0)),
3514 draw(integers(min_value=0)),
3515 draw(integers(min_value=0)),
3517 return (value, expl, optional, _decoded)
3520 class AnyInherited(Any):
3524 class TestAny(CommonMixin, TestCase):
3527 def test_invalid_value_type(self):
3528 with self.assertRaises(InvalidValueType) as err:
3533 def test_optional(self, optional):
3534 obj = Any(optional=optional)
3535 self.assertEqual(obj.optional, optional)
3538 def test_ready(self, value):
3540 self.assertFalse(obj.ready)
3543 with self.assertRaises(ObjNotReady) as err:
3547 self.assertTrue(obj.ready)
3552 def test_basic(self, value):
3553 integer_encoded = Integer(value).encode()
3555 Any(integer_encoded),
3556 Any(Integer(value)),
3557 Any(Any(Integer(value))),
3559 self.assertSequenceEqual(bytes(obj), integer_encoded)
3561 obj.decode(obj.encode())[0].vlen,
3562 len(integer_encoded),
3566 self.assertSequenceEqual(obj.encode(), integer_encoded)
3568 @given(binary(), binary())
3569 def test_comparison(self, value1, value2):
3570 for klass in (Any, AnyInherited):
3571 obj1 = klass(value1)
3572 obj2 = klass(value2)
3573 self.assertEqual(obj1 == obj2, value1 == value2)
3574 self.assertEqual(obj1 != obj2, value1 != value2)
3575 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3577 @given(data_strategy())
3578 def test_call(self, d):
3579 for klass in (Any, AnyInherited):
3585 ) = d.draw(any_values_strategy())
3586 obj_initial = klass(
3589 optional_initial or False,
3597 ) = d.draw(any_values_strategy(do_expl=True))
3598 obj = obj_initial(value, expl, optional)
3600 value_expected = None if value is None else value
3601 self.assertEqual(obj, value_expected)
3602 self.assertEqual(obj.expl_tag, expl or expl_initial)
3603 if obj.default is None:
3604 optional = optional_initial if optional is None else optional
3605 optional = False if optional is None else optional
3606 self.assertEqual(obj.optional, optional)
3608 def test_simultaneous_impl_expl(self):
3609 # override it, as Any does not have implicit tag
3612 def test_decoded(self):
3613 # override it, as Any does not have implicit tag
3616 @given(any_values_strategy())
3617 def test_copy(self, values):
3618 for klass in (Any, AnyInherited):
3619 obj = klass(*values)
3620 obj_copied = obj.copy()
3621 self.assert_copied_basic_fields(obj, obj_copied)
3622 self.assertEqual(obj._value, obj_copied._value)
3624 @given(binary().map(OctetString))
3625 def test_stripped(self, value):
3627 with self.assertRaises(NotEnoughData):
3628 obj.decode(obj.encode()[:-1])
3632 integers(min_value=1).map(tag_ctxc),
3634 def test_stripped_expl(self, value, tag_expl):
3635 obj = Any(value, expl=tag_expl)
3636 with self.assertRaises(NotEnoughData):
3637 obj.decode(obj.encode()[:-1])
3640 integers(min_value=31),
3641 integers(min_value=0),
3644 def test_bad_tag(self, tag, offset, decode_path):
3645 decode_path = tuple(str(i) for i in decode_path)
3646 with self.assertRaises(DecodeError) as err:
3648 tag_encode(tag)[:-1],
3650 decode_path=decode_path,
3653 self.assertEqual(err.exception.offset, offset)
3654 self.assertEqual(err.exception.decode_path, decode_path)
3657 integers(min_value=128),
3658 integers(min_value=0),
3661 def test_bad_len(self, l, offset, decode_path):
3662 decode_path = tuple(str(i) for i in decode_path)
3663 with self.assertRaises(DecodeError) as err:
3665 Any.tag_default + len_encode(l)[:-1],
3667 decode_path=decode_path,
3670 self.assertEqual(err.exception.offset, offset)
3671 self.assertEqual(err.exception.decode_path, decode_path)
3673 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3675 any_values_strategy(),
3676 integers().map(lambda x: Integer(x).encode()),
3677 integers(min_value=1).map(tag_ctxc),
3678 integers(min_value=0),
3681 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3682 for klass in (Any, AnyInherited):
3683 _, _, optional, _decoded = values
3684 obj = klass(value=value, optional=optional, _decoded=_decoded)
3687 self.assertFalse(obj.expled)
3688 obj_encoded = obj.encode()
3689 obj_expled = obj(value, expl=tag_expl)
3690 self.assertTrue(obj_expled.expled)
3693 obj_expled_encoded = obj_expled.encode()
3694 obj_decoded, tail = obj_expled.decode(
3695 obj_expled_encoded + tail_junk,
3700 self.assertEqual(tail, tail_junk)
3701 self.assertEqual(obj_decoded, obj_expled)
3702 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3703 self.assertEqual(bytes(obj_decoded), bytes(obj))
3704 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3705 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3706 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3708 obj_decoded.expl_llen,
3709 len(len_encode(len(obj_encoded))),
3711 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3712 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3715 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3717 self.assertEqual(obj_decoded.expl_offset, offset)
3718 self.assertEqual(obj_decoded.tlen, 0)
3719 self.assertEqual(obj_decoded.llen, 0)
3720 self.assertEqual(obj_decoded.vlen, len(value))
3724 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3726 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3727 tags = [tag_encode(tag) for tag in draw(sets(
3728 integers(min_value=0),
3729 min_size=len(names),
3730 max_size=len(names),
3732 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3734 if value_required or draw(booleans()):
3735 value = draw(tuples(
3736 sampled_from([name for name, _ in schema]),
3737 integers().map(Integer),
3741 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3742 default = draw(one_of(
3744 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3746 optional = draw(one_of(none(), booleans()))
3748 draw(integers(min_value=0)),
3749 draw(integers(min_value=0)),
3750 draw(integers(min_value=0)),
3752 return (schema, value, expl, default, optional, _decoded)
3755 class ChoiceInherited(Choice):
3759 class TestChoice(CommonMixin, TestCase):
3761 schema = (("whatever", Boolean()),)
3764 def test_schema_required(self):
3765 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3768 def test_impl_forbidden(self):
3769 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3770 Choice(impl=b"whatever")
3772 def test_invalid_value_type(self):
3773 with self.assertRaises(InvalidValueType) as err:
3774 self.base_klass(123)
3776 with self.assertRaises(ObjUnknown) as err:
3777 self.base_klass(("whenever", Boolean(False)))
3779 with self.assertRaises(InvalidValueType) as err:
3780 self.base_klass(("whatever", Integer(123)))
3784 def test_optional(self, optional):
3785 obj = self.base_klass(
3786 default=self.base_klass(("whatever", Boolean(False))),
3789 self.assertTrue(obj.optional)
3792 def test_ready(self, value):
3793 obj = self.base_klass()
3794 self.assertFalse(obj.ready)
3797 self.assertIsNone(obj["whatever"])
3798 with self.assertRaises(ObjNotReady) as err:
3801 obj["whatever"] = Boolean()
3802 self.assertFalse(obj.ready)
3805 obj["whatever"] = Boolean(value)
3806 self.assertTrue(obj.ready)
3810 @given(booleans(), booleans())
3811 def test_comparison(self, value1, value2):
3812 class WahlInherited(self.base_klass):
3814 for klass in (self.base_klass, WahlInherited):
3815 obj1 = klass(("whatever", Boolean(value1)))
3816 obj2 = klass(("whatever", Boolean(value2)))
3817 self.assertEqual(obj1 == obj2, value1 == value2)
3818 self.assertEqual(obj1 != obj2, value1 != value2)
3819 self.assertEqual(obj1 == obj2._value, value1 == value2)
3820 self.assertFalse(obj1 == obj2._value[1])
3822 @given(data_strategy())
3823 def test_call(self, d):
3824 for klass in (Choice, ChoiceInherited):
3832 ) = d.draw(choice_values_strategy())
3835 schema = schema_initial
3837 value=value_initial,
3839 default=default_initial,
3840 optional=optional_initial or False,
3841 _decoded=_decoded_initial,
3850 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
3851 obj = obj_initial(value, expl, default, optional)
3853 value_expected = default if value is None else value
3855 default_initial if value_expected is None
3858 self.assertEqual(obj.choice, value_expected[0])
3859 self.assertEqual(obj.value, int(value_expected[1]))
3860 self.assertEqual(obj.expl_tag, expl or expl_initial)
3861 default_expect = default_initial if default is None else default
3862 if default_expect is not None:
3863 self.assertEqual(obj.default.choice, default_expect[0])
3864 self.assertEqual(obj.default.value, int(default_expect[1]))
3865 if obj.default is None:
3866 optional = optional_initial if optional is None else optional
3867 optional = False if optional is None else optional
3870 self.assertEqual(obj.optional, optional)
3871 self.assertEqual(obj.specs, obj_initial.specs)
3873 def test_simultaneous_impl_expl(self):
3874 # override it, as Any does not have implicit tag
3877 def test_decoded(self):
3878 # override it, as Any does not have implicit tag
3881 @given(choice_values_strategy())
3882 def test_copy(self, values):
3883 _schema, value, expl, default, optional, _decoded = values
3885 class Wahl(self.base_klass):
3891 optional=optional or False,
3894 obj_copied = obj.copy()
3895 self.assertIsNone(obj.tag)
3896 self.assertIsNone(obj_copied.tag)
3897 # hack for assert_copied_basic_fields
3898 obj.tag = "whatever"
3899 obj_copied.tag = "whatever"
3900 self.assert_copied_basic_fields(obj, obj_copied)
3901 self.assertEqual(obj._value, obj_copied._value)
3902 self.assertEqual(obj.specs, obj_copied.specs)
3905 def test_stripped(self, value):
3906 obj = self.base_klass(("whatever", Boolean(value)))
3907 with self.assertRaises(NotEnoughData):
3908 obj.decode(obj.encode()[:-1])
3912 integers(min_value=1).map(tag_ctxc),
3914 def test_stripped_expl(self, value, tag_expl):
3915 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3916 with self.assertRaises(NotEnoughData):
3917 obj.decode(obj.encode()[:-1])
3919 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3920 @given(data_strategy())
3921 def test_symmetric(self, d):
3922 _schema, value, _, default, optional, _decoded = d.draw(
3923 choice_values_strategy(value_required=True)
3925 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3926 offset = d.draw(integers(min_value=0))
3927 tail_junk = d.draw(binary(max_size=5))
3929 class Wahl(self.base_klass):
3939 self.assertFalse(obj.expled)
3940 obj_encoded = obj.encode()
3941 obj_expled = obj(value, expl=tag_expl)
3942 self.assertTrue(obj_expled.expled)
3945 obj_expled_encoded = obj_expled.encode()
3946 obj_decoded, tail = obj_expled.decode(
3947 obj_expled_encoded + tail_junk,
3952 self.assertEqual(tail, tail_junk)
3953 self.assertEqual(obj_decoded, obj_expled)
3954 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3955 self.assertEqual(obj_decoded.value, obj_expled.value)
3956 self.assertEqual(obj_decoded.choice, obj.choice)
3957 self.assertEqual(obj_decoded.value, obj.value)
3958 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3959 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3960 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3962 obj_decoded.expl_llen,
3963 len(len_encode(len(obj_encoded))),
3965 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3966 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3969 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3971 self.assertEqual(obj_decoded.expl_offset, offset)
3972 self.assertSequenceEqual(
3974 obj_decoded.value.offset - offset:
3975 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3981 def test_set_get(self, value):
3984 ("erste", Boolean()),
3985 ("zweite", Integer()),
3988 with self.assertRaises(ObjUnknown) as err:
3989 obj["whatever"] = "whenever"
3990 with self.assertRaises(InvalidValueType) as err:
3991 obj["zweite"] = Boolean(False)
3992 obj["zweite"] = Integer(value)
3994 with self.assertRaises(ObjUnknown) as err:
3997 self.assertIsNone(obj["erste"])
3998 self.assertEqual(obj["zweite"], Integer(value))
4000 def test_tag_mismatch(self):
4003 ("erste", Boolean()),
4005 int_encoded = Integer(123).encode()
4006 bool_encoded = Boolean(False).encode()
4008 obj.decode(bool_encoded)
4009 with self.assertRaises(TagMismatch):
4010 obj.decode(int_encoded)
4012 def test_tag_mismatch_underlying(self):
4013 class SeqOfBoolean(SequenceOf):
4016 class SeqOfInteger(SequenceOf):
4021 ("erste", SeqOfBoolean()),
4024 int_encoded = SeqOfInteger((Integer(123),)).encode()
4025 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4027 obj.decode(bool_encoded)
4028 with self.assertRaises(TagMismatch) as err:
4029 obj.decode(int_encoded)
4030 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4034 def seq_values_strategy(draw, seq_klass, do_expl=False):
4036 if draw(booleans()):
4039 k: v for k, v in draw(dictionaries(
4042 booleans().map(Boolean),
4043 integers().map(Integer),
4048 if draw(booleans()):
4049 schema = list(draw(dictionaries(
4052 booleans().map(Boolean),
4053 integers().map(Integer),
4059 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4061 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4063 if draw(booleans()):
4064 default = seq_klass()
4066 k: v for k, v in draw(dictionaries(
4069 booleans().map(Boolean),
4070 integers().map(Integer),
4074 optional = draw(one_of(none(), booleans()))
4076 draw(integers(min_value=0)),
4077 draw(integers(min_value=0)),
4078 draw(integers(min_value=0)),
4080 return (value, schema, impl, expl, default, optional, _decoded)
4084 def sequence_strategy(draw, seq_klass):
4085 inputs = draw(lists(
4087 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4088 tuples(just(Integer), integers(), one_of(none(), integers())),
4093 integers(min_value=1),
4094 min_size=len(inputs),
4095 max_size=len(inputs),
4098 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4099 for tag, expled in zip(tags, draw(lists(
4101 min_size=len(inputs),
4102 max_size=len(inputs),
4106 for i, optional in enumerate(draw(lists(
4107 sampled_from(("required", "optional", "empty")),
4108 min_size=len(inputs),
4109 max_size=len(inputs),
4111 if optional in ("optional", "empty"):
4112 inits[i]["optional"] = True
4113 if optional == "empty":
4115 empties = set(empties)
4116 names = list(draw(sets(
4118 min_size=len(inputs),
4119 max_size=len(inputs),
4122 for i, (klass, value, default) in enumerate(inputs):
4123 schema.append((names[i], klass(default=default, **inits[i])))
4124 seq_name = draw(text_letters())
4125 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4128 for i, (klass, value, default) in enumerate(inputs):
4135 "default_value": None if spec.default is None else default,
4139 expect["optional"] = True
4141 expect["presented"] = True
4142 expect["value"] = value
4144 expect["optional"] = True
4145 if default is not None and default == value:
4146 expect["presented"] = False
4147 seq[name] = klass(value)
4148 expects.append(expect)
4153 def sequences_strategy(draw, seq_klass):
4154 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4156 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4157 for tag, expled in zip(tags, draw(lists(
4164 i for i, is_default in enumerate(draw(lists(
4170 names = list(draw(sets(
4175 seq_expectses = draw(lists(
4176 sequence_strategy(seq_klass=seq_klass),
4180 seqs = [seq for seq, _ in seq_expectses]
4182 for i, (name, seq) in enumerate(zip(names, seqs)):
4185 seq(default=(seq if i in defaulted else None), **inits[i]),
4187 seq_name = draw(text_letters())
4188 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4191 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4194 "expects": expects_inner,
4197 seq_outer[name] = seq_inner
4198 if seq_outer.specs[name].default is None:
4199 expect["presented"] = True
4200 expect_outers.append(expect)
4201 return seq_outer, expect_outers
4204 class SeqMixing(object):
4205 def test_invalid_value_type(self):
4206 with self.assertRaises(InvalidValueType) as err:
4207 self.base_klass(123)
4210 def test_invalid_value_type_set(self):
4211 class Seq(self.base_klass):
4212 schema = (("whatever", Boolean()),)
4214 with self.assertRaises(InvalidValueType) as err:
4215 seq["whatever"] = Integer(123)
4219 def test_optional(self, optional):
4220 obj = self.base_klass(default=self.base_klass(), optional=optional)
4221 self.assertTrue(obj.optional)
4223 @given(data_strategy())
4224 def test_ready(self, d):
4226 str(i): v for i, v in enumerate(d.draw(lists(
4233 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4240 for name in d.draw(permutations(
4241 list(ready.keys()) + list(non_ready.keys()),
4243 schema_input.append((name, Boolean()))
4245 class Seq(self.base_klass):
4246 schema = tuple(schema_input)
4248 for name in ready.keys():
4250 seq[name] = Boolean()
4251 self.assertFalse(seq.ready)
4254 for name, value in ready.items():
4255 seq[name] = Boolean(value)
4256 self.assertFalse(seq.ready)
4259 with self.assertRaises(ObjNotReady) as err:
4262 for name, value in non_ready.items():
4263 seq[name] = Boolean(value)
4264 self.assertTrue(seq.ready)
4268 @given(data_strategy())
4269 def test_call(self, d):
4270 class SeqInherited(self.base_klass):
4272 for klass in (self.base_klass, SeqInherited):
4281 ) = d.draw(seq_values_strategy(seq_klass=klass))
4282 obj_initial = klass(
4288 optional_initial or False,
4299 ) = d.draw(seq_values_strategy(
4301 do_expl=impl_initial is None,
4303 obj = obj_initial(value, impl, expl, default, optional)
4304 value_expected = default if value is None else value
4306 default_initial if value_expected is None
4309 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4310 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4311 self.assertEqual(obj.expl_tag, expl or expl_initial)
4313 {} if obj.default is None else obj.default._value,
4314 getattr(default_initial if default is None else default, "_value", {}),
4316 if obj.default is None:
4317 optional = optional_initial if optional is None else optional
4318 optional = False if optional is None else optional
4321 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4322 self.assertEqual(obj.optional, optional)
4324 @given(data_strategy())
4325 def test_copy(self, d):
4326 class SeqInherited(self.base_klass):
4328 for klass in (self.base_klass, SeqInherited):
4329 values = d.draw(seq_values_strategy(seq_klass=klass))
4330 obj = klass(*values)
4331 obj_copied = obj.copy()
4332 self.assert_copied_basic_fields(obj, obj_copied)
4333 self.assertEqual(obj.specs, obj_copied.specs)
4334 self.assertEqual(obj._value, obj_copied._value)
4336 @given(data_strategy())
4337 def test_stripped(self, d):
4338 value = d.draw(integers())
4339 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4341 class Seq(self.base_klass):
4343 schema = (("whatever", Integer()),)
4345 seq["whatever"] = Integer(value)
4346 with self.assertRaises(NotEnoughData):
4347 seq.decode(seq.encode()[:-1])
4349 @given(data_strategy())
4350 def test_stripped_expl(self, d):
4351 value = d.draw(integers())
4352 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4354 class Seq(self.base_klass):
4356 schema = (("whatever", Integer()),)
4358 seq["whatever"] = Integer(value)
4359 with self.assertRaises(NotEnoughData):
4360 seq.decode(seq.encode()[:-1])
4362 @given(binary(min_size=2))
4363 def test_non_tag_mismatch_raised(self, junk):
4365 _, _, len_encoded = tag_strip(memoryview(junk))
4366 len_decode(len_encoded)
4372 class Seq(self.base_klass):
4374 ("whatever", Integer()),
4376 ("whenever", Integer()),
4379 seq["whatever"] = Integer(123)
4380 seq["junk"] = Any(junk)
4381 seq["whenever"] = Integer(123)
4382 with self.assertRaises(DecodeError):
4383 seq.decode(seq.encode())
4386 integers(min_value=31),
4387 integers(min_value=0),
4390 def test_bad_tag(self, tag, offset, decode_path):
4391 decode_path = tuple(str(i) for i in decode_path)
4392 with self.assertRaises(DecodeError) as err:
4393 self.base_klass().decode(
4394 tag_encode(tag)[:-1],
4396 decode_path=decode_path,
4399 self.assertEqual(err.exception.offset, offset)
4400 self.assertEqual(err.exception.decode_path, decode_path)
4403 integers(min_value=128),
4404 integers(min_value=0),
4407 def test_bad_len(self, l, offset, decode_path):
4408 decode_path = tuple(str(i) for i in decode_path)
4409 with self.assertRaises(DecodeError) as err:
4410 self.base_klass().decode(
4411 self.base_klass.tag_default + len_encode(l)[:-1],
4413 decode_path=decode_path,
4416 self.assertEqual(err.exception.offset, offset)
4417 self.assertEqual(err.exception.decode_path, decode_path)
4419 def _assert_expects(self, seq, expects):
4420 for expect in expects:
4422 seq.specs[expect["name"]].optional,
4425 if expect["default_value"] is not None:
4427 seq.specs[expect["name"]].default,
4428 expect["default_value"],
4430 if expect["presented"]:
4431 self.assertIn(expect["name"], seq)
4432 self.assertEqual(seq[expect["name"]], expect["value"])
4434 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4435 @given(data_strategy())
4436 def test_symmetric(self, d):
4437 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4438 tail_junk = d.draw(binary(max_size=5))
4439 self.assertTrue(seq.ready)
4440 self.assertFalse(seq.decoded)
4441 self._assert_expects(seq, expects)
4444 seq_encoded = seq.encode()
4445 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4446 self.assertEqual(tail, tail_junk)
4447 self.assertTrue(seq.ready)
4448 self._assert_expects(seq_decoded, expects)
4449 self.assertEqual(seq, seq_decoded)
4450 self.assertEqual(seq_decoded.encode(), seq_encoded)
4451 for expect in expects:
4452 if not expect["presented"]:
4453 self.assertNotIn(expect["name"], seq_decoded)
4455 self.assertIn(expect["name"], seq_decoded)
4456 obj = seq_decoded[expect["name"]]
4457 self.assertTrue(obj.decoded)
4458 offset = obj.expl_offset if obj.expled else obj.offset
4459 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4460 self.assertSequenceEqual(
4461 seq_encoded[offset:offset + tlvlen],
4465 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4466 @given(data_strategy())
4467 def test_symmetric_with_seq(self, d):
4468 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4469 self.assertTrue(seq.ready)
4470 seq_encoded = seq.encode()
4471 seq_decoded, tail = seq.decode(seq_encoded)
4472 self.assertEqual(tail, b"")
4473 self.assertTrue(seq.ready)
4474 self.assertEqual(seq, seq_decoded)
4475 self.assertEqual(seq_decoded.encode(), seq_encoded)
4476 for expect_outer in expect_outers:
4477 if not expect_outer["presented"]:
4478 self.assertNotIn(expect_outer["name"], seq_decoded)
4480 self.assertIn(expect_outer["name"], seq_decoded)
4481 obj = seq_decoded[expect_outer["name"]]
4482 self.assertTrue(obj.decoded)
4483 offset = obj.expl_offset if obj.expled else obj.offset
4484 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4485 self.assertSequenceEqual(
4486 seq_encoded[offset:offset + tlvlen],
4489 self._assert_expects(obj, expect_outer["expects"])
4491 @given(data_strategy())
4492 def test_default_disappears(self, d):
4493 _schema = list(d.draw(dictionaries(
4495 sets(integers(), min_size=2, max_size=2),
4499 class Seq(self.base_klass):
4501 (n, Integer(default=d))
4502 for n, (_, d) in _schema
4505 for name, (value, _) in _schema:
4506 seq[name] = Integer(value)
4507 self.assertEqual(len(seq._value), len(_schema))
4508 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4509 self.assertGreater(len(seq.encode()), len(empty_seq))
4510 for name, (_, default) in _schema:
4511 seq[name] = Integer(default)
4512 self.assertEqual(len(seq._value), 0)
4513 self.assertSequenceEqual(seq.encode(), empty_seq)
4515 @given(data_strategy())
4516 def test_encoded_default_accepted(self, d):
4517 _schema = list(d.draw(dictionaries(
4522 tags = [tag_encode(tag) for tag in d.draw(sets(
4523 integers(min_value=0),
4524 min_size=len(_schema),
4525 max_size=len(_schema),
4528 class SeqWithoutDefault(self.base_klass):
4530 (n, Integer(impl=t))
4531 for (n, _), t in zip(_schema, tags)
4533 seq_without_default = SeqWithoutDefault()
4534 for name, value in _schema:
4535 seq_without_default[name] = Integer(value)
4536 seq_encoded = seq_without_default.encode()
4538 class SeqWithDefault(self.base_klass):
4540 (n, Integer(default=v, impl=t))
4541 for (n, v), t in zip(_schema, tags)
4543 seq_with_default = SeqWithDefault()
4544 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4545 for name, value in _schema:
4546 self.assertEqual(seq_decoded[name], seq_with_default[name])
4547 self.assertEqual(seq_decoded[name], value)
4549 @given(data_strategy())
4550 def test_missing_from_spec(self, d):
4551 names = list(d.draw(sets(text_letters(), min_size=2)))
4552 tags = [tag_encode(tag) for tag in d.draw(sets(
4553 integers(min_value=0),
4554 min_size=len(names),
4555 max_size=len(names),
4557 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4559 class SeqFull(self.base_klass):
4560 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4561 seq_full = SeqFull()
4562 for i, name in enumerate(names):
4563 seq_full[name] = Integer(i)
4564 seq_encoded = seq_full.encode()
4565 altered = names_tags[:-2] + names_tags[-1:]
4567 class SeqMissing(self.base_klass):
4568 schema = [(n, Integer(impl=t)) for n, t in altered]
4569 seq_missing = SeqMissing()
4570 with self.assertRaises(TagMismatch):
4571 seq_missing.decode(seq_encoded)
4574 class TestSequence(SeqMixing, CommonMixin, TestCase):
4575 base_klass = Sequence
4581 def test_remaining(self, value, junk):
4582 class Seq(Sequence):
4584 ("whatever", Integer()),
4586 int_encoded = Integer(value).encode()
4588 Sequence.tag_default,
4589 len_encode(len(int_encoded + junk)),
4592 with assertRaisesRegex(self, DecodeError, "remaining"):
4593 Seq().decode(junked)
4595 @given(sets(text_letters(), min_size=2))
4596 def test_obj_unknown(self, names):
4597 missing = names.pop()
4599 class Seq(Sequence):
4600 schema = [(n, Boolean()) for n in names]
4602 with self.assertRaises(ObjUnknown) as err:
4605 with self.assertRaises(ObjUnknown) as err:
4606 seq[missing] = Boolean()
4609 def test_x690_vector(self):
4610 class Seq(Sequence):
4612 ("name", IA5String()),
4615 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4616 self.assertEqual(seq["name"], "Smith")
4617 self.assertEqual(seq["ok"], True)
4620 class TestSet(SeqMixing, CommonMixin, TestCase):
4623 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4624 @given(data_strategy())
4625 def test_sorted(self, d):
4627 tag_encode(tag) for tag in
4628 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4632 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4634 for name, _ in Seq.schema:
4635 seq[name] = OctetString(b"")
4636 seq_encoded = seq.encode()
4637 seq_decoded, _ = seq.decode(seq_encoded)
4638 self.assertSequenceEqual(
4639 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4640 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4645 def seqof_values_strategy(draw, schema=None, do_expl=False):
4647 schema = draw(sampled_from((Boolean(), Integer())))
4648 bound_min, bound_max = sorted(draw(sets(
4649 integers(min_value=0, max_value=10),
4653 if isinstance(schema, Boolean):
4654 values_generator = booleans().map(Boolean)
4655 elif isinstance(schema, Integer):
4656 values_generator = integers().map(Integer)
4657 values_generator = lists(
4662 values = draw(one_of(none(), values_generator))
4666 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4668 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4669 default = draw(one_of(none(), values_generator))
4670 optional = draw(one_of(none(), booleans()))
4672 draw(integers(min_value=0)),
4673 draw(integers(min_value=0)),
4674 draw(integers(min_value=0)),
4679 (bound_min, bound_max),
4688 class SeqOfMixing(object):
4689 def test_invalid_value_type(self):
4690 with self.assertRaises(InvalidValueType) as err:
4691 self.base_klass(123)
4694 def test_invalid_values_type(self):
4695 class SeqOf(self.base_klass):
4697 with self.assertRaises(InvalidValueType) as err:
4698 SeqOf([Integer(123), Boolean(False), Integer(234)])
4701 def test_schema_required(self):
4702 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4703 self.base_klass.__mro__[1]()
4705 @given(booleans(), booleans(), binary(), binary())
4706 def test_comparison(self, value1, value2, tag1, tag2):
4707 class SeqOf(self.base_klass):
4709 obj1 = SeqOf([Boolean(value1)])
4710 obj2 = SeqOf([Boolean(value2)])
4711 self.assertEqual(obj1 == obj2, value1 == value2)
4712 self.assertEqual(obj1 != obj2, value1 != value2)
4713 self.assertEqual(obj1 == list(obj2), value1 == value2)
4714 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4715 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4716 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4717 self.assertEqual(obj1 == obj2, tag1 == tag2)
4718 self.assertEqual(obj1 != obj2, tag1 != tag2)
4720 @given(lists(booleans()))
4721 def test_iter(self, values):
4722 class SeqOf(self.base_klass):
4724 obj = SeqOf([Boolean(value) for value in values])
4725 self.assertEqual(len(obj), len(values))
4726 for i, value in enumerate(obj):
4727 self.assertEqual(value, values[i])
4729 @given(data_strategy())
4730 def test_ready(self, d):
4731 ready = [Integer(v) for v in d.draw(lists(
4738 range(d.draw(integers(min_value=1, max_value=5)))
4741 class SeqOf(self.base_klass):
4743 values = d.draw(permutations(ready + non_ready))
4745 for value in values:
4747 self.assertFalse(seqof.ready)
4750 with self.assertRaises(ObjNotReady) as err:
4753 for i, value in enumerate(values):
4754 self.assertEqual(seqof[i], value)
4755 if not seqof[i].ready:
4756 seqof[i] = Integer(i)
4757 self.assertTrue(seqof.ready)
4761 def test_spec_mismatch(self):
4762 class SeqOf(self.base_klass):
4765 seqof.append(Integer(123))
4766 with self.assertRaises(ValueError):
4767 seqof.append(Boolean(False))
4768 with self.assertRaises(ValueError):
4769 seqof[0] = Boolean(False)
4771 @given(data_strategy())
4772 def test_bounds_satisfied(self, d):
4773 class SeqOf(self.base_klass):
4775 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4776 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4777 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4778 SeqOf(value=value, bounds=(bound_min, bound_max))
4780 @given(data_strategy())
4781 def test_bounds_unsatisfied(self, d):
4782 class SeqOf(self.base_klass):
4784 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4785 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4786 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4787 with self.assertRaises(BoundsError) as err:
4788 SeqOf(value=value, bounds=(bound_min, bound_max))
4790 value = [Boolean()] * d.draw(integers(
4791 min_value=bound_max + 1,
4792 max_value=bound_max + 10,
4794 with self.assertRaises(BoundsError) as err:
4795 SeqOf(value=value, bounds=(bound_min, bound_max))
4798 @given(integers(min_value=1, max_value=10))
4799 def test_out_of_bounds(self, bound_max):
4800 class SeqOf(self.base_klass):
4802 bounds = (0, bound_max)
4804 for _ in range(bound_max):
4805 seqof.append(Integer(123))
4806 with self.assertRaises(BoundsError):
4807 seqof.append(Integer(123))
4809 @given(data_strategy())
4810 def test_call(self, d):
4820 ) = d.draw(seqof_values_strategy())
4822 class SeqOf(self.base_klass):
4823 schema = schema_initial
4824 obj_initial = SeqOf(
4825 value=value_initial,
4826 bounds=bounds_initial,
4829 default=default_initial,
4830 optional=optional_initial or False,
4831 _decoded=_decoded_initial,
4842 ) = d.draw(seqof_values_strategy(
4843 schema=schema_initial,
4844 do_expl=impl_initial is None,
4846 if (default is None) and (obj_initial.default is not None):
4849 (bounds is None) and
4850 (value is not None) and
4851 (bounds_initial is not None) and
4852 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4856 (bounds is None) and
4857 (default is not None) and
4858 (bounds_initial is not None) and
4859 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4871 value_expected = default if value is None else value
4873 default_initial if value_expected is None
4876 value_expected = () if value_expected is None else value_expected
4877 self.assertEqual(obj, value_expected)
4878 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4879 self.assertEqual(obj.expl_tag, expl or expl_initial)
4882 default_initial if default is None else default,
4884 if obj.default is None:
4885 optional = optional_initial if optional is None else optional
4886 optional = False if optional is None else optional
4889 self.assertEqual(obj.optional, optional)
4891 (obj._bound_min, obj._bound_max),
4892 bounds or bounds_initial or (0, float("+inf")),
4895 @given(seqof_values_strategy())
4896 def test_copy(self, values):
4897 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4899 class SeqOf(self.base_klass):
4907 optional=optional or False,
4910 obj_copied = obj.copy()
4911 self.assert_copied_basic_fields(obj, obj_copied)
4912 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4913 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4914 self.assertEqual(obj._value, obj_copied._value)
4918 integers(min_value=1).map(tag_encode),
4920 def test_stripped(self, values, tag_impl):
4921 class SeqOf(self.base_klass):
4922 schema = OctetString()
4923 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4924 with self.assertRaises(NotEnoughData):
4925 obj.decode(obj.encode()[:-1])
4929 integers(min_value=1).map(tag_ctxc),
4931 def test_stripped_expl(self, values, tag_expl):
4932 class SeqOf(self.base_klass):
4933 schema = OctetString()
4934 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4935 with self.assertRaises(NotEnoughData):
4936 obj.decode(obj.encode()[:-1])
4939 integers(min_value=31),
4940 integers(min_value=0),
4943 def test_bad_tag(self, tag, offset, decode_path):
4944 decode_path = tuple(str(i) for i in decode_path)
4945 with self.assertRaises(DecodeError) as err:
4946 self.base_klass().decode(
4947 tag_encode(tag)[:-1],
4949 decode_path=decode_path,
4952 self.assertEqual(err.exception.offset, offset)
4953 self.assertEqual(err.exception.decode_path, decode_path)
4956 integers(min_value=128),
4957 integers(min_value=0),
4960 def test_bad_len(self, l, offset, decode_path):
4961 decode_path = tuple(str(i) for i in decode_path)
4962 with self.assertRaises(DecodeError) as err:
4963 self.base_klass().decode(
4964 self.base_klass.tag_default + len_encode(l)[:-1],
4966 decode_path=decode_path,
4969 self.assertEqual(err.exception.offset, offset)
4970 self.assertEqual(err.exception.decode_path, decode_path)
4972 @given(binary(min_size=1))
4973 def test_tag_mismatch(self, impl):
4974 assume(impl != self.base_klass.tag_default)
4975 with self.assertRaises(TagMismatch):
4976 self.base_klass(impl=impl).decode(self.base_klass().encode())
4978 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4980 seqof_values_strategy(schema=Integer()),
4981 lists(integers().map(Integer)),
4982 integers(min_value=1).map(tag_ctxc),
4983 integers(min_value=0),
4986 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4987 _, _, _, _, _, default, optional, _decoded = values
4989 class SeqOf(self.base_klass):
4999 self.assertFalse(obj.expled)
5000 obj_encoded = obj.encode()
5001 obj_expled = obj(value, expl=tag_expl)
5002 self.assertTrue(obj_expled.expled)
5005 obj_expled_encoded = obj_expled.encode()
5006 obj_decoded, tail = obj_expled.decode(
5007 obj_expled_encoded + tail_junk,
5012 self.assertEqual(tail, tail_junk)
5013 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5014 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5015 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5016 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5018 obj_decoded.expl_llen,
5019 len(len_encode(len(obj_encoded))),
5021 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5022 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5025 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5027 self.assertEqual(obj_decoded.expl_offset, offset)
5028 for obj_inner in obj_decoded:
5029 self.assertIn(obj_inner, obj_decoded)
5030 self.assertSequenceEqual(
5033 obj_inner.offset - offset:
5034 obj_inner.offset + obj_inner.tlvlen - offset
5039 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5040 class SeqOf(SequenceOf):
5044 def _test_symmetric_compare_objs(self, obj1, obj2):
5045 self.assertEqual(obj1, obj2)
5046 self.assertSequenceEqual(list(obj1), list(obj2))
5049 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5054 def _test_symmetric_compare_objs(self, obj1, obj2):
5055 self.assertSetEqual(
5056 set(int(v) for v in obj1),
5057 set(int(v) for v in obj2),
5060 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5061 @given(data_strategy())
5062 def test_sorted(self, d):
5063 values = [OctetString(v) for v in d.draw(lists(binary()))]
5066 schema = OctetString()
5068 seq_encoded = seq.encode()
5069 seq_decoded, _ = seq.decode(seq_encoded)
5070 self.assertSequenceEqual(
5071 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5072 b"".join(sorted([v.encode() for v in values])),
5076 class TestGoMarshalVectors(TestCase):
5078 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5079 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5080 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5081 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5082 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5084 class Seq(Sequence):
5086 ("erste", Integer()),
5087 ("zweite", Integer(optional=True))
5090 seq["erste"] = Integer(64)
5091 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5092 seq["erste"] = Integer(0x123456)
5093 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5094 seq["erste"] = Integer(64)
5095 seq["zweite"] = Integer(65)
5096 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5098 class NestedSeq(Sequence):
5102 seq["erste"] = Integer(127)
5103 seq["zweite"] = None
5104 nested = NestedSeq()
5105 nested["nest"] = seq
5106 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5108 self.assertSequenceEqual(
5109 OctetString(b"\x01\x02\x03").encode(),
5110 hexdec("0403010203"),
5113 class Seq(Sequence):
5115 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5118 seq["erste"] = Integer(64)
5119 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5121 class Seq(Sequence):
5123 ("erste", Integer(expl=tag_ctxc(5))),
5126 seq["erste"] = Integer(64)
5127 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5129 class Seq(Sequence):
5132 impl=tag_encode(0, klass=TagClassContext),
5137 seq["erste"] = Null()
5138 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5140 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5142 self.assertSequenceEqual(
5143 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5144 hexdec("170d3730303130313030303030305a"),
5146 self.assertSequenceEqual(
5147 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5148 hexdec("170d3039313131353232353631365a"),
5150 self.assertSequenceEqual(
5151 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5152 hexdec("180f32313030303430353132303130315a"),
5155 class Seq(Sequence):
5157 ("erste", GeneralizedTime()),
5160 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5161 self.assertSequenceEqual(
5163 hexdec("3011180f32303039313131353232353631365a"),
5166 self.assertSequenceEqual(
5167 BitString((1, b"\x80")).encode(),
5170 self.assertSequenceEqual(
5171 BitString((12, b"\x81\xF0")).encode(),
5172 hexdec("03030481f0"),
5175 self.assertSequenceEqual(
5176 ObjectIdentifier("1.2.3.4").encode(),
5177 hexdec("06032a0304"),
5179 self.assertSequenceEqual(
5180 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5181 hexdec("06092a864888932d010105"),
5183 self.assertSequenceEqual(
5184 ObjectIdentifier("2.100.3").encode(),
5185 hexdec("0603813403"),
5188 self.assertSequenceEqual(
5189 PrintableString("test").encode(),
5190 hexdec("130474657374"),
5192 self.assertSequenceEqual(
5193 PrintableString("x" * 127).encode(),
5194 hexdec("137F" + "78" * 127),
5196 self.assertSequenceEqual(
5197 PrintableString("x" * 128).encode(),
5198 hexdec("138180" + "78" * 128),
5200 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5202 class Seq(Sequence):
5204 ("erste", IA5String()),
5207 seq["erste"] = IA5String("test")
5208 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5210 class Seq(Sequence):
5212 ("erste", PrintableString()),
5215 seq["erste"] = PrintableString("test")
5216 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5217 seq["erste"] = PrintableString("test*")
5218 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5220 class Seq(Sequence):
5222 ("erste", Any(optional=True)),
5223 ("zweite", Integer()),
5226 seq["zweite"] = Integer(64)
5227 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5232 seq.append(Integer(10))
5233 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5235 class _SeqOf(SequenceOf):
5236 schema = PrintableString()
5238 class SeqOf(SequenceOf):
5241 _seqof.append(PrintableString("1"))
5243 seqof.append(_seqof)
5244 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5246 class Seq(Sequence):
5248 ("erste", Integer(default=1)),
5251 seq["erste"] = Integer(0)
5252 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5253 seq["erste"] = Integer(1)
5254 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5255 seq["erste"] = Integer(2)
5256 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5259 class TestPP(TestCase):
5260 @given(data_strategy())
5261 def test_oid_printing(self, d):
5263 str(ObjectIdentifier(k)): v * 2
5264 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5266 chosen = d.draw(sampled_from(sorted(oids)))
5267 chosen_id = oids[chosen]
5268 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5269 self.assertNotIn(chosen_id, pp_console_row(pp))
5270 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5273 class TestAutoAddSlots(TestCase):
5275 class Inher(Integer):
5278 with self.assertRaises(AttributeError):
5280 inher.unexistent = "whatever"
5283 class TestOIDDefines(TestCase):
5284 @given(data_strategy())
5285 def runTest(self, d):
5286 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5287 value_name_chosen = d.draw(sampled_from(value_names))
5289 ObjectIdentifier(oid)
5290 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5292 oid_chosen = d.draw(sampled_from(oids))
5293 values = d.draw(lists(
5295 min_size=len(value_names),
5296 max_size=len(value_names),
5299 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5300 oid: Integer() for oid in oids[:-1]
5303 for i, value_name in enumerate(value_names):
5304 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5306 class Seq(Sequence):
5309 for value_name, value in zip(value_names, values):
5310 seq[value_name] = Any(Integer(value).encode())
5311 seq["type"] = oid_chosen
5312 seq, _ = Seq().decode(seq.encode())
5313 for value_name in value_names:
5314 if value_name == value_name_chosen:
5316 self.assertIsNone(seq[value_name].defined)
5317 if value_name_chosen in oids[:-1]:
5318 self.assertIsNotNone(seq[value_name_chosen].defined)
5319 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5320 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5323 class TestDefinesByPath(TestCase):
5324 def test_generated(self):
5325 class Seq(Sequence):
5327 ("type", ObjectIdentifier()),
5328 ("value", OctetString(expl=tag_ctxc(123))),
5331 class SeqInner(Sequence):
5333 ("typeInner", ObjectIdentifier()),
5334 ("valueInner", Any()),
5337 class PairValue(SetOf):
5340 class Pair(Sequence):
5342 ("type", ObjectIdentifier()),
5343 ("value", PairValue()),
5346 class Pairs(SequenceOf):
5353 type_octet_stringed,
5355 ObjectIdentifier(oid)
5356 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5358 seq_integered = Seq()
5359 seq_integered["type"] = type_integered
5360 seq_integered["value"] = OctetString(Integer(123).encode())
5361 seq_integered_raw = seq_integered.encode()
5365 (type_octet_stringed, OctetString(b"whatever")),
5366 (type_integered, Integer(123)),
5367 (type_octet_stringed, OctetString(b"whenever")),
5368 (type_integered, Integer(234)),
5370 for t, v in pairs_input:
5373 pair["value"] = PairValue((Any(v),))
5375 seq_inner = SeqInner()
5376 seq_inner["typeInner"] = type_innered
5377 seq_inner["valueInner"] = Any(pairs)
5378 seq_sequenced = Seq()
5379 seq_sequenced["type"] = type_sequenced
5380 seq_sequenced["value"] = OctetString(seq_inner.encode())
5381 seq_sequenced_raw = seq_sequenced.encode()
5383 defines_by_path = []
5384 seq_integered, _ = Seq().decode(seq_integered_raw)
5385 self.assertIsNone(seq_integered["value"].defined)
5386 defines_by_path.append(
5387 (("type",), ((("value",), {
5388 type_integered: Integer(),
5389 type_sequenced: SeqInner(),
5392 seq_integered, _ = Seq().decode(
5394 ctx={"defines_by_path": defines_by_path},
5396 self.assertIsNotNone(seq_integered["value"].defined)
5397 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5398 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5399 self.assertTrue(seq_integered_raw[
5400 seq_integered["value"].defined[1].offset:
5401 ].startswith(Integer(123).encode()))
5403 seq_sequenced, _ = Seq().decode(
5405 ctx={"defines_by_path": defines_by_path},
5407 self.assertIsNotNone(seq_sequenced["value"].defined)
5408 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5409 seq_inner = seq_sequenced["value"].defined[1]
5410 self.assertIsNone(seq_inner["valueInner"].defined)
5412 defines_by_path.append((
5413 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5414 ((("valueInner",), {type_innered: Pairs()}),),
5416 seq_sequenced, _ = Seq().decode(
5418 ctx={"defines_by_path": defines_by_path},
5420 self.assertIsNotNone(seq_sequenced["value"].defined)
5421 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5422 seq_inner = seq_sequenced["value"].defined[1]
5423 self.assertIsNotNone(seq_inner["valueInner"].defined)
5424 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5425 pairs = seq_inner["valueInner"].defined[1]
5427 self.assertIsNone(pair["value"][0].defined)
5429 defines_by_path.append((
5432 DecodePathDefBy(type_sequenced),
5434 DecodePathDefBy(type_innered),
5439 type_integered: Integer(),
5440 type_octet_stringed: OctetString(),
5443 seq_sequenced, _ = Seq().decode(
5445 ctx={"defines_by_path": defines_by_path},
5447 self.assertIsNotNone(seq_sequenced["value"].defined)
5448 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5449 seq_inner = seq_sequenced["value"].defined[1]
5450 self.assertIsNotNone(seq_inner["valueInner"].defined)
5451 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5452 pairs_got = seq_inner["valueInner"].defined[1]
5453 for pair_input, pair_got in zip(pairs_input, pairs_got):
5454 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5455 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5457 @given(oid_strategy(), integers())
5458 def test_simple(self, oid, tgt):
5459 class Inner(Sequence):
5461 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5462 ObjectIdentifier(oid): Integer(),
5466 class Outer(Sequence):
5469 ("tgt", OctetString()),
5473 inner["oid"] = ObjectIdentifier(oid)
5475 outer["inner"] = inner
5476 outer["tgt"] = OctetString(Integer(tgt).encode())
5477 decoded, _ = Outer().decode(outer.encode())
5478 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5481 class TestAbsDecodePath(TestCase):
5483 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5484 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5486 def test_concat(self, decode_path, rel_path):
5487 self.assertSequenceEqual(
5488 abs_decode_path(decode_path, rel_path),
5489 decode_path + rel_path,
5493 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5494 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5496 def test_abs(self, decode_path, rel_path):
5497 self.assertSequenceEqual(
5498 abs_decode_path(decode_path, ("/",) + rel_path),
5503 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5504 integers(min_value=1, max_value=3),
5505 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5507 def test_dots(self, decode_path, number_of_dots, rel_path):
5508 self.assertSequenceEqual(
5509 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5510 decode_path[:-number_of_dots] + rel_path,
5514 class TestStrictDefaultExistence(TestCase):
5515 @given(data_strategy())
5516 def runTest(self, d):
5517 count = d.draw(integers(min_value=1, max_value=10))
5518 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5520 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5521 for i in range(count)
5524 class Seq(Sequence):
5527 for i in range(count):
5528 seq["int%d" % i] = Integer(123)
5530 chosen = "int%d" % chosen
5531 seq.specs[chosen] = seq.specs[chosen](default=123)
5533 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5534 seq.decode(raw, ctx={"strict_default_existence": True})
5537 class TestX690PrefixedType(TestCase):
5539 self.assertSequenceEqual(
5540 VisibleString("Jones").encode(),
5541 hexdec("1A054A6F6E6573"),
5543 self.assertSequenceEqual(
5546 impl=tag_encode(3, klass=TagClassApplication),
5548 hexdec("43054A6F6E6573"),
5550 self.assertSequenceEqual(
5554 impl=tag_encode(3, klass=TagClassApplication),
5558 hexdec("A20743054A6F6E6573"),
5560 self.assertSequenceEqual(
5564 impl=tag_encode(3, klass=TagClassApplication),
5566 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5568 hexdec("670743054A6F6E6573"),
5570 self.assertSequenceEqual(
5571 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5572 hexdec("82054A6F6E6573"),