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 printable
22 from string import whitespace
23 from unittest import TestCase
25 from hypothesis import assume
26 from hypothesis import given
27 from hypothesis import settings
28 from hypothesis.strategies import binary
29 from hypothesis.strategies import booleans
30 from hypothesis.strategies import composite
31 from hypothesis.strategies import data as data_strategy
32 from hypothesis.strategies import datetimes
33 from hypothesis.strategies import dictionaries
34 from hypothesis.strategies import integers
35 from hypothesis.strategies import just
36 from hypothesis.strategies import lists
37 from hypothesis.strategies import none
38 from hypothesis.strategies import one_of
39 from hypothesis.strategies import permutations
40 from hypothesis.strategies import sampled_from
41 from hypothesis.strategies import sets
42 from hypothesis.strategies import text
43 from hypothesis.strategies import tuples
44 from six import assertRaisesRegex
45 from six import byte2int
46 from six import indexbytes
47 from six import int2byte
48 from six import iterbytes
50 from six import text_type
52 from pyderasn import _pp
53 from pyderasn import abs_decode_path
54 from pyderasn import Any
55 from pyderasn import BitString
56 from pyderasn import BMPString
57 from pyderasn import Boolean
58 from pyderasn import BoundsError
59 from pyderasn import Choice
60 from pyderasn import DecodeError
61 from pyderasn import DecodePathDefBy
62 from pyderasn import Enumerated
63 from pyderasn import GeneralizedTime
64 from pyderasn import GeneralString
65 from pyderasn import GraphicString
66 from pyderasn import hexdec
67 from pyderasn import hexenc
68 from pyderasn import IA5String
69 from pyderasn import Integer
70 from pyderasn import InvalidLength
71 from pyderasn import InvalidOID
72 from pyderasn import InvalidValueType
73 from pyderasn import len_decode
74 from pyderasn import len_encode
75 from pyderasn import NotEnoughData
76 from pyderasn import Null
77 from pyderasn import NumericString
78 from pyderasn import ObjectIdentifier
79 from pyderasn import ObjNotReady
80 from pyderasn import ObjUnknown
81 from pyderasn import OctetString
82 from pyderasn import pp_console_row
83 from pyderasn import pprint
84 from pyderasn import PrintableString
85 from pyderasn import Sequence
86 from pyderasn import SequenceOf
87 from pyderasn import Set
88 from pyderasn import SetOf
89 from pyderasn import tag_ctxc
90 from pyderasn import tag_ctxp
91 from pyderasn import tag_decode
92 from pyderasn import tag_encode
93 from pyderasn import tag_strip
94 from pyderasn import TagClassApplication
95 from pyderasn import TagClassContext
96 from pyderasn import TagClassPrivate
97 from pyderasn import TagClassUniversal
98 from pyderasn import TagFormConstructed
99 from pyderasn import TagFormPrimitive
100 from pyderasn import TagMismatch
101 from pyderasn import TeletexString
102 from pyderasn import UniversalString
103 from pyderasn import UTCTime
104 from pyderasn import UTF8String
105 from pyderasn import VideotexString
106 from pyderasn import VisibleString
109 settings.register_profile('local', settings(
111 perform_health_check=False,
113 settings.load_profile('local')
114 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
116 tag_classes = sampled_from((
122 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
125 class TestHex(TestCase):
127 def test_symmetric(self, data):
128 self.assertEqual(hexdec(hexenc(data)), data)
131 class TestTagCoder(TestCase):
132 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
136 integers(min_value=0, max_value=30),
139 def test_short(self, klass, form, num, junk):
140 raw = tag_encode(klass=klass, form=form, num=num)
141 self.assertEqual(tag_decode(raw), (klass, form, num))
142 self.assertEqual(len(raw), 1)
144 byte2int(tag_encode(klass=klass, form=form, num=0)),
145 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
147 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
148 self.assertSequenceEqual(stripped.tobytes(), raw)
149 self.assertEqual(tlen, len(raw))
150 self.assertSequenceEqual(tail, junk)
152 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
156 integers(min_value=31),
159 def test_long(self, klass, form, num, junk):
160 raw = tag_encode(klass=klass, form=form, num=num)
161 self.assertEqual(tag_decode(raw), (klass, form, num))
162 self.assertGreater(len(raw), 1)
164 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
167 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
168 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
169 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
170 self.assertSequenceEqual(stripped.tobytes(), raw)
171 self.assertEqual(tlen, len(raw))
172 self.assertSequenceEqual(tail, junk)
174 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
175 @given(integers(min_value=31))
176 def test_unfinished_tag(self, num):
177 raw = bytearray(tag_encode(num=num))
178 for i in range(1, len(raw)):
180 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
181 tag_strip(bytes(raw))
183 def test_go_vectors_valid(self):
184 for data, (eklass, etag, elen, eform) in (
185 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
186 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
187 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
188 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
189 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
190 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
191 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
192 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
193 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
194 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
196 tag, _, len_encoded = tag_strip(memoryview(data))
197 klass, form, num = tag_decode(tag)
198 _len, _, tail = len_decode(len_encoded)
199 self.assertSequenceEqual(tail, b"")
200 self.assertEqual(klass, eklass)
201 self.assertEqual(num, etag)
202 self.assertEqual(_len, elen)
203 self.assertEqual(form, eform)
205 def test_go_vectors_invalid(self):
213 with self.assertRaises(DecodeError):
214 _, _, len_encoded = tag_strip(memoryview(data))
215 len_decode(len_encoded)
218 integers(min_value=0, max_value=127),
219 integers(min_value=0, max_value=2),
221 def test_long_instead_of_short(self, l, dummy_num):
222 octets = (b"\x00" * dummy_num) + int2byte(l)
223 octets = int2byte((dummy_num + 1) | 0x80) + octets
224 with self.assertRaises(DecodeError):
228 class TestLenCoder(TestCase):
229 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
231 integers(min_value=0, max_value=127),
234 def test_short(self, l, junk):
235 raw = len_encode(l) + junk
236 decoded, llen, tail = len_decode(memoryview(raw))
237 self.assertEqual(decoded, l)
238 self.assertEqual(llen, 1)
239 self.assertEqual(len(raw), 1 + len(junk))
240 self.assertEqual(tail.tobytes(), junk)
242 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
244 integers(min_value=128),
247 def test_long(self, l, junk):
248 raw = len_encode(l) + junk
249 decoded, llen, tail = len_decode(memoryview(raw))
250 self.assertEqual(decoded, l)
251 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
252 self.assertEqual(llen, len(raw) - len(junk))
253 self.assertNotEqual(indexbytes(raw, 1), 0)
254 self.assertSequenceEqual(tail.tobytes(), junk)
256 def test_empty(self):
257 with self.assertRaises(NotEnoughData):
260 @given(integers(min_value=128))
261 def test_stripped(self, _len):
262 with self.assertRaises(NotEnoughData):
263 len_decode(len_encode(_len)[:-1])
266 text_printable = text(alphabet=printable, min_size=1)
270 def text_letters(draw):
271 result = draw(text(alphabet=ascii_letters, min_size=1))
273 result = result.encode("ascii")
277 class CommonMixin(object):
278 def test_tag_default(self):
279 obj = self.base_klass()
280 self.assertEqual(obj.tag, obj.tag_default)
282 def test_simultaneous_impl_expl(self):
283 with self.assertRaises(ValueError):
284 self.base_klass(impl=b"whatever", expl=b"whenever")
286 @given(binary(), integers(), integers(), integers())
287 def test_decoded(self, impl, offset, llen, vlen):
288 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
289 self.assertEqual(obj.offset, offset)
290 self.assertEqual(obj.llen, llen)
291 self.assertEqual(obj.vlen, vlen)
292 self.assertEqual(obj.tlen, len(impl))
293 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
296 def test_impl_inherited(self, impl_tag):
297 class Inherited(self.base_klass):
300 self.assertSequenceEqual(obj.impl, impl_tag)
301 self.assertFalse(obj.expled)
304 def test_expl_inherited(self, expl_tag):
305 class Inherited(self.base_klass):
308 self.assertSequenceEqual(obj.expl, expl_tag)
309 self.assertTrue(obj.expled)
311 def assert_copied_basic_fields(self, obj, obj_copied):
312 self.assertEqual(obj, obj_copied)
313 self.assertSequenceEqual(obj.tag, obj_copied.tag)
314 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
315 self.assertEqual(obj.default, obj_copied.default)
316 self.assertEqual(obj.optional, obj_copied.optional)
317 self.assertEqual(obj.offset, obj_copied.offset)
318 self.assertEqual(obj.llen, obj_copied.llen)
319 self.assertEqual(obj.vlen, obj_copied.vlen)
323 def boolean_values_strategy(draw, do_expl=False):
324 value = draw(one_of(none(), booleans()))
328 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
330 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
331 default = draw(one_of(none(), booleans()))
332 optional = draw(one_of(none(), booleans()))
334 draw(integers(min_value=0)),
335 draw(integers(min_value=0)),
336 draw(integers(min_value=0)),
338 return (value, impl, expl, default, optional, _decoded)
341 class BooleanInherited(Boolean):
345 class TestBoolean(CommonMixin, TestCase):
348 def test_invalid_value_type(self):
349 with self.assertRaises(InvalidValueType) as err:
354 def test_optional(self, optional):
355 obj = Boolean(default=Boolean(False), optional=optional)
356 self.assertTrue(obj.optional)
359 def test_ready(self, value):
361 self.assertFalse(obj.ready)
364 with self.assertRaises(ObjNotReady) as err:
368 self.assertTrue(obj.ready)
372 @given(booleans(), booleans(), binary(), binary())
373 def test_comparison(self, value1, value2, tag1, tag2):
374 for klass in (Boolean, BooleanInherited):
377 self.assertEqual(obj1 == obj2, value1 == value2)
378 self.assertEqual(obj1 != obj2, value1 != value2)
379 self.assertEqual(obj1 == bool(obj2), value1 == value2)
380 obj1 = klass(value1, impl=tag1)
381 obj2 = klass(value1, impl=tag2)
382 self.assertEqual(obj1 == obj2, tag1 == tag2)
383 self.assertEqual(obj1 != obj2, tag1 != tag2)
385 @given(data_strategy())
386 def test_call(self, d):
387 for klass in (Boolean, BooleanInherited):
395 ) = d.draw(boolean_values_strategy())
401 optional_initial or False,
411 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
412 obj = obj_initial(value, impl, expl, default, optional)
414 value_expected = default if value is None else value
416 default_initial if value_expected is None
419 self.assertEqual(obj, value_expected)
420 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
421 self.assertEqual(obj.expl_tag, expl or expl_initial)
424 default_initial if default is None else default,
426 if obj.default is None:
427 optional = optional_initial if optional is None else optional
428 optional = False if optional is None else optional
431 self.assertEqual(obj.optional, optional)
433 @given(boolean_values_strategy())
434 def test_copy(self, values):
435 for klass in (Boolean, BooleanInherited):
437 obj_copied = obj.copy()
438 self.assert_copied_basic_fields(obj, obj_copied)
442 integers(min_value=1).map(tag_encode),
444 def test_stripped(self, value, tag_impl):
445 obj = Boolean(value, impl=tag_impl)
446 with self.assertRaises(NotEnoughData):
447 obj.decode(obj.encode()[:-1])
451 integers(min_value=1).map(tag_ctxc),
453 def test_stripped_expl(self, value, tag_expl):
454 obj = Boolean(value, expl=tag_expl)
455 with self.assertRaises(NotEnoughData):
456 obj.decode(obj.encode()[:-1])
459 integers(min_value=31),
460 integers(min_value=0),
463 def test_bad_tag(self, tag, offset, decode_path):
464 decode_path = tuple(str(i) for i in decode_path)
465 with self.assertRaises(DecodeError) as err:
467 tag_encode(tag)[:-1],
469 decode_path=decode_path,
472 self.assertEqual(err.exception.offset, offset)
473 self.assertEqual(err.exception.decode_path, decode_path)
476 integers(min_value=31),
477 integers(min_value=0),
480 def test_bad_expl_tag(self, tag, offset, decode_path):
481 decode_path = tuple(str(i) for i in decode_path)
482 with self.assertRaises(DecodeError) as err:
483 Boolean(expl=Boolean.tag_default).decode(
484 tag_encode(tag)[:-1],
486 decode_path=decode_path,
489 self.assertEqual(err.exception.offset, offset)
490 self.assertEqual(err.exception.decode_path, decode_path)
493 integers(min_value=128),
494 integers(min_value=0),
497 def test_bad_len(self, l, offset, decode_path):
498 decode_path = tuple(str(i) for i in decode_path)
499 with self.assertRaises(DecodeError) as err:
501 Boolean.tag_default + len_encode(l)[:-1],
503 decode_path=decode_path,
506 self.assertEqual(err.exception.offset, offset)
507 self.assertEqual(err.exception.decode_path, decode_path)
510 integers(min_value=128),
511 integers(min_value=0),
514 def test_bad_expl_len(self, l, offset, decode_path):
515 decode_path = tuple(str(i) for i in decode_path)
516 with self.assertRaises(DecodeError) as err:
517 Boolean(expl=Boolean.tag_default).decode(
518 Boolean.tag_default + len_encode(l)[:-1],
520 decode_path=decode_path,
523 self.assertEqual(err.exception.offset, offset)
524 self.assertEqual(err.exception.decode_path, decode_path)
526 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
528 boolean_values_strategy(),
530 integers(min_value=1).map(tag_ctxc),
531 integers(min_value=0),
534 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
535 for klass in (Boolean, BooleanInherited):
536 _, _, _, default, optional, _decoded = values
545 self.assertFalse(obj.expled)
546 obj_encoded = obj.encode()
547 obj_expled = obj(value, expl=tag_expl)
548 self.assertTrue(obj_expled.expled)
551 obj_expled_encoded = obj_expled.encode()
552 obj_decoded, tail = obj_expled.decode(
553 obj_expled_encoded + tail_junk,
558 self.assertEqual(tail, tail_junk)
559 self.assertEqual(obj_decoded, obj_expled)
560 self.assertNotEqual(obj_decoded, obj)
561 self.assertEqual(bool(obj_decoded), bool(obj_expled))
562 self.assertEqual(bool(obj_decoded), bool(obj))
563 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
564 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
565 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
567 obj_decoded.expl_llen,
568 len(len_encode(len(obj_encoded))),
570 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
571 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
574 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
576 self.assertEqual(obj_decoded.expl_offset, offset)
578 @given(integers(min_value=2))
579 def test_invalid_len(self, l):
580 with self.assertRaises(InvalidLength):
581 Boolean().decode(b"".join((
587 @given(integers(min_value=0 + 1, max_value=255 - 1))
588 def test_invalid_value(self, value):
589 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
590 Boolean().decode(b"".join((
598 def integer_values_strategy(draw, do_expl=False):
599 bound_min, value, default, bound_max = sorted(draw(sets(
608 _specs = draw(sets(text_letters()))
611 min_size=len(_specs),
612 max_size=len(_specs),
614 _specs = list(zip(_specs, values))
617 bounds = (bound_min, bound_max)
621 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
623 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
626 optional = draw(one_of(none(), booleans()))
628 draw(integers(min_value=0)),
629 draw(integers(min_value=0)),
630 draw(integers(min_value=0)),
632 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
635 class IntegerInherited(Integer):
639 class TestInteger(CommonMixin, TestCase):
642 def test_invalid_value_type(self):
643 with self.assertRaises(InvalidValueType) as err:
647 @given(sets(text_letters(), min_size=2))
648 def test_unknown_name(self, names_input):
649 missing = names_input.pop()
652 schema = [(n, 123) for n in names_input]
653 with self.assertRaises(ObjUnknown) as err:
657 @given(sets(text_letters(), min_size=2))
658 def test_known_name(self, names_input):
660 schema = [(n, 123) for n in names_input]
661 Int(names_input.pop())
664 def test_optional(self, optional):
665 obj = Integer(default=Integer(0), optional=optional)
666 self.assertTrue(obj.optional)
669 def test_ready(self, value):
671 self.assertFalse(obj.ready)
674 with self.assertRaises(ObjNotReady) as err:
678 self.assertTrue(obj.ready)
683 @given(integers(), integers(), binary(), binary())
684 def test_comparison(self, value1, value2, tag1, tag2):
685 for klass in (Integer, IntegerInherited):
688 self.assertEqual(obj1 == obj2, value1 == value2)
689 self.assertEqual(obj1 != obj2, value1 != value2)
690 self.assertEqual(obj1 == int(obj2), value1 == value2)
691 obj1 = klass(value1, impl=tag1)
692 obj2 = klass(value1, impl=tag2)
693 self.assertEqual(obj1 == obj2, tag1 == tag2)
694 self.assertEqual(obj1 != obj2, tag1 != tag2)
696 @given(lists(integers()))
697 def test_sorted_works(self, values):
698 self.assertSequenceEqual(
699 [int(v) for v in sorted(Integer(v) for v in values)],
703 @given(data_strategy())
704 def test_named(self, d):
705 names_input = list(d.draw(sets(text_letters(), min_size=1)))
706 values_input = list(d.draw(sets(
708 min_size=len(names_input),
709 max_size=len(names_input),
711 chosen_name = d.draw(sampled_from(names_input))
712 names_input = dict(zip(names_input, values_input))
716 _int = Int(chosen_name)
717 self.assertEqual(_int.named, chosen_name)
718 self.assertEqual(int(_int), names_input[chosen_name])
720 @given(integers(), integers(min_value=0), integers(min_value=0))
721 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
722 value = bound_min + value_delta
723 bound_max = value + bound_delta
724 Integer(value=value, bounds=(bound_min, bound_max))
726 @given(sets(integers(), min_size=3, max_size=3))
727 def test_bounds_unsatisfied(self, values):
728 values = sorted(values)
729 with self.assertRaises(BoundsError) as err:
730 Integer(value=values[0], bounds=(values[1], values[2]))
732 with self.assertRaises(BoundsError) as err:
733 Integer(value=values[2], bounds=(values[0], values[1]))
736 @given(data_strategy())
737 def test_call(self, d):
738 for klass in (Integer, IntegerInherited):
748 ) = d.draw(integer_values_strategy())
755 optional_initial or False,
768 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
769 if (default is None) and (obj_initial.default is not None):
773 (value is not None) and
774 (bounds_initial is not None) and
775 not (bounds_initial[0] <= value <= bounds_initial[1])
780 (default is not None) and
781 (bounds_initial is not None) and
782 not (bounds_initial[0] <= default <= bounds_initial[1])
785 obj = obj_initial(value, bounds, impl, expl, default, optional)
787 value_expected = default if value is None else value
789 default_initial if value_expected is None
792 self.assertEqual(obj, value_expected)
793 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
794 self.assertEqual(obj.expl_tag, expl or expl_initial)
797 default_initial if default is None else default,
799 if obj.default is None:
800 optional = optional_initial if optional is None else optional
801 optional = False if optional is None else optional
804 self.assertEqual(obj.optional, optional)
806 (obj._bound_min, obj._bound_max),
807 bounds or bounds_initial or (float("-inf"), float("+inf")),
811 {} if _specs_initial is None else dict(_specs_initial),
814 @given(integer_values_strategy())
815 def test_copy(self, values):
816 for klass in (Integer, IntegerInherited):
818 obj_copied = obj.copy()
819 self.assert_copied_basic_fields(obj, obj_copied)
820 self.assertEqual(obj.specs, obj_copied.specs)
821 self.assertEqual(obj._bound_min, obj_copied._bound_min)
822 self.assertEqual(obj._bound_max, obj_copied._bound_max)
823 self.assertEqual(obj._value, obj_copied._value)
827 integers(min_value=1).map(tag_encode),
829 def test_stripped(self, value, tag_impl):
830 obj = Integer(value, impl=tag_impl)
831 with self.assertRaises(NotEnoughData):
832 obj.decode(obj.encode()[:-1])
836 integers(min_value=1).map(tag_ctxc),
838 def test_stripped_expl(self, value, tag_expl):
839 obj = Integer(value, expl=tag_expl)
840 with self.assertRaises(NotEnoughData):
841 obj.decode(obj.encode()[:-1])
843 def test_zero_len(self):
844 with self.assertRaises(NotEnoughData):
845 Integer().decode(b"".join((
851 integers(min_value=31),
852 integers(min_value=0),
855 def test_bad_tag(self, tag, offset, decode_path):
856 decode_path = tuple(str(i) for i in decode_path)
857 with self.assertRaises(DecodeError) as err:
859 tag_encode(tag)[:-1],
861 decode_path=decode_path,
864 self.assertEqual(err.exception.offset, offset)
865 self.assertEqual(err.exception.decode_path, decode_path)
868 integers(min_value=128),
869 integers(min_value=0),
872 def test_bad_len(self, l, offset, decode_path):
873 decode_path = tuple(str(i) for i in decode_path)
874 with self.assertRaises(DecodeError) as err:
876 Integer.tag_default + len_encode(l)[:-1],
878 decode_path=decode_path,
881 self.assertEqual(err.exception.offset, offset)
882 self.assertEqual(err.exception.decode_path, decode_path)
885 sets(integers(), min_size=2, max_size=2),
886 integers(min_value=0),
889 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
890 decode_path = tuple(str(i) for i in decode_path)
891 value, bound_min = list(sorted(ints))
894 bounds = (bound_min, bound_min)
895 with self.assertRaises(DecodeError) as err:
897 Integer(value).encode(),
899 decode_path=decode_path,
902 self.assertEqual(err.exception.offset, offset)
903 self.assertEqual(err.exception.decode_path, decode_path)
905 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
907 integer_values_strategy(),
909 integers(min_value=1).map(tag_ctxc),
910 integers(min_value=0),
913 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
914 for klass in (Integer, IntegerInherited):
915 _, _, _, _, default, optional, _, _decoded = values
924 self.assertFalse(obj.expled)
925 obj_encoded = obj.encode()
926 obj_expled = obj(value, expl=tag_expl)
927 self.assertTrue(obj_expled.expled)
930 obj_expled_encoded = obj_expled.encode()
931 obj_decoded, tail = obj_expled.decode(
932 obj_expled_encoded + tail_junk,
937 self.assertEqual(tail, tail_junk)
938 self.assertEqual(obj_decoded, obj_expled)
939 self.assertNotEqual(obj_decoded, obj)
940 self.assertEqual(int(obj_decoded), int(obj_expled))
941 self.assertEqual(int(obj_decoded), int(obj))
942 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
943 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
944 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
946 obj_decoded.expl_llen,
947 len(len_encode(len(obj_encoded))),
949 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
950 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
953 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
955 self.assertEqual(obj_decoded.expl_offset, offset)
957 def test_go_vectors_valid(self):
958 for data, expect in ((
970 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
971 (b"\x80\x00\x00\x00", -2147483648),
974 Integer().decode(b"".join((
976 len_encode(len(data)),
982 def test_go_vectors_invalid(self):
987 with self.assertRaises(DecodeError):
988 Integer().decode(b"".join((
990 len_encode(len(data)),
996 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1000 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1002 integers(min_value=0, max_value=255),
1003 min_size=len(schema),
1004 max_size=len(schema),
1006 schema = list(zip(schema, bits))
1008 def _value(value_required):
1009 if not value_required and draw(booleans()):
1011 generation_choice = 0
1013 generation_choice = draw(sampled_from((1, 2, 3)))
1014 if generation_choice == 1 or draw(booleans()):
1015 return "'%s'B" % "".join(draw(lists(
1016 sampled_from(("0", "1")),
1017 max_size=len(schema),
1019 elif generation_choice == 2 or draw(booleans()):
1020 return draw(binary(max_size=len(schema) // 8))
1021 elif generation_choice == 3 or draw(booleans()):
1022 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1024 value = _value(value_required)
1025 default = _value(value_required=False)
1029 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1031 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1032 optional = draw(one_of(none(), booleans()))
1034 draw(integers(min_value=0)),
1035 draw(integers(min_value=0)),
1036 draw(integers(min_value=0)),
1038 return (schema, value, impl, expl, default, optional, _decoded)
1041 class BitStringInherited(BitString):
1045 class TestBitString(CommonMixin, TestCase):
1046 base_klass = BitString
1048 @given(lists(booleans()))
1049 def test_b_encoding(self, bits):
1050 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1051 self.assertEqual(obj.bit_len, len(bits))
1052 self.assertSequenceEqual(list(obj), bits)
1053 for i, bit in enumerate(bits):
1054 self.assertEqual(obj[i], bit)
1056 @given(lists(booleans()))
1057 def test_out_of_bounds_bits(self, bits):
1058 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1059 for i in range(len(bits), len(bits) * 2):
1060 self.assertFalse(obj[i])
1062 def test_bad_b_encoding(self):
1063 with self.assertRaises(ValueError):
1064 BitString("'010120101'B")
1067 integers(min_value=1, max_value=255),
1068 integers(min_value=1, max_value=255),
1070 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1071 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1072 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1073 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1075 class BS(BitString):
1076 schema = (("whatever", 0),)
1077 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1078 self.assertEqual(obj.bit_len, leading_zeros + 1)
1079 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1081 def test_zero_len(self):
1082 with self.assertRaises(NotEnoughData):
1083 BitString().decode(b"".join((
1084 BitString.tag_default,
1088 def test_invalid_value_type(self):
1089 with self.assertRaises(InvalidValueType) as err:
1092 with self.assertRaises(InvalidValueType) as err:
1096 def test_obj_unknown(self):
1097 with self.assertRaises(ObjUnknown) as err:
1098 BitString(b"whatever")["whenever"]
1101 def test_get_invalid_type(self):
1102 with self.assertRaises(InvalidValueType) as err:
1103 BitString(b"whatever")[(1, 2, 3)]
1106 @given(data_strategy())
1107 def test_unknown_name(self, d):
1108 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1109 missing = _schema.pop()
1111 class BS(BitString):
1112 schema = [(n, i) for i, n in enumerate(_schema)]
1113 with self.assertRaises(ObjUnknown) as err:
1118 def test_optional(self, optional):
1119 obj = BitString(default=BitString(b""), optional=optional)
1120 self.assertTrue(obj.optional)
1123 def test_ready(self, value):
1125 self.assertFalse(obj.ready)
1128 with self.assertRaises(ObjNotReady) as err:
1131 obj = BitString(value)
1132 self.assertTrue(obj.ready)
1137 tuples(integers(min_value=0), binary()),
1138 tuples(integers(min_value=0), binary()),
1142 def test_comparison(self, value1, value2, tag1, tag2):
1143 for klass in (BitString, BitStringInherited):
1144 obj1 = klass(value1)
1145 obj2 = klass(value2)
1146 self.assertEqual(obj1 == obj2, value1 == value2)
1147 self.assertEqual(obj1 != obj2, value1 != value2)
1148 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1149 obj1 = klass(value1, impl=tag1)
1150 obj2 = klass(value1, impl=tag2)
1151 self.assertEqual(obj1 == obj2, tag1 == tag2)
1152 self.assertEqual(obj1 != obj2, tag1 != tag2)
1154 @given(data_strategy())
1155 def test_call(self, d):
1156 for klass in (BitString, BitStringInherited):
1165 ) = d.draw(bit_string_values_strategy())
1168 schema = schema_initial
1170 value=value_initial,
1173 default=default_initial,
1174 optional=optional_initial or False,
1175 _decoded=_decoded_initial,
1185 ) = d.draw(bit_string_values_strategy(
1186 schema=schema_initial,
1187 do_expl=impl_initial is None,
1196 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1197 self.assertEqual(obj.expl_tag, expl or expl_initial)
1198 if obj.default is None:
1199 optional = optional_initial if optional is None else optional
1200 optional = False if optional is None else optional
1203 self.assertEqual(obj.optional, optional)
1204 self.assertEqual(obj.specs, obj_initial.specs)
1206 @given(bit_string_values_strategy())
1207 def test_copy(self, values):
1208 for klass in (BitString, BitStringInherited):
1209 _schema, value, impl, expl, default, optional, _decoded = values
1218 optional=optional or False,
1221 obj_copied = obj.copy()
1222 self.assert_copied_basic_fields(obj, obj_copied)
1223 self.assertEqual(obj.specs, obj_copied.specs)
1224 self.assertEqual(obj._value, obj_copied._value)
1228 integers(min_value=1).map(tag_encode),
1230 def test_stripped(self, value, tag_impl):
1231 obj = BitString(value, impl=tag_impl)
1232 with self.assertRaises(NotEnoughData):
1233 obj.decode(obj.encode()[:-1])
1237 integers(min_value=1).map(tag_ctxc),
1239 def test_stripped_expl(self, value, tag_expl):
1240 obj = BitString(value, expl=tag_expl)
1241 with self.assertRaises(NotEnoughData):
1242 obj.decode(obj.encode()[:-1])
1245 integers(min_value=31),
1246 integers(min_value=0),
1249 def test_bad_tag(self, tag, offset, decode_path):
1250 decode_path = tuple(str(i) for i in decode_path)
1251 with self.assertRaises(DecodeError) as err:
1253 tag_encode(tag)[:-1],
1255 decode_path=decode_path,
1258 self.assertEqual(err.exception.offset, offset)
1259 self.assertEqual(err.exception.decode_path, decode_path)
1262 integers(min_value=128),
1263 integers(min_value=0),
1266 def test_bad_len(self, l, offset, decode_path):
1267 decode_path = tuple(str(i) for i in decode_path)
1268 with self.assertRaises(DecodeError) as err:
1270 BitString.tag_default + len_encode(l)[:-1],
1272 decode_path=decode_path,
1275 self.assertEqual(err.exception.offset, offset)
1276 self.assertEqual(err.exception.decode_path, decode_path)
1278 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1279 @given(data_strategy())
1280 def test_symmetric(self, d):
1289 ) = d.draw(bit_string_values_strategy(value_required=True))
1290 tail_junk = d.draw(binary(max_size=5))
1291 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1292 offset = d.draw(integers(min_value=0))
1293 for klass in (BitString, BitStringInherited):
1304 self.assertFalse(obj.expled)
1305 obj_encoded = obj.encode()
1306 obj_expled = obj(value, expl=tag_expl)
1307 self.assertTrue(obj_expled.expled)
1310 obj_expled_encoded = obj_expled.encode()
1311 obj_decoded, tail = obj_expled.decode(
1312 obj_expled_encoded + tail_junk,
1317 self.assertEqual(tail, tail_junk)
1318 self.assertEqual(obj_decoded, obj_expled)
1319 self.assertNotEqual(obj_decoded, obj)
1320 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1321 self.assertEqual(bytes(obj_decoded), bytes(obj))
1322 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1323 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1324 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1326 obj_decoded.expl_llen,
1327 len(len_encode(len(obj_encoded))),
1329 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1330 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1333 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1335 self.assertEqual(obj_decoded.expl_offset, offset)
1336 if isinstance(value, tuple):
1337 self.assertSetEqual(set(value), set(obj_decoded.named))
1341 @given(integers(min_value=1, max_value=255))
1342 def test_bad_zero_value(self, pad_size):
1343 with self.assertRaises(DecodeError):
1344 BitString().decode(b"".join((
1345 BitString.tag_default,
1350 def test_go_vectors_invalid(self):
1356 with self.assertRaises(DecodeError):
1357 BitString().decode(b"".join((
1358 BitString.tag_default,
1363 def test_go_vectors_valid(self):
1364 obj, _ = BitString().decode(b"".join((
1365 BitString.tag_default,
1369 self.assertEqual(bytes(obj), b"")
1370 self.assertEqual(obj.bit_len, 0)
1372 obj, _ = BitString().decode(b"".join((
1373 BitString.tag_default,
1377 self.assertEqual(bytes(obj), b"\x00")
1378 self.assertEqual(obj.bit_len, 1)
1380 obj = BitString((16, b"\x82\x40"))
1381 self.assertTrue(obj[0])
1382 self.assertFalse(obj[1])
1383 self.assertTrue(obj[6])
1384 self.assertTrue(obj[9])
1385 self.assertFalse(obj[17])
1389 def octet_string_values_strategy(draw, do_expl=False):
1390 bound_min, bound_max = sorted(draw(sets(
1391 integers(min_value=0, max_value=1 << 7),
1395 value = draw(one_of(
1397 binary(min_size=bound_min, max_size=bound_max),
1399 default = draw(one_of(
1401 binary(min_size=bound_min, max_size=bound_max),
1404 if draw(booleans()):
1405 bounds = (bound_min, bound_max)
1409 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1411 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1412 optional = draw(one_of(none(), booleans()))
1414 draw(integers(min_value=0)),
1415 draw(integers(min_value=0)),
1416 draw(integers(min_value=0)),
1418 return (value, bounds, impl, expl, default, optional, _decoded)
1421 class OctetStringInherited(OctetString):
1425 class TestOctetString(CommonMixin, TestCase):
1426 base_klass = OctetString
1428 def test_invalid_value_type(self):
1429 with self.assertRaises(InvalidValueType) as err:
1430 OctetString(text_type(123))
1434 def test_optional(self, optional):
1435 obj = OctetString(default=OctetString(b""), optional=optional)
1436 self.assertTrue(obj.optional)
1439 def test_ready(self, value):
1441 self.assertFalse(obj.ready)
1444 with self.assertRaises(ObjNotReady) as err:
1447 obj = OctetString(value)
1448 self.assertTrue(obj.ready)
1452 @given(binary(), binary(), binary(), binary())
1453 def test_comparison(self, value1, value2, tag1, tag2):
1454 for klass in (OctetString, OctetStringInherited):
1455 obj1 = klass(value1)
1456 obj2 = klass(value2)
1457 self.assertEqual(obj1 == obj2, value1 == value2)
1458 self.assertEqual(obj1 != obj2, value1 != value2)
1459 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1460 obj1 = klass(value1, impl=tag1)
1461 obj2 = klass(value1, impl=tag2)
1462 self.assertEqual(obj1 == obj2, tag1 == tag2)
1463 self.assertEqual(obj1 != obj2, tag1 != tag2)
1465 @given(lists(binary()))
1466 def test_sorted_works(self, values):
1467 self.assertSequenceEqual(
1468 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1472 @given(data_strategy())
1473 def test_bounds_satisfied(self, d):
1474 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1475 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1476 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1477 OctetString(value=value, bounds=(bound_min, bound_max))
1479 @given(data_strategy())
1480 def test_bounds_unsatisfied(self, d):
1481 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1482 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1483 value = d.draw(binary(max_size=bound_min - 1))
1484 with self.assertRaises(BoundsError) as err:
1485 OctetString(value=value, bounds=(bound_min, bound_max))
1487 value = d.draw(binary(min_size=bound_max + 1))
1488 with self.assertRaises(BoundsError) as err:
1489 OctetString(value=value, bounds=(bound_min, bound_max))
1492 @given(data_strategy())
1493 def test_call(self, d):
1494 for klass in (OctetString, OctetStringInherited):
1503 ) = d.draw(octet_string_values_strategy())
1504 obj_initial = klass(
1510 optional_initial or False,
1521 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1522 if (default is None) and (obj_initial.default is not None):
1525 (bounds is None) and
1526 (value is not None) and
1527 (bounds_initial is not None) and
1528 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1532 (bounds is None) and
1533 (default is not None) and
1534 (bounds_initial is not None) and
1535 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1538 obj = obj_initial(value, bounds, impl, expl, default, optional)
1540 value_expected = default if value is None else value
1542 default_initial if value_expected is None
1545 self.assertEqual(obj, value_expected)
1546 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1547 self.assertEqual(obj.expl_tag, expl or expl_initial)
1550 default_initial if default is None else default,
1552 if obj.default is None:
1553 optional = optional_initial if optional is None else optional
1554 optional = False if optional is None else optional
1557 self.assertEqual(obj.optional, optional)
1559 (obj._bound_min, obj._bound_max),
1560 bounds or bounds_initial or (0, float("+inf")),
1563 @given(octet_string_values_strategy())
1564 def test_copy(self, values):
1565 for klass in (OctetString, OctetStringInherited):
1566 obj = klass(*values)
1567 obj_copied = obj.copy()
1568 self.assert_copied_basic_fields(obj, obj_copied)
1569 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1570 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1571 self.assertEqual(obj._value, obj_copied._value)
1575 integers(min_value=1).map(tag_encode),
1577 def test_stripped(self, value, tag_impl):
1578 obj = OctetString(value, impl=tag_impl)
1579 with self.assertRaises(NotEnoughData):
1580 obj.decode(obj.encode()[:-1])
1584 integers(min_value=1).map(tag_ctxc),
1586 def test_stripped_expl(self, value, tag_expl):
1587 obj = OctetString(value, expl=tag_expl)
1588 with self.assertRaises(NotEnoughData):
1589 obj.decode(obj.encode()[:-1])
1592 integers(min_value=31),
1593 integers(min_value=0),
1596 def test_bad_tag(self, tag, offset, decode_path):
1597 decode_path = tuple(str(i) for i in decode_path)
1598 with self.assertRaises(DecodeError) as err:
1599 OctetString().decode(
1600 tag_encode(tag)[:-1],
1602 decode_path=decode_path,
1605 self.assertEqual(err.exception.offset, offset)
1606 self.assertEqual(err.exception.decode_path, decode_path)
1609 integers(min_value=128),
1610 integers(min_value=0),
1613 def test_bad_len(self, l, offset, decode_path):
1614 decode_path = tuple(str(i) for i in decode_path)
1615 with self.assertRaises(DecodeError) as err:
1616 OctetString().decode(
1617 OctetString.tag_default + len_encode(l)[:-1],
1619 decode_path=decode_path,
1622 self.assertEqual(err.exception.offset, offset)
1623 self.assertEqual(err.exception.decode_path, decode_path)
1626 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1627 integers(min_value=0),
1630 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1631 decode_path = tuple(str(i) for i in decode_path)
1632 value, bound_min = list(sorted(ints))
1634 class String(OctetString):
1635 bounds = (bound_min, bound_min)
1636 with self.assertRaises(DecodeError) as err:
1638 OctetString(b"\x00" * value).encode(),
1640 decode_path=decode_path,
1643 self.assertEqual(err.exception.offset, offset)
1644 self.assertEqual(err.exception.decode_path, decode_path)
1646 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1648 octet_string_values_strategy(),
1650 integers(min_value=1).map(tag_ctxc),
1651 integers(min_value=0),
1654 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1655 for klass in (OctetString, OctetStringInherited):
1656 _, _, _, _, default, optional, _decoded = values
1665 self.assertFalse(obj.expled)
1666 obj_encoded = obj.encode()
1667 obj_expled = obj(value, expl=tag_expl)
1668 self.assertTrue(obj_expled.expled)
1671 obj_expled_encoded = obj_expled.encode()
1672 obj_decoded, tail = obj_expled.decode(
1673 obj_expled_encoded + tail_junk,
1678 self.assertEqual(tail, tail_junk)
1679 self.assertEqual(obj_decoded, obj_expled)
1680 self.assertNotEqual(obj_decoded, obj)
1681 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1682 self.assertEqual(bytes(obj_decoded), bytes(obj))
1683 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1684 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1685 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1687 obj_decoded.expl_llen,
1688 len(len_encode(len(obj_encoded))),
1690 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1691 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1694 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1696 self.assertEqual(obj_decoded.expl_offset, offset)
1700 def null_values_strategy(draw, do_expl=False):
1704 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1706 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1707 optional = draw(one_of(none(), booleans()))
1709 draw(integers(min_value=0)),
1710 draw(integers(min_value=0)),
1711 draw(integers(min_value=0)),
1713 return (impl, expl, optional, _decoded)
1716 class NullInherited(Null):
1720 class TestNull(CommonMixin, TestCase):
1723 def test_ready(self):
1725 self.assertTrue(obj.ready)
1729 @given(binary(), binary())
1730 def test_comparison(self, tag1, tag2):
1731 for klass in (Null, NullInherited):
1732 obj1 = klass(impl=tag1)
1733 obj2 = klass(impl=tag2)
1734 self.assertEqual(obj1 == obj2, tag1 == tag2)
1735 self.assertEqual(obj1 != obj2, tag1 != tag2)
1736 self.assertNotEqual(obj1, tag2)
1738 @given(data_strategy())
1739 def test_call(self, d):
1740 for klass in (Null, NullInherited):
1746 ) = d.draw(null_values_strategy())
1747 obj_initial = klass(
1750 optional=optional_initial or False,
1751 _decoded=_decoded_initial,
1758 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
1759 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1760 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1761 self.assertEqual(obj.expl_tag, expl or expl_initial)
1762 optional = optional_initial if optional is None else optional
1763 optional = False if optional is None else optional
1764 self.assertEqual(obj.optional, optional)
1766 @given(null_values_strategy())
1767 def test_copy(self, values):
1768 for klass in (Null, NullInherited):
1769 impl, expl, optional, _decoded = values
1773 optional=optional or False,
1776 obj_copied = obj.copy()
1777 self.assert_copied_basic_fields(obj, obj_copied)
1779 @given(integers(min_value=1).map(tag_encode))
1780 def test_stripped(self, tag_impl):
1781 obj = Null(impl=tag_impl)
1782 with self.assertRaises(NotEnoughData):
1783 obj.decode(obj.encode()[:-1])
1785 @given(integers(min_value=1).map(tag_ctxc))
1786 def test_stripped_expl(self, tag_expl):
1787 obj = Null(expl=tag_expl)
1788 with self.assertRaises(NotEnoughData):
1789 obj.decode(obj.encode()[:-1])
1792 integers(min_value=31),
1793 integers(min_value=0),
1796 def test_bad_tag(self, tag, offset, decode_path):
1797 decode_path = tuple(str(i) for i in decode_path)
1798 with self.assertRaises(DecodeError) as err:
1800 tag_encode(tag)[:-1],
1802 decode_path=decode_path,
1805 self.assertEqual(err.exception.offset, offset)
1806 self.assertEqual(err.exception.decode_path, decode_path)
1809 integers(min_value=128),
1810 integers(min_value=0),
1813 def test_bad_len(self, l, offset, decode_path):
1814 decode_path = tuple(str(i) for i in decode_path)
1815 with self.assertRaises(DecodeError) as err:
1817 Null.tag_default + len_encode(l)[:-1],
1819 decode_path=decode_path,
1822 self.assertEqual(err.exception.offset, offset)
1823 self.assertEqual(err.exception.decode_path, decode_path)
1825 @given(binary(min_size=1))
1826 def test_tag_mismatch(self, impl):
1827 assume(impl != Null.tag_default)
1828 with self.assertRaises(TagMismatch):
1829 Null(impl=impl).decode(Null().encode())
1832 null_values_strategy(),
1833 integers(min_value=1).map(tag_ctxc),
1834 integers(min_value=0),
1837 def test_symmetric(self, values, tag_expl, offset, tail_junk):
1838 for klass in (Null, NullInherited):
1839 _, _, optional, _decoded = values
1840 obj = klass(optional=optional, _decoded=_decoded)
1843 self.assertFalse(obj.expled)
1844 obj_encoded = obj.encode()
1845 obj_expled = obj(expl=tag_expl)
1846 self.assertTrue(obj_expled.expled)
1849 obj_expled_encoded = obj_expled.encode()
1850 obj_decoded, tail = obj_expled.decode(
1851 obj_expled_encoded + tail_junk,
1856 self.assertEqual(tail, tail_junk)
1857 self.assertEqual(obj_decoded, obj_expled)
1858 self.assertNotEqual(obj_decoded, obj)
1859 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1860 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1861 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1863 obj_decoded.expl_llen,
1864 len(len_encode(len(obj_encoded))),
1866 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1867 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1870 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1872 self.assertEqual(obj_decoded.expl_offset, offset)
1874 @given(integers(min_value=1))
1875 def test_invalid_len(self, l):
1876 with self.assertRaises(InvalidLength):
1877 Null().decode(b"".join((
1884 def oid_strategy(draw):
1885 first_arc = draw(integers(min_value=0, max_value=2))
1887 if first_arc in (0, 1):
1888 second_arc = draw(integers(min_value=0, max_value=39))
1890 second_arc = draw(integers(min_value=0))
1891 other_arcs = draw(lists(integers(min_value=0)))
1892 return tuple([first_arc, second_arc] + other_arcs)
1896 def oid_values_strategy(draw, do_expl=False):
1897 value = draw(one_of(none(), oid_strategy()))
1901 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1903 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1904 default = draw(one_of(none(), oid_strategy()))
1905 optional = draw(one_of(none(), booleans()))
1907 draw(integers(min_value=0)),
1908 draw(integers(min_value=0)),
1909 draw(integers(min_value=0)),
1911 return (value, impl, expl, default, optional, _decoded)
1914 class ObjectIdentifierInherited(ObjectIdentifier):
1918 class TestObjectIdentifier(CommonMixin, TestCase):
1919 base_klass = ObjectIdentifier
1921 def test_invalid_value_type(self):
1922 with self.assertRaises(InvalidValueType) as err:
1923 ObjectIdentifier(123)
1927 def test_optional(self, optional):
1928 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
1929 self.assertTrue(obj.optional)
1931 @given(oid_strategy())
1932 def test_ready(self, value):
1933 obj = ObjectIdentifier()
1934 self.assertFalse(obj.ready)
1937 with self.assertRaises(ObjNotReady) as err:
1940 obj = ObjectIdentifier(value)
1941 self.assertTrue(obj.ready)
1946 @given(oid_strategy(), oid_strategy(), binary(), binary())
1947 def test_comparison(self, value1, value2, tag1, tag2):
1948 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1949 obj1 = klass(value1)
1950 obj2 = klass(value2)
1951 self.assertEqual(obj1 == obj2, value1 == value2)
1952 self.assertEqual(obj1 != obj2, value1 != value2)
1953 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
1954 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
1955 obj1 = klass(value1, impl=tag1)
1956 obj2 = klass(value1, impl=tag2)
1957 self.assertEqual(obj1 == obj2, tag1 == tag2)
1958 self.assertEqual(obj1 != obj2, tag1 != tag2)
1960 @given(lists(oid_strategy()))
1961 def test_sorted_works(self, values):
1962 self.assertSequenceEqual(
1963 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
1967 @given(data_strategy())
1968 def test_call(self, d):
1969 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1977 ) = d.draw(oid_values_strategy())
1978 obj_initial = klass(
1979 value=value_initial,
1982 default=default_initial,
1983 optional=optional_initial or False,
1984 _decoded=_decoded_initial,
1993 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2002 value_expected = default if value is None else value
2004 default_initial if value_expected is None
2007 self.assertEqual(obj, value_expected)
2008 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2009 self.assertEqual(obj.expl_tag, expl or expl_initial)
2012 default_initial if default is None else default,
2014 if obj.default is None:
2015 optional = optional_initial if optional is None else optional
2016 optional = False if optional is None else optional
2019 self.assertEqual(obj.optional, optional)
2021 @given(oid_values_strategy())
2022 def test_copy(self, values):
2023 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2040 obj_copied = obj.copy()
2041 self.assert_copied_basic_fields(obj, obj_copied)
2042 self.assertEqual(obj._value, obj_copied._value)
2044 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2047 integers(min_value=1).map(tag_encode),
2049 def test_stripped(self, value, tag_impl):
2050 obj = ObjectIdentifier(value, impl=tag_impl)
2051 with self.assertRaises(NotEnoughData):
2052 obj.decode(obj.encode()[:-1])
2056 integers(min_value=1).map(tag_ctxc),
2058 def test_stripped_expl(self, value, tag_expl):
2059 obj = ObjectIdentifier(value, expl=tag_expl)
2060 with self.assertRaises(NotEnoughData):
2061 obj.decode(obj.encode()[:-1])
2064 integers(min_value=31),
2065 integers(min_value=0),
2068 def test_bad_tag(self, tag, offset, decode_path):
2069 decode_path = tuple(str(i) for i in decode_path)
2070 with self.assertRaises(DecodeError) as err:
2071 ObjectIdentifier().decode(
2072 tag_encode(tag)[:-1],
2074 decode_path=decode_path,
2077 self.assertEqual(err.exception.offset, offset)
2078 self.assertEqual(err.exception.decode_path, decode_path)
2081 integers(min_value=128),
2082 integers(min_value=0),
2085 def test_bad_len(self, l, offset, decode_path):
2086 decode_path = tuple(str(i) for i in decode_path)
2087 with self.assertRaises(DecodeError) as err:
2088 ObjectIdentifier().decode(
2089 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2091 decode_path=decode_path,
2094 self.assertEqual(err.exception.offset, offset)
2095 self.assertEqual(err.exception.decode_path, decode_path)
2097 def test_zero_oid(self):
2098 with self.assertRaises(NotEnoughData):
2099 ObjectIdentifier().decode(
2100 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2103 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2104 @given(oid_strategy())
2105 def test_unfinished_oid(self, value):
2106 assume(list(value)[-1] > 255)
2107 obj_encoded = ObjectIdentifier(value).encode()
2108 obj, _ = ObjectIdentifier().decode(obj_encoded)
2109 data = obj_encoded[obj.tlen + obj.llen:-1]
2111 ObjectIdentifier.tag_default,
2112 len_encode(len(data)),
2115 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2118 @given(integers(min_value=0))
2119 def test_invalid_short(self, value):
2120 with self.assertRaises(InvalidOID):
2121 ObjectIdentifier((value,))
2122 with self.assertRaises(InvalidOID):
2123 ObjectIdentifier("%d" % value)
2125 @given(integers(min_value=3), integers(min_value=0))
2126 def test_invalid_first_arc(self, first_arc, second_arc):
2127 with self.assertRaises(InvalidOID):
2128 ObjectIdentifier((first_arc, second_arc))
2129 with self.assertRaises(InvalidOID):
2130 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2132 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2133 def test_invalid_second_arc(self, first_arc, second_arc):
2134 with self.assertRaises(InvalidOID):
2135 ObjectIdentifier((first_arc, second_arc))
2136 with self.assertRaises(InvalidOID):
2137 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2139 @given(text(alphabet=ascii_letters + ".", min_size=1))
2140 def test_junk(self, oid):
2141 with self.assertRaises(InvalidOID):
2142 ObjectIdentifier(oid)
2144 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2145 @given(oid_strategy())
2146 def test_validness(self, oid):
2147 obj = ObjectIdentifier(oid)
2148 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2153 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2155 oid_values_strategy(),
2157 integers(min_value=1).map(tag_ctxc),
2158 integers(min_value=0),
2161 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2162 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2163 _, _, _, default, optional, _decoded = values
2172 self.assertFalse(obj.expled)
2173 obj_encoded = obj.encode()
2174 obj_expled = obj(value, expl=tag_expl)
2175 self.assertTrue(obj_expled.expled)
2178 obj_expled_encoded = obj_expled.encode()
2179 obj_decoded, tail = obj_expled.decode(
2180 obj_expled_encoded + tail_junk,
2185 self.assertEqual(tail, tail_junk)
2186 self.assertEqual(obj_decoded, obj_expled)
2187 self.assertNotEqual(obj_decoded, obj)
2188 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2189 self.assertEqual(tuple(obj_decoded), tuple(obj))
2190 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2191 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2192 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2194 obj_decoded.expl_llen,
2195 len(len_encode(len(obj_encoded))),
2197 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2198 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2201 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2203 self.assertEqual(obj_decoded.expl_offset, offset)
2206 oid_strategy().map(ObjectIdentifier),
2207 oid_strategy().map(ObjectIdentifier),
2209 def test_add(self, oid1, oid2):
2210 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2211 for oid_to_add in (oid2, tuple(oid2)):
2212 self.assertEqual(oid1 + oid_to_add, oid_expect)
2213 with self.assertRaises(InvalidValueType):
2216 def test_go_vectors_valid(self):
2217 for data, expect in (
2219 (b"\x55\x02", (2, 5, 2)),
2220 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2221 (b"\x81\x34\x03", (2, 100, 3)),
2224 ObjectIdentifier().decode(b"".join((
2225 ObjectIdentifier.tag_default,
2226 len_encode(len(data)),
2232 def test_go_vectors_invalid(self):
2233 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2234 with self.assertRaises(DecodeError):
2235 ObjectIdentifier().decode(b"".join((
2236 Integer.tag_default,
2237 len_encode(len(data)),
2243 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2245 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2246 values = list(draw(sets(
2248 min_size=len(schema),
2249 max_size=len(schema),
2251 schema = list(zip(schema, values))
2252 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2256 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2258 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2259 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2260 optional = draw(one_of(none(), booleans()))
2262 draw(integers(min_value=0)),
2263 draw(integers(min_value=0)),
2264 draw(integers(min_value=0)),
2266 return (schema, value, impl, expl, default, optional, _decoded)
2269 class TestEnumerated(CommonMixin, TestCase):
2270 class EWhatever(Enumerated):
2271 schema = (("whatever", 0),)
2273 base_klass = EWhatever
2275 def test_schema_required(self):
2276 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2279 def test_invalid_value_type(self):
2280 with self.assertRaises(InvalidValueType) as err:
2281 self.base_klass((1, 2))
2284 @given(sets(text_letters(), min_size=2))
2285 def test_unknown_name(self, schema_input):
2286 missing = schema_input.pop()
2288 class E(Enumerated):
2289 schema = [(n, 123) for n in schema_input]
2290 with self.assertRaises(ObjUnknown) as err:
2295 sets(text_letters(), min_size=2),
2296 sets(integers(), min_size=2),
2298 def test_unknown_value(self, schema_input, values_input):
2300 missing_value = values_input.pop()
2301 _input = list(zip(schema_input, values_input))
2303 class E(Enumerated):
2305 with self.assertRaises(DecodeError) as err:
2310 def test_optional(self, optional):
2311 obj = self.base_klass(default="whatever", optional=optional)
2312 self.assertTrue(obj.optional)
2314 def test_ready(self):
2315 obj = self.base_klass()
2316 self.assertFalse(obj.ready)
2319 with self.assertRaises(ObjNotReady) as err:
2322 obj = self.base_klass("whatever")
2323 self.assertTrue(obj.ready)
2327 @given(integers(), integers(), binary(), binary())
2328 def test_comparison(self, value1, value2, tag1, tag2):
2329 class E(Enumerated):
2331 ("whatever0", value1),
2332 ("whatever1", value2),
2335 class EInherited(E):
2337 for klass in (E, EInherited):
2338 obj1 = klass(value1)
2339 obj2 = klass(value2)
2340 self.assertEqual(obj1 == obj2, value1 == value2)
2341 self.assertEqual(obj1 != obj2, value1 != value2)
2342 self.assertEqual(obj1 == int(obj2), value1 == value2)
2343 obj1 = klass(value1, impl=tag1)
2344 obj2 = klass(value1, impl=tag2)
2345 self.assertEqual(obj1 == obj2, tag1 == tag2)
2346 self.assertEqual(obj1 != obj2, tag1 != tag2)
2348 @given(data_strategy())
2349 def test_call(self, d):
2358 ) = d.draw(enumerated_values_strategy())
2360 class E(Enumerated):
2361 schema = schema_initial
2363 value=value_initial,
2366 default=default_initial,
2367 optional=optional_initial or False,
2368 _decoded=_decoded_initial,
2378 ) = d.draw(enumerated_values_strategy(
2379 schema=schema_initial,
2380 do_expl=impl_initial is None,
2390 value_expected = default if value is None else value
2392 default_initial if value_expected is None
2397 dict(schema_initial).get(value_expected, value_expected),
2399 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2400 self.assertEqual(obj.expl_tag, expl or expl_initial)
2403 default_initial if default is None else default,
2405 if obj.default is None:
2406 optional = optional_initial if optional is None else optional
2407 optional = False if optional is None else optional
2410 self.assertEqual(obj.optional, optional)
2411 self.assertEqual(obj.specs, dict(schema_initial))
2413 @given(enumerated_values_strategy())
2414 def test_copy(self, values):
2415 schema_input, value, impl, expl, default, optional, _decoded = values
2417 class E(Enumerated):
2418 schema = schema_input
2427 obj_copied = obj.copy()
2428 self.assert_copied_basic_fields(obj, obj_copied)
2429 self.assertEqual(obj.specs, obj_copied.specs)
2431 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2432 @given(data_strategy())
2433 def test_symmetric(self, d):
2434 schema_input, _, _, _, default, optional, _decoded = d.draw(
2435 enumerated_values_strategy(),
2437 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2438 offset = d.draw(integers(min_value=0))
2439 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2440 tail_junk = d.draw(binary(max_size=5))
2442 class E(Enumerated):
2443 schema = schema_input
2452 self.assertFalse(obj.expled)
2453 obj_encoded = obj.encode()
2454 obj_expled = obj(value, expl=tag_expl)
2455 self.assertTrue(obj_expled.expled)
2458 obj_expled_encoded = obj_expled.encode()
2459 obj_decoded, tail = obj_expled.decode(
2460 obj_expled_encoded + tail_junk,
2465 self.assertEqual(tail, tail_junk)
2466 self.assertEqual(obj_decoded, obj_expled)
2467 self.assertNotEqual(obj_decoded, obj)
2468 self.assertEqual(int(obj_decoded), int(obj_expled))
2469 self.assertEqual(int(obj_decoded), int(obj))
2470 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2471 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2472 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2474 obj_decoded.expl_llen,
2475 len(len_encode(len(obj_encoded))),
2477 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2478 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2481 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2483 self.assertEqual(obj_decoded.expl_offset, offset)
2487 def string_values_strategy(draw, alphabet, do_expl=False):
2488 bound_min, bound_max = sorted(draw(sets(
2489 integers(min_value=0, max_value=1 << 7),
2493 value = draw(one_of(
2495 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2497 default = draw(one_of(
2499 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2502 if draw(booleans()):
2503 bounds = (bound_min, bound_max)
2507 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2509 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2510 optional = draw(one_of(none(), booleans()))
2512 draw(integers(min_value=0)),
2513 draw(integers(min_value=0)),
2514 draw(integers(min_value=0)),
2516 return (value, bounds, impl, expl, default, optional, _decoded)
2519 class StringMixin(object):
2520 def test_invalid_value_type(self):
2521 with self.assertRaises(InvalidValueType) as err:
2522 self.base_klass((1, 2))
2525 def text_alphabet(self):
2526 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2527 return printable + whitespace
2531 def test_optional(self, optional):
2532 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2533 self.assertTrue(obj.optional)
2535 @given(data_strategy())
2536 def test_ready(self, d):
2537 obj = self.base_klass()
2538 self.assertFalse(obj.ready)
2542 with self.assertRaises(ObjNotReady) as err:
2545 value = d.draw(text(alphabet=self.text_alphabet()))
2546 obj = self.base_klass(value)
2547 self.assertTrue(obj.ready)
2552 @given(data_strategy())
2553 def test_comparison(self, d):
2554 value1 = d.draw(text(alphabet=self.text_alphabet()))
2555 value2 = d.draw(text(alphabet=self.text_alphabet()))
2556 tag1 = d.draw(binary())
2557 tag2 = d.draw(binary())
2558 obj1 = self.base_klass(value1)
2559 obj2 = self.base_klass(value2)
2560 self.assertEqual(obj1 == obj2, value1 == value2)
2561 self.assertEqual(obj1 != obj2, value1 != value2)
2562 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2563 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2564 obj1 = self.base_klass(value1, impl=tag1)
2565 obj2 = self.base_klass(value1, impl=tag2)
2566 self.assertEqual(obj1 == obj2, tag1 == tag2)
2567 self.assertEqual(obj1 != obj2, tag1 != tag2)
2569 @given(data_strategy())
2570 def test_bounds_satisfied(self, d):
2571 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2572 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2573 value = d.draw(text(
2574 alphabet=self.text_alphabet(),
2578 self.base_klass(value=value, bounds=(bound_min, bound_max))
2580 @given(data_strategy())
2581 def test_bounds_unsatisfied(self, d):
2582 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2583 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2584 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2585 with self.assertRaises(BoundsError) as err:
2586 self.base_klass(value=value, bounds=(bound_min, bound_max))
2588 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2589 with self.assertRaises(BoundsError) as err:
2590 self.base_klass(value=value, bounds=(bound_min, bound_max))
2593 @given(data_strategy())
2594 def test_call(self, d):
2603 ) = d.draw(string_values_strategy(self.text_alphabet()))
2604 obj_initial = self.base_klass(
2610 optional_initial or False,
2621 ) = d.draw(string_values_strategy(
2622 self.text_alphabet(),
2623 do_expl=impl_initial is None,
2625 if (default is None) and (obj_initial.default is not None):
2628 (bounds is None) and
2629 (value is not None) and
2630 (bounds_initial is not None) and
2631 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2635 (bounds is None) and
2636 (default is not None) and
2637 (bounds_initial is not None) and
2638 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2641 obj = obj_initial(value, bounds, impl, expl, default, optional)
2643 value_expected = default if value is None else value
2645 default_initial if value_expected is None
2648 self.assertEqual(obj, value_expected)
2649 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2650 self.assertEqual(obj.expl_tag, expl or expl_initial)
2653 default_initial if default is None else default,
2655 if obj.default is None:
2656 optional = optional_initial if optional is None else optional
2657 optional = False if optional is None else optional
2660 self.assertEqual(obj.optional, optional)
2662 (obj._bound_min, obj._bound_max),
2663 bounds or bounds_initial or (0, float("+inf")),
2666 @given(data_strategy())
2667 def test_copy(self, d):
2668 values = d.draw(string_values_strategy(self.text_alphabet()))
2669 obj = self.base_klass(*values)
2670 obj_copied = obj.copy()
2671 self.assert_copied_basic_fields(obj, obj_copied)
2672 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2673 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2674 self.assertEqual(obj._value, obj_copied._value)
2676 @given(data_strategy())
2677 def test_stripped(self, d):
2678 value = d.draw(text(alphabet=self.text_alphabet()))
2679 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2680 obj = self.base_klass(value, impl=tag_impl)
2681 with self.assertRaises(NotEnoughData):
2682 obj.decode(obj.encode()[:-1])
2684 @given(data_strategy())
2685 def test_stripped_expl(self, d):
2686 value = d.draw(text(alphabet=self.text_alphabet()))
2687 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2688 obj = self.base_klass(value, expl=tag_expl)
2689 with self.assertRaises(NotEnoughData):
2690 obj.decode(obj.encode()[:-1])
2693 integers(min_value=31),
2694 integers(min_value=0),
2697 def test_bad_tag(self, tag, offset, decode_path):
2698 decode_path = tuple(str(i) for i in decode_path)
2699 with self.assertRaises(DecodeError) as err:
2700 self.base_klass().decode(
2701 tag_encode(tag)[:-1],
2703 decode_path=decode_path,
2706 self.assertEqual(err.exception.offset, offset)
2707 self.assertEqual(err.exception.decode_path, decode_path)
2710 integers(min_value=128),
2711 integers(min_value=0),
2714 def test_bad_len(self, l, offset, decode_path):
2715 decode_path = tuple(str(i) for i in decode_path)
2716 with self.assertRaises(DecodeError) as err:
2717 self.base_klass().decode(
2718 self.base_klass.tag_default + len_encode(l)[:-1],
2720 decode_path=decode_path,
2723 self.assertEqual(err.exception.offset, offset)
2724 self.assertEqual(err.exception.decode_path, decode_path)
2727 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2728 integers(min_value=0),
2731 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2732 decode_path = tuple(str(i) for i in decode_path)
2733 value, bound_min = list(sorted(ints))
2735 class String(self.base_klass):
2736 # Multiply this value by four, to satisfy UTF-32 bounds
2737 # (4 bytes per character) validation
2738 bounds = (bound_min * 4, bound_min * 4)
2739 with self.assertRaises(DecodeError) as err:
2741 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2743 decode_path=decode_path,
2746 self.assertEqual(err.exception.offset, offset)
2747 self.assertEqual(err.exception.decode_path, decode_path)
2749 @given(data_strategy())
2750 def test_symmetric(self, d):
2751 values = d.draw(string_values_strategy(self.text_alphabet()))
2752 value = d.draw(text(alphabet=self.text_alphabet()))
2753 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2754 offset = d.draw(integers(min_value=0))
2755 tail_junk = d.draw(binary(max_size=5))
2756 _, _, _, _, default, optional, _decoded = values
2757 obj = self.base_klass(
2765 self.assertFalse(obj.expled)
2766 obj_encoded = obj.encode()
2767 obj_expled = obj(value, expl=tag_expl)
2768 self.assertTrue(obj_expled.expled)
2771 obj_expled_encoded = obj_expled.encode()
2772 obj_decoded, tail = obj_expled.decode(
2773 obj_expled_encoded + tail_junk,
2778 self.assertEqual(tail, tail_junk)
2779 self.assertEqual(obj_decoded, obj_expled)
2780 self.assertNotEqual(obj_decoded, obj)
2781 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2782 self.assertEqual(bytes(obj_decoded), bytes(obj))
2783 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2784 self.assertEqual(text_type(obj_decoded), text_type(obj))
2785 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2786 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2787 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2789 obj_decoded.expl_llen,
2790 len(len_encode(len(obj_encoded))),
2792 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2793 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2796 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2798 self.assertEqual(obj_decoded.expl_offset, offset)
2801 class TestUTF8String(StringMixin, CommonMixin, TestCase):
2802 base_klass = UTF8String
2805 class TestNumericString(StringMixin, CommonMixin, TestCase):
2806 base_klass = NumericString
2809 class TestPrintableString(StringMixin, CommonMixin, TestCase):
2810 base_klass = PrintableString
2813 class TestTeletexString(StringMixin, CommonMixin, TestCase):
2814 base_klass = TeletexString
2817 class TestVideotexString(StringMixin, CommonMixin, TestCase):
2818 base_klass = VideotexString
2821 class TestIA5String(StringMixin, CommonMixin, TestCase):
2822 base_klass = IA5String
2825 class TestGraphicString(StringMixin, CommonMixin, TestCase):
2826 base_klass = GraphicString
2829 class TestVisibleString(StringMixin, CommonMixin, TestCase):
2830 base_klass = VisibleString
2833 class TestGeneralString(StringMixin, CommonMixin, TestCase):
2834 base_klass = GeneralString
2837 class TestUniversalString(StringMixin, CommonMixin, TestCase):
2838 base_klass = UniversalString
2841 class TestBMPString(StringMixin, CommonMixin, TestCase):
2842 base_klass = BMPString
2846 def generalized_time_values_strategy(
2854 if draw(booleans()):
2855 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2857 value = value.replace(microsecond=0)
2859 if draw(booleans()):
2860 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2862 default = default.replace(microsecond=0)
2866 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2868 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2869 optional = draw(one_of(none(), booleans()))
2871 draw(integers(min_value=0)),
2872 draw(integers(min_value=0)),
2873 draw(integers(min_value=0)),
2875 return (value, impl, expl, default, optional, _decoded)
2878 class TimeMixin(object):
2879 def test_invalid_value_type(self):
2880 with self.assertRaises(InvalidValueType) as err:
2881 self.base_klass(datetime.now().timetuple())
2884 @given(data_strategy())
2885 def test_optional(self, d):
2886 default = d.draw(datetimes(
2887 min_value=self.min_datetime,
2888 max_value=self.max_datetime,
2890 optional = d.draw(booleans())
2891 obj = self.base_klass(default=default, optional=optional)
2892 self.assertTrue(obj.optional)
2894 @given(data_strategy())
2895 def test_ready(self, d):
2896 obj = self.base_klass()
2897 self.assertFalse(obj.ready)
2900 with self.assertRaises(ObjNotReady) as err:
2903 value = d.draw(datetimes(min_value=self.min_datetime))
2904 obj = self.base_klass(value)
2905 self.assertTrue(obj.ready)
2909 @given(data_strategy())
2910 def test_comparison(self, d):
2911 value1 = d.draw(datetimes(
2912 min_value=self.min_datetime,
2913 max_value=self.max_datetime,
2915 value2 = d.draw(datetimes(
2916 min_value=self.min_datetime,
2917 max_value=self.max_datetime,
2919 tag1 = d.draw(binary())
2920 tag2 = d.draw(binary())
2922 value1 = value1.replace(microsecond=0)
2923 value2 = value2.replace(microsecond=0)
2924 obj1 = self.base_klass(value1)
2925 obj2 = self.base_klass(value2)
2926 self.assertEqual(obj1 == obj2, value1 == value2)
2927 self.assertEqual(obj1 != obj2, value1 != value2)
2928 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
2929 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2930 obj1 = self.base_klass(value1, impl=tag1)
2931 obj2 = self.base_klass(value1, impl=tag2)
2932 self.assertEqual(obj1 == obj2, tag1 == tag2)
2933 self.assertEqual(obj1 != obj2, tag1 != tag2)
2935 @given(data_strategy())
2936 def test_call(self, d):
2944 ) = d.draw(generalized_time_values_strategy(
2945 min_datetime=self.min_datetime,
2946 max_datetime=self.max_datetime,
2947 omit_ms=self.omit_ms,
2949 obj_initial = self.base_klass(
2950 value=value_initial,
2953 default=default_initial,
2954 optional=optional_initial or False,
2955 _decoded=_decoded_initial,
2964 ) = d.draw(generalized_time_values_strategy(
2965 min_datetime=self.min_datetime,
2966 max_datetime=self.max_datetime,
2967 omit_ms=self.omit_ms,
2968 do_expl=impl_initial is None,
2978 value_expected = default if value is None else value
2980 default_initial if value_expected is None
2983 self.assertEqual(obj, value_expected)
2984 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2985 self.assertEqual(obj.expl_tag, expl or expl_initial)
2988 default_initial if default is None else default,
2990 if obj.default is None:
2991 optional = optional_initial if optional is None else optional
2992 optional = False if optional is None else optional
2995 self.assertEqual(obj.optional, optional)
2997 @given(data_strategy())
2998 def test_copy(self, d):
2999 values = d.draw(generalized_time_values_strategy(
3000 min_datetime=self.min_datetime,
3001 max_datetime=self.max_datetime,
3003 obj = self.base_klass(*values)
3004 obj_copied = obj.copy()
3005 self.assert_copied_basic_fields(obj, obj_copied)
3006 self.assertEqual(obj._value, obj_copied._value)
3008 @given(data_strategy())
3009 def test_stripped(self, d):
3010 value = d.draw(datetimes(
3011 min_value=self.min_datetime,
3012 max_value=self.max_datetime,
3014 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3015 obj = self.base_klass(value, impl=tag_impl)
3016 with self.assertRaises(NotEnoughData):
3017 obj.decode(obj.encode()[:-1])
3019 @given(data_strategy())
3020 def test_stripped_expl(self, d):
3021 value = d.draw(datetimes(
3022 min_value=self.min_datetime,
3023 max_value=self.max_datetime,
3025 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3026 obj = self.base_klass(value, expl=tag_expl)
3027 with self.assertRaises(NotEnoughData):
3028 obj.decode(obj.encode()[:-1])
3030 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3031 @given(data_strategy())
3032 def test_symmetric(self, d):
3033 values = d.draw(generalized_time_values_strategy(
3034 min_datetime=self.min_datetime,
3035 max_datetime=self.max_datetime,
3037 value = d.draw(datetimes(
3038 min_value=self.min_datetime,
3039 max_value=self.max_datetime,
3041 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3042 offset = d.draw(integers(min_value=0))
3043 tail_junk = d.draw(binary(max_size=5))
3044 _, _, _, default, optional, _decoded = values
3045 obj = self.base_klass(
3053 self.assertFalse(obj.expled)
3054 obj_encoded = obj.encode()
3055 obj_expled = obj(value, expl=tag_expl)
3056 self.assertTrue(obj_expled.expled)
3059 obj_expled_encoded = obj_expled.encode()
3060 obj_decoded, tail = obj_expled.decode(
3061 obj_expled_encoded + tail_junk,
3066 self.assertEqual(tail, tail_junk)
3067 self.assertEqual(obj_decoded, obj_expled)
3068 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3069 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3070 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3071 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3072 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3074 obj_decoded.expl_llen,
3075 len(len_encode(len(obj_encoded))),
3077 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3078 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3081 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3083 self.assertEqual(obj_decoded.expl_offset, offset)
3086 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3087 base_klass = GeneralizedTime
3089 min_datetime = datetime(1900, 1, 1)
3090 max_datetime = datetime(9999, 12, 31)
3092 def test_go_vectors_invalid(self):
3104 b"-20100102030410Z",
3105 b"2010-0102030410Z",
3106 b"2010-0002030410Z",
3107 b"201001-02030410Z",
3108 b"20100102-030410Z",
3109 b"2010010203-0410Z",
3110 b"201001020304-10Z",
3111 # These ones are INVALID in *DER*, but accepted
3112 # by Go's encoding/asn1
3113 b"20100102030405+0607",
3114 b"20100102030405-0607",
3116 with self.assertRaises(DecodeError) as err:
3117 GeneralizedTime(data)
3120 def test_go_vectors_valid(self):
3122 GeneralizedTime(b"20100102030405Z").todatetime(),
3123 datetime(2010, 1, 2, 3, 4, 5, 0),
3127 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3128 base_klass = UTCTime
3130 min_datetime = datetime(2000, 1, 1)
3131 max_datetime = datetime(2049, 12, 31)
3133 def test_go_vectors_invalid(self):
3159 # These ones are INVALID in *DER*, but accepted
3160 # by Go's encoding/asn1
3161 b"910506164540-0700",
3162 b"910506164540+0730",
3166 with self.assertRaises(DecodeError) as err:
3170 def test_go_vectors_valid(self):
3172 UTCTime(b"910506234540Z").todatetime(),
3173 datetime(1991, 5, 6, 23, 45, 40, 0),
3176 @given(integers(min_value=0, max_value=49))
3177 def test_pre50(self, year):
3179 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3183 @given(integers(min_value=50, max_value=99))
3184 def test_post50(self, year):
3186 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3192 def any_values_strategy(draw, do_expl=False):
3193 value = draw(one_of(none(), binary()))
3196 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3197 optional = draw(one_of(none(), booleans()))
3199 draw(integers(min_value=0)),
3200 draw(integers(min_value=0)),
3201 draw(integers(min_value=0)),
3203 return (value, expl, optional, _decoded)
3206 class AnyInherited(Any):
3210 class TestAny(CommonMixin, TestCase):
3213 def test_invalid_value_type(self):
3214 with self.assertRaises(InvalidValueType) as err:
3219 def test_optional(self, optional):
3220 obj = Any(optional=optional)
3221 self.assertEqual(obj.optional, optional)
3224 def test_ready(self, value):
3226 self.assertFalse(obj.ready)
3229 with self.assertRaises(ObjNotReady) as err:
3233 self.assertTrue(obj.ready)
3238 def test_basic(self, value):
3239 integer_encoded = Integer(value).encode()
3241 Any(integer_encoded),
3242 Any(Integer(value)),
3243 Any(Any(Integer(value))),
3245 self.assertSequenceEqual(bytes(obj), integer_encoded)
3247 obj.decode(obj.encode())[0].vlen,
3248 len(integer_encoded),
3252 self.assertSequenceEqual(obj.encode(), integer_encoded)
3254 @given(binary(), binary())
3255 def test_comparison(self, value1, value2):
3256 for klass in (Any, AnyInherited):
3257 obj1 = klass(value1)
3258 obj2 = klass(value2)
3259 self.assertEqual(obj1 == obj2, value1 == value2)
3260 self.assertEqual(obj1 != obj2, value1 != value2)
3261 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3263 @given(data_strategy())
3264 def test_call(self, d):
3265 for klass in (Any, AnyInherited):
3271 ) = d.draw(any_values_strategy())
3272 obj_initial = klass(
3275 optional_initial or False,
3283 ) = d.draw(any_values_strategy(do_expl=True))
3284 obj = obj_initial(value, expl, optional)
3286 value_expected = None if value is None else value
3287 self.assertEqual(obj, value_expected)
3288 self.assertEqual(obj.expl_tag, expl or expl_initial)
3289 if obj.default is None:
3290 optional = optional_initial if optional is None else optional
3291 optional = False if optional is None else optional
3292 self.assertEqual(obj.optional, optional)
3294 def test_simultaneous_impl_expl(self):
3295 # override it, as Any does not have implicit tag
3298 def test_decoded(self):
3299 # override it, as Any does not have implicit tag
3302 @given(any_values_strategy())
3303 def test_copy(self, values):
3304 for klass in (Any, AnyInherited):
3305 obj = klass(*values)
3306 obj_copied = obj.copy()
3307 self.assert_copied_basic_fields(obj, obj_copied)
3308 self.assertEqual(obj._value, obj_copied._value)
3310 @given(binary().map(OctetString))
3311 def test_stripped(self, value):
3313 with self.assertRaises(NotEnoughData):
3314 obj.decode(obj.encode()[:-1])
3318 integers(min_value=1).map(tag_ctxc),
3320 def test_stripped_expl(self, value, tag_expl):
3321 obj = Any(value, expl=tag_expl)
3322 with self.assertRaises(NotEnoughData):
3323 obj.decode(obj.encode()[:-1])
3326 integers(min_value=31),
3327 integers(min_value=0),
3330 def test_bad_tag(self, tag, offset, decode_path):
3331 decode_path = tuple(str(i) for i in decode_path)
3332 with self.assertRaises(DecodeError) as err:
3334 tag_encode(tag)[:-1],
3336 decode_path=decode_path,
3339 self.assertEqual(err.exception.offset, offset)
3340 self.assertEqual(err.exception.decode_path, decode_path)
3343 integers(min_value=128),
3344 integers(min_value=0),
3347 def test_bad_len(self, l, offset, decode_path):
3348 decode_path = tuple(str(i) for i in decode_path)
3349 with self.assertRaises(DecodeError) as err:
3351 Any.tag_default + len_encode(l)[:-1],
3353 decode_path=decode_path,
3356 self.assertEqual(err.exception.offset, offset)
3357 self.assertEqual(err.exception.decode_path, decode_path)
3359 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3361 any_values_strategy(),
3362 integers().map(lambda x: Integer(x).encode()),
3363 integers(min_value=1).map(tag_ctxc),
3364 integers(min_value=0),
3367 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3368 for klass in (Any, AnyInherited):
3369 _, _, optional, _decoded = values
3370 obj = klass(value=value, optional=optional, _decoded=_decoded)
3373 self.assertFalse(obj.expled)
3374 obj_encoded = obj.encode()
3375 obj_expled = obj(value, expl=tag_expl)
3376 self.assertTrue(obj_expled.expled)
3379 obj_expled_encoded = obj_expled.encode()
3380 obj_decoded, tail = obj_expled.decode(
3381 obj_expled_encoded + tail_junk,
3386 self.assertEqual(tail, tail_junk)
3387 self.assertEqual(obj_decoded, obj_expled)
3388 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3389 self.assertEqual(bytes(obj_decoded), bytes(obj))
3390 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3391 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3392 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3394 obj_decoded.expl_llen,
3395 len(len_encode(len(obj_encoded))),
3397 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3398 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3401 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3403 self.assertEqual(obj_decoded.expl_offset, offset)
3404 self.assertEqual(obj_decoded.tlen, 0)
3405 self.assertEqual(obj_decoded.llen, 0)
3406 self.assertEqual(obj_decoded.vlen, len(value))
3410 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3412 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3413 tags = [tag_encode(tag) for tag in draw(sets(
3414 integers(min_value=0),
3415 min_size=len(names),
3416 max_size=len(names),
3418 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3420 if value_required or draw(booleans()):
3421 value = draw(tuples(
3422 sampled_from([name for name, _ in schema]),
3423 integers().map(Integer),
3427 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3428 default = draw(one_of(
3430 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3432 optional = draw(one_of(none(), booleans()))
3434 draw(integers(min_value=0)),
3435 draw(integers(min_value=0)),
3436 draw(integers(min_value=0)),
3438 return (schema, value, expl, default, optional, _decoded)
3441 class ChoiceInherited(Choice):
3445 class TestChoice(CommonMixin, TestCase):
3447 schema = (("whatever", Boolean()),)
3450 def test_schema_required(self):
3451 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3454 def test_impl_forbidden(self):
3455 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3456 Choice(impl=b"whatever")
3458 def test_invalid_value_type(self):
3459 with self.assertRaises(InvalidValueType) as err:
3460 self.base_klass(123)
3462 with self.assertRaises(ObjUnknown) as err:
3463 self.base_klass(("whenever", Boolean(False)))
3465 with self.assertRaises(InvalidValueType) as err:
3466 self.base_klass(("whatever", Integer(123)))
3470 def test_optional(self, optional):
3471 obj = self.base_klass(
3472 default=self.base_klass(("whatever", Boolean(False))),
3475 self.assertTrue(obj.optional)
3478 def test_ready(self, value):
3479 obj = self.base_klass()
3480 self.assertFalse(obj.ready)
3483 self.assertIsNone(obj["whatever"])
3484 with self.assertRaises(ObjNotReady) as err:
3487 obj["whatever"] = Boolean()
3488 self.assertFalse(obj.ready)
3491 obj["whatever"] = Boolean(value)
3492 self.assertTrue(obj.ready)
3496 @given(booleans(), booleans())
3497 def test_comparison(self, value1, value2):
3498 class WahlInherited(self.base_klass):
3500 for klass in (self.base_klass, WahlInherited):
3501 obj1 = klass(("whatever", Boolean(value1)))
3502 obj2 = klass(("whatever", Boolean(value2)))
3503 self.assertEqual(obj1 == obj2, value1 == value2)
3504 self.assertEqual(obj1 != obj2, value1 != value2)
3505 self.assertEqual(obj1 == obj2._value, value1 == value2)
3506 self.assertFalse(obj1 == obj2._value[1])
3508 @given(data_strategy())
3509 def test_call(self, d):
3510 for klass in (Choice, ChoiceInherited):
3518 ) = d.draw(choice_values_strategy())
3521 schema = schema_initial
3523 value=value_initial,
3525 default=default_initial,
3526 optional=optional_initial or False,
3527 _decoded=_decoded_initial,
3536 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
3537 obj = obj_initial(value, expl, default, optional)
3539 value_expected = default if value is None else value
3541 default_initial if value_expected is None
3544 self.assertEqual(obj.choice, value_expected[0])
3545 self.assertEqual(obj.value, int(value_expected[1]))
3546 self.assertEqual(obj.expl_tag, expl or expl_initial)
3547 default_expect = default_initial if default is None else default
3548 if default_expect is not None:
3549 self.assertEqual(obj.default.choice, default_expect[0])
3550 self.assertEqual(obj.default.value, int(default_expect[1]))
3551 if obj.default is None:
3552 optional = optional_initial if optional is None else optional
3553 optional = False if optional is None else optional
3556 self.assertEqual(obj.optional, optional)
3557 self.assertEqual(obj.specs, obj_initial.specs)
3559 def test_simultaneous_impl_expl(self):
3560 # override it, as Any does not have implicit tag
3563 def test_decoded(self):
3564 # override it, as Any does not have implicit tag
3567 @given(choice_values_strategy())
3568 def test_copy(self, values):
3569 _schema, value, expl, default, optional, _decoded = values
3571 class Wahl(self.base_klass):
3577 optional=optional or False,
3580 obj_copied = obj.copy()
3581 self.assertIsNone(obj.tag)
3582 self.assertIsNone(obj_copied.tag)
3583 # hack for assert_copied_basic_fields
3584 obj.tag = "whatever"
3585 obj_copied.tag = "whatever"
3586 self.assert_copied_basic_fields(obj, obj_copied)
3587 self.assertEqual(obj._value, obj_copied._value)
3588 self.assertEqual(obj.specs, obj_copied.specs)
3591 def test_stripped(self, value):
3592 obj = self.base_klass(("whatever", Boolean(value)))
3593 with self.assertRaises(NotEnoughData):
3594 obj.decode(obj.encode()[:-1])
3598 integers(min_value=1).map(tag_ctxc),
3600 def test_stripped_expl(self, value, tag_expl):
3601 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3602 with self.assertRaises(NotEnoughData):
3603 obj.decode(obj.encode()[:-1])
3605 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3606 @given(data_strategy())
3607 def test_symmetric(self, d):
3608 _schema, value, _, default, optional, _decoded = d.draw(
3609 choice_values_strategy(value_required=True)
3611 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3612 offset = d.draw(integers(min_value=0))
3613 tail_junk = d.draw(binary(max_size=5))
3615 class Wahl(self.base_klass):
3625 self.assertFalse(obj.expled)
3626 obj_encoded = obj.encode()
3627 obj_expled = obj(value, expl=tag_expl)
3628 self.assertTrue(obj_expled.expled)
3631 obj_expled_encoded = obj_expled.encode()
3632 obj_decoded, tail = obj_expled.decode(
3633 obj_expled_encoded + tail_junk,
3638 self.assertEqual(tail, tail_junk)
3639 self.assertEqual(obj_decoded, obj_expled)
3640 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3641 self.assertEqual(obj_decoded.value, obj_expled.value)
3642 self.assertEqual(obj_decoded.choice, obj.choice)
3643 self.assertEqual(obj_decoded.value, obj.value)
3644 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3645 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3646 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3648 obj_decoded.expl_llen,
3649 len(len_encode(len(obj_encoded))),
3651 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3652 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3655 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3657 self.assertEqual(obj_decoded.expl_offset, offset)
3658 self.assertSequenceEqual(
3660 obj_decoded.value.offset - offset:
3661 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3667 def test_set_get(self, value):
3670 ("erste", Boolean()),
3671 ("zweite", Integer()),
3674 with self.assertRaises(ObjUnknown) as err:
3675 obj["whatever"] = "whenever"
3676 with self.assertRaises(InvalidValueType) as err:
3677 obj["zweite"] = Boolean(False)
3678 obj["zweite"] = Integer(value)
3680 with self.assertRaises(ObjUnknown) as err:
3683 self.assertIsNone(obj["erste"])
3684 self.assertEqual(obj["zweite"], Integer(value))
3686 def test_tag_mismatch(self):
3689 ("erste", Boolean()),
3691 int_encoded = Integer(123).encode()
3692 bool_encoded = Boolean(False).encode()
3694 obj.decode(bool_encoded)
3695 with self.assertRaises(TagMismatch):
3696 obj.decode(int_encoded)
3700 def seq_values_strategy(draw, seq_klass, do_expl=False):
3702 if draw(booleans()):
3705 k: v for k, v in draw(dictionaries(
3708 booleans().map(Boolean),
3709 integers().map(Integer),
3714 if draw(booleans()):
3715 schema = list(draw(dictionaries(
3718 booleans().map(Boolean),
3719 integers().map(Integer),
3725 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3727 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3729 if draw(booleans()):
3730 default = seq_klass()
3732 k: v for k, v in draw(dictionaries(
3735 booleans().map(Boolean),
3736 integers().map(Integer),
3740 optional = draw(one_of(none(), booleans()))
3742 draw(integers(min_value=0)),
3743 draw(integers(min_value=0)),
3744 draw(integers(min_value=0)),
3746 return (value, schema, impl, expl, default, optional, _decoded)
3750 def sequence_strategy(draw, seq_klass):
3751 inputs = draw(lists(
3753 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
3754 tuples(just(Integer), integers(), one_of(none(), integers())),
3759 integers(min_value=1),
3760 min_size=len(inputs),
3761 max_size=len(inputs),
3764 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3765 for tag, expled in zip(tags, draw(lists(
3767 min_size=len(inputs),
3768 max_size=len(inputs),
3772 for i, optional in enumerate(draw(lists(
3773 sampled_from(("required", "optional", "empty")),
3774 min_size=len(inputs),
3775 max_size=len(inputs),
3777 if optional in ("optional", "empty"):
3778 inits[i]["optional"] = True
3779 if optional == "empty":
3781 empties = set(empties)
3782 names = list(draw(sets(
3784 min_size=len(inputs),
3785 max_size=len(inputs),
3788 for i, (klass, value, default) in enumerate(inputs):
3789 schema.append((names[i], klass(default=default, **inits[i])))
3790 seq_name = draw(text_letters())
3791 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3794 for i, (klass, value, default) in enumerate(inputs):
3801 "default_value": None if spec.default is None else default,
3805 expect["optional"] = True
3807 expect["presented"] = True
3808 expect["value"] = value
3810 expect["optional"] = True
3811 if default is not None and default == value:
3812 expect["presented"] = False
3813 seq[name] = klass(value)
3814 expects.append(expect)
3819 def sequences_strategy(draw, seq_klass):
3820 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
3822 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3823 for tag, expled in zip(tags, draw(lists(
3830 i for i, is_default in enumerate(draw(lists(
3836 names = list(draw(sets(
3841 seq_expectses = draw(lists(
3842 sequence_strategy(seq_klass=seq_klass),
3846 seqs = [seq for seq, _ in seq_expectses]
3848 for i, (name, seq) in enumerate(zip(names, seqs)):
3851 seq(default=(seq if i in defaulted else None), **inits[i]),
3853 seq_name = draw(text_letters())
3854 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3857 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
3860 "expects": expects_inner,
3863 seq_outer[name] = seq_inner
3864 if seq_outer.specs[name].default is None:
3865 expect["presented"] = True
3866 expect_outers.append(expect)
3867 return seq_outer, expect_outers
3870 class SeqMixing(object):
3871 def test_invalid_value_type(self):
3872 with self.assertRaises(InvalidValueType) as err:
3873 self.base_klass((1, 2, 3))
3876 def test_invalid_value_type_set(self):
3877 class Seq(self.base_klass):
3878 schema = (("whatever", Boolean()),)
3880 with self.assertRaises(InvalidValueType) as err:
3881 seq["whatever"] = Integer(123)
3885 def test_optional(self, optional):
3886 obj = self.base_klass(default=self.base_klass(), optional=optional)
3887 self.assertTrue(obj.optional)
3889 @given(data_strategy())
3890 def test_ready(self, d):
3892 str(i): v for i, v in enumerate(d.draw(lists(
3899 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
3906 for name in d.draw(permutations(
3907 list(ready.keys()) + list(non_ready.keys()),
3909 schema_input.append((name, Boolean()))
3911 class Seq(self.base_klass):
3912 schema = tuple(schema_input)
3914 for name in ready.keys():
3916 seq[name] = Boolean()
3917 self.assertFalse(seq.ready)
3920 for name, value in ready.items():
3921 seq[name] = Boolean(value)
3922 self.assertFalse(seq.ready)
3925 with self.assertRaises(ObjNotReady) as err:
3928 for name, value in non_ready.items():
3929 seq[name] = Boolean(value)
3930 self.assertTrue(seq.ready)
3934 @given(data_strategy())
3935 def test_call(self, d):
3936 class SeqInherited(self.base_klass):
3938 for klass in (self.base_klass, SeqInherited):
3947 ) = d.draw(seq_values_strategy(seq_klass=klass))
3948 obj_initial = klass(
3954 optional_initial or False,
3965 ) = d.draw(seq_values_strategy(
3967 do_expl=impl_initial is None,
3969 obj = obj_initial(value, impl, expl, default, optional)
3970 value_expected = default if value is None else value
3972 default_initial if value_expected is None
3975 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
3976 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3977 self.assertEqual(obj.expl_tag, expl or expl_initial)
3979 {} if obj.default is None else obj.default._value,
3980 getattr(default_initial if default is None else default, "_value", {}),
3982 if obj.default is None:
3983 optional = optional_initial if optional is None else optional
3984 optional = False if optional is None else optional
3987 self.assertEqual(list(obj.specs.items()), schema_initial or [])
3988 self.assertEqual(obj.optional, optional)
3990 @given(data_strategy())
3991 def test_copy(self, d):
3992 class SeqInherited(self.base_klass):
3994 for klass in (self.base_klass, SeqInherited):
3995 values = d.draw(seq_values_strategy(seq_klass=klass))
3996 obj = klass(*values)
3997 obj_copied = obj.copy()
3998 self.assert_copied_basic_fields(obj, obj_copied)
3999 self.assertEqual(obj.specs, obj_copied.specs)
4000 self.assertEqual(obj._value, obj_copied._value)
4002 @given(data_strategy())
4003 def test_stripped(self, d):
4004 value = d.draw(integers())
4005 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4007 class Seq(self.base_klass):
4009 schema = (("whatever", Integer()),)
4011 seq["whatever"] = Integer(value)
4012 with self.assertRaises(NotEnoughData):
4013 seq.decode(seq.encode()[:-1])
4015 @given(data_strategy())
4016 def test_stripped_expl(self, d):
4017 value = d.draw(integers())
4018 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4020 class Seq(self.base_klass):
4022 schema = (("whatever", Integer()),)
4024 seq["whatever"] = Integer(value)
4025 with self.assertRaises(NotEnoughData):
4026 seq.decode(seq.encode()[:-1])
4028 @given(binary(min_size=2))
4029 def test_non_tag_mismatch_raised(self, junk):
4031 _, _, len_encoded = tag_strip(memoryview(junk))
4032 len_decode(len_encoded)
4038 class Seq(self.base_klass):
4040 ("whatever", Integer()),
4042 ("whenever", Integer()),
4045 seq["whatever"] = Integer(123)
4046 seq["junk"] = Any(junk)
4047 seq["whenever"] = Integer(123)
4048 with self.assertRaises(DecodeError):
4049 seq.decode(seq.encode())
4052 integers(min_value=31),
4053 integers(min_value=0),
4056 def test_bad_tag(self, tag, offset, decode_path):
4057 decode_path = tuple(str(i) for i in decode_path)
4058 with self.assertRaises(DecodeError) as err:
4059 self.base_klass().decode(
4060 tag_encode(tag)[:-1],
4062 decode_path=decode_path,
4065 self.assertEqual(err.exception.offset, offset)
4066 self.assertEqual(err.exception.decode_path, decode_path)
4069 integers(min_value=128),
4070 integers(min_value=0),
4073 def test_bad_len(self, l, offset, decode_path):
4074 decode_path = tuple(str(i) for i in decode_path)
4075 with self.assertRaises(DecodeError) as err:
4076 self.base_klass().decode(
4077 self.base_klass.tag_default + len_encode(l)[:-1],
4079 decode_path=decode_path,
4082 self.assertEqual(err.exception.offset, offset)
4083 self.assertEqual(err.exception.decode_path, decode_path)
4085 def _assert_expects(self, seq, expects):
4086 for expect in expects:
4088 seq.specs[expect["name"]].optional,
4091 if expect["default_value"] is not None:
4093 seq.specs[expect["name"]].default,
4094 expect["default_value"],
4096 if expect["presented"]:
4097 self.assertIn(expect["name"], seq)
4098 self.assertEqual(seq[expect["name"]], expect["value"])
4100 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4101 @given(data_strategy())
4102 def test_symmetric(self, d):
4103 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4104 tail_junk = d.draw(binary(max_size=5))
4105 self.assertTrue(seq.ready)
4106 self.assertFalse(seq.decoded)
4107 self._assert_expects(seq, expects)
4110 seq_encoded = seq.encode()
4111 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4112 self.assertEqual(tail, tail_junk)
4113 self.assertTrue(seq.ready)
4114 self._assert_expects(seq_decoded, expects)
4115 self.assertEqual(seq, seq_decoded)
4116 self.assertEqual(seq_decoded.encode(), seq_encoded)
4117 for expect in expects:
4118 if not expect["presented"]:
4119 self.assertNotIn(expect["name"], seq_decoded)
4121 self.assertIn(expect["name"], seq_decoded)
4122 obj = seq_decoded[expect["name"]]
4123 self.assertTrue(obj.decoded)
4124 offset = obj.expl_offset if obj.expled else obj.offset
4125 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4126 self.assertSequenceEqual(
4127 seq_encoded[offset:offset + tlvlen],
4131 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4132 @given(data_strategy())
4133 def test_symmetric_with_seq(self, d):
4134 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4135 self.assertTrue(seq.ready)
4136 seq_encoded = seq.encode()
4137 seq_decoded, tail = seq.decode(seq_encoded)
4138 self.assertEqual(tail, b"")
4139 self.assertTrue(seq.ready)
4140 self.assertEqual(seq, seq_decoded)
4141 self.assertEqual(seq_decoded.encode(), seq_encoded)
4142 for expect_outer in expect_outers:
4143 if not expect_outer["presented"]:
4144 self.assertNotIn(expect_outer["name"], seq_decoded)
4146 self.assertIn(expect_outer["name"], seq_decoded)
4147 obj = seq_decoded[expect_outer["name"]]
4148 self.assertTrue(obj.decoded)
4149 offset = obj.expl_offset if obj.expled else obj.offset
4150 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4151 self.assertSequenceEqual(
4152 seq_encoded[offset:offset + tlvlen],
4155 self._assert_expects(obj, expect_outer["expects"])
4157 @given(data_strategy())
4158 def test_default_disappears(self, d):
4159 _schema = list(d.draw(dictionaries(
4161 sets(integers(), min_size=2, max_size=2),
4165 class Seq(self.base_klass):
4167 (n, Integer(default=d))
4168 for n, (_, d) in _schema
4171 for name, (value, _) in _schema:
4172 seq[name] = Integer(value)
4173 self.assertEqual(len(seq._value), len(_schema))
4174 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4175 self.assertGreater(len(seq.encode()), len(empty_seq))
4176 for name, (_, default) in _schema:
4177 seq[name] = Integer(default)
4178 self.assertEqual(len(seq._value), 0)
4179 self.assertSequenceEqual(seq.encode(), empty_seq)
4181 @given(data_strategy())
4182 def test_encoded_default_accepted(self, d):
4183 _schema = list(d.draw(dictionaries(
4188 tags = [tag_encode(tag) for tag in d.draw(sets(
4189 integers(min_value=0),
4190 min_size=len(_schema),
4191 max_size=len(_schema),
4194 class SeqWithoutDefault(self.base_klass):
4196 (n, Integer(impl=t))
4197 for (n, _), t in zip(_schema, tags)
4199 seq_without_default = SeqWithoutDefault()
4200 for name, value in _schema:
4201 seq_without_default[name] = Integer(value)
4202 seq_encoded = seq_without_default.encode()
4204 class SeqWithDefault(self.base_klass):
4206 (n, Integer(default=v, impl=t))
4207 for (n, v), t in zip(_schema, tags)
4209 seq_with_default = SeqWithDefault()
4210 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4211 for name, value in _schema:
4212 self.assertEqual(seq_decoded[name], seq_with_default[name])
4213 self.assertEqual(seq_decoded[name], value)
4215 @given(data_strategy())
4216 def test_missing_from_spec(self, d):
4217 names = list(d.draw(sets(text_letters(), min_size=2)))
4218 tags = [tag_encode(tag) for tag in d.draw(sets(
4219 integers(min_value=0),
4220 min_size=len(names),
4221 max_size=len(names),
4223 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4225 class SeqFull(self.base_klass):
4226 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4227 seq_full = SeqFull()
4228 for i, name in enumerate(names):
4229 seq_full[name] = Integer(i)
4230 seq_encoded = seq_full.encode()
4231 altered = names_tags[:-2] + names_tags[-1:]
4233 class SeqMissing(self.base_klass):
4234 schema = [(n, Integer(impl=t)) for n, t in altered]
4235 seq_missing = SeqMissing()
4236 with self.assertRaises(TagMismatch):
4237 seq_missing.decode(seq_encoded)
4240 class TestSequence(SeqMixing, CommonMixin, TestCase):
4241 base_klass = Sequence
4247 def test_remaining(self, value, junk):
4248 class Seq(Sequence):
4250 ("whatever", Integer()),
4252 int_encoded = Integer(value).encode()
4254 Sequence.tag_default,
4255 len_encode(len(int_encoded + junk)),
4258 with assertRaisesRegex(self, DecodeError, "remaining"):
4259 Seq().decode(junked)
4261 @given(sets(text_letters(), min_size=2))
4262 def test_obj_unknown(self, names):
4263 missing = names.pop()
4265 class Seq(Sequence):
4266 schema = [(n, Boolean()) for n in names]
4268 with self.assertRaises(ObjUnknown) as err:
4271 with self.assertRaises(ObjUnknown) as err:
4272 seq[missing] = Boolean()
4276 class TestSet(SeqMixing, CommonMixin, TestCase):
4279 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4280 @given(data_strategy())
4281 def test_sorted(self, d):
4283 tag_encode(tag) for tag in
4284 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4288 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4290 for name, _ in Seq.schema:
4291 seq[name] = OctetString(b"")
4292 seq_encoded = seq.encode()
4293 seq_decoded, _ = seq.decode(seq_encoded)
4294 self.assertSequenceEqual(
4295 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4296 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4301 def seqof_values_strategy(draw, schema=None, do_expl=False):
4303 schema = draw(sampled_from((Boolean(), Integer())))
4304 bound_min, bound_max = sorted(draw(sets(
4305 integers(min_value=0, max_value=10),
4309 if isinstance(schema, Boolean):
4310 values_generator = booleans().map(Boolean)
4311 elif isinstance(schema, Integer):
4312 values_generator = integers().map(Integer)
4313 values_generator = lists(
4318 values = draw(one_of(none(), values_generator))
4322 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4324 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4325 default = draw(one_of(none(), values_generator))
4326 optional = draw(one_of(none(), booleans()))
4328 draw(integers(min_value=0)),
4329 draw(integers(min_value=0)),
4330 draw(integers(min_value=0)),
4335 (bound_min, bound_max),
4344 class SeqOfMixing(object):
4345 def test_invalid_value_type(self):
4346 with self.assertRaises(InvalidValueType) as err:
4347 self.base_klass(123)
4350 def test_invalid_values_type(self):
4351 class SeqOf(self.base_klass):
4353 with self.assertRaises(InvalidValueType) as err:
4354 SeqOf([Integer(123), Boolean(False), Integer(234)])
4357 def test_schema_required(self):
4358 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4359 self.base_klass.__mro__[1]()
4361 @given(booleans(), booleans(), binary(), binary())
4362 def test_comparison(self, value1, value2, tag1, tag2):
4363 class SeqOf(self.base_klass):
4365 obj1 = SeqOf([Boolean(value1)])
4366 obj2 = SeqOf([Boolean(value2)])
4367 self.assertEqual(obj1 == obj2, value1 == value2)
4368 self.assertEqual(obj1 != obj2, value1 != value2)
4369 self.assertEqual(obj1 == list(obj2), value1 == value2)
4370 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4371 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4372 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4373 self.assertEqual(obj1 == obj2, tag1 == tag2)
4374 self.assertEqual(obj1 != obj2, tag1 != tag2)
4376 @given(lists(booleans()))
4377 def test_iter(self, values):
4378 class SeqOf(self.base_klass):
4380 obj = SeqOf([Boolean(value) for value in values])
4381 self.assertEqual(len(obj), len(values))
4382 for i, value in enumerate(obj):
4383 self.assertEqual(value, values[i])
4385 @given(data_strategy())
4386 def test_ready(self, d):
4387 ready = [Integer(v) for v in d.draw(lists(
4394 range(d.draw(integers(min_value=1, max_value=5)))
4397 class SeqOf(self.base_klass):
4399 values = d.draw(permutations(ready + non_ready))
4401 for value in values:
4403 self.assertFalse(seqof.ready)
4406 with self.assertRaises(ObjNotReady) as err:
4409 for i, value in enumerate(values):
4410 self.assertEqual(seqof[i], value)
4411 if not seqof[i].ready:
4412 seqof[i] = Integer(i)
4413 self.assertTrue(seqof.ready)
4417 def test_spec_mismatch(self):
4418 class SeqOf(self.base_klass):
4421 seqof.append(Integer(123))
4422 with self.assertRaises(ValueError):
4423 seqof.append(Boolean(False))
4424 with self.assertRaises(ValueError):
4425 seqof[0] = Boolean(False)
4427 @given(data_strategy())
4428 def test_bounds_satisfied(self, d):
4429 class SeqOf(self.base_klass):
4431 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4432 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4433 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4434 SeqOf(value=value, bounds=(bound_min, bound_max))
4436 @given(data_strategy())
4437 def test_bounds_unsatisfied(self, d):
4438 class SeqOf(self.base_klass):
4440 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4441 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4442 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4443 with self.assertRaises(BoundsError) as err:
4444 SeqOf(value=value, bounds=(bound_min, bound_max))
4446 value = [Boolean()] * d.draw(integers(
4447 min_value=bound_max + 1,
4448 max_value=bound_max + 10,
4450 with self.assertRaises(BoundsError) as err:
4451 SeqOf(value=value, bounds=(bound_min, bound_max))
4454 @given(integers(min_value=1, max_value=10))
4455 def test_out_of_bounds(self, bound_max):
4456 class SeqOf(self.base_klass):
4458 bounds = (0, bound_max)
4460 for _ in range(bound_max):
4461 seqof.append(Integer(123))
4462 with self.assertRaises(BoundsError):
4463 seqof.append(Integer(123))
4465 @given(data_strategy())
4466 def test_call(self, d):
4476 ) = d.draw(seqof_values_strategy())
4478 class SeqOf(self.base_klass):
4479 schema = schema_initial
4480 obj_initial = SeqOf(
4481 value=value_initial,
4482 bounds=bounds_initial,
4485 default=default_initial,
4486 optional=optional_initial or False,
4487 _decoded=_decoded_initial,
4498 ) = d.draw(seqof_values_strategy(
4499 schema=schema_initial,
4500 do_expl=impl_initial is None,
4502 if (default is None) and (obj_initial.default is not None):
4505 (bounds is None) and
4506 (value is not None) and
4507 (bounds_initial is not None) and
4508 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4512 (bounds is None) and
4513 (default is not None) and
4514 (bounds_initial is not None) and
4515 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4527 value_expected = default if value is None else value
4529 default_initial if value_expected is None
4532 value_expected = () if value_expected is None else value_expected
4533 self.assertEqual(obj, value_expected)
4534 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4535 self.assertEqual(obj.expl_tag, expl or expl_initial)
4538 default_initial if default is None else default,
4540 if obj.default is None:
4541 optional = optional_initial if optional is None else optional
4542 optional = False if optional is None else optional
4545 self.assertEqual(obj.optional, optional)
4547 (obj._bound_min, obj._bound_max),
4548 bounds or bounds_initial or (0, float("+inf")),
4551 @given(seqof_values_strategy())
4552 def test_copy(self, values):
4553 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4555 class SeqOf(self.base_klass):
4563 optional=optional or False,
4566 obj_copied = obj.copy()
4567 self.assert_copied_basic_fields(obj, obj_copied)
4568 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4569 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4570 self.assertEqual(obj._value, obj_copied._value)
4574 integers(min_value=1).map(tag_encode),
4576 def test_stripped(self, values, tag_impl):
4577 class SeqOf(self.base_klass):
4578 schema = OctetString()
4579 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4580 with self.assertRaises(NotEnoughData):
4581 obj.decode(obj.encode()[:-1])
4585 integers(min_value=1).map(tag_ctxc),
4587 def test_stripped_expl(self, values, tag_expl):
4588 class SeqOf(self.base_klass):
4589 schema = OctetString()
4590 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4591 with self.assertRaises(NotEnoughData):
4592 obj.decode(obj.encode()[:-1])
4595 integers(min_value=31),
4596 integers(min_value=0),
4599 def test_bad_tag(self, tag, offset, decode_path):
4600 decode_path = tuple(str(i) for i in decode_path)
4601 with self.assertRaises(DecodeError) as err:
4602 self.base_klass().decode(
4603 tag_encode(tag)[:-1],
4605 decode_path=decode_path,
4608 self.assertEqual(err.exception.offset, offset)
4609 self.assertEqual(err.exception.decode_path, decode_path)
4612 integers(min_value=128),
4613 integers(min_value=0),
4616 def test_bad_len(self, l, offset, decode_path):
4617 decode_path = tuple(str(i) for i in decode_path)
4618 with self.assertRaises(DecodeError) as err:
4619 self.base_klass().decode(
4620 self.base_klass.tag_default + len_encode(l)[:-1],
4622 decode_path=decode_path,
4625 self.assertEqual(err.exception.offset, offset)
4626 self.assertEqual(err.exception.decode_path, decode_path)
4628 @given(binary(min_size=1))
4629 def test_tag_mismatch(self, impl):
4630 assume(impl != self.base_klass.tag_default)
4631 with self.assertRaises(TagMismatch):
4632 self.base_klass(impl=impl).decode(self.base_klass().encode())
4634 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4636 seqof_values_strategy(schema=Integer()),
4637 lists(integers().map(Integer)),
4638 integers(min_value=1).map(tag_ctxc),
4639 integers(min_value=0),
4642 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4643 _, _, _, _, _, default, optional, _decoded = values
4645 class SeqOf(self.base_klass):
4655 self.assertFalse(obj.expled)
4656 obj_encoded = obj.encode()
4657 obj_expled = obj(value, expl=tag_expl)
4658 self.assertTrue(obj_expled.expled)
4661 obj_expled_encoded = obj_expled.encode()
4662 obj_decoded, tail = obj_expled.decode(
4663 obj_expled_encoded + tail_junk,
4668 self.assertEqual(tail, tail_junk)
4669 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
4670 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4671 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4672 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4674 obj_decoded.expl_llen,
4675 len(len_encode(len(obj_encoded))),
4677 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4678 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4681 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4683 self.assertEqual(obj_decoded.expl_offset, offset)
4684 for obj_inner in obj_decoded:
4685 self.assertIn(obj_inner, obj_decoded)
4686 self.assertSequenceEqual(
4689 obj_inner.offset - offset:
4690 obj_inner.offset + obj_inner.tlvlen - offset
4695 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
4696 class SeqOf(SequenceOf):
4700 def _test_symmetric_compare_objs(self, obj1, obj2):
4701 self.assertEqual(obj1, obj2)
4702 self.assertSequenceEqual(list(obj1), list(obj2))
4705 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
4710 def _test_symmetric_compare_objs(self, obj1, obj2):
4711 self.assertSetEqual(
4712 set(int(v) for v in obj1),
4713 set(int(v) for v in obj2),
4716 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4717 @given(data_strategy())
4718 def test_sorted(self, d):
4719 values = [OctetString(v) for v in d.draw(lists(binary()))]
4722 schema = OctetString()
4724 seq_encoded = seq.encode()
4725 seq_decoded, _ = seq.decode(seq_encoded)
4726 self.assertSequenceEqual(
4727 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4728 b"".join(sorted([v.encode() for v in values])),
4732 class TestGoMarshalVectors(TestCase):
4734 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
4735 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
4736 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
4737 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
4738 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
4740 class Seq(Sequence):
4742 ("erste", Integer()),
4743 ("zweite", Integer(optional=True))
4746 seq["erste"] = Integer(64)
4747 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4748 seq["erste"] = Integer(0x123456)
4749 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
4750 seq["erste"] = Integer(64)
4751 seq["zweite"] = Integer(65)
4752 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
4754 class NestedSeq(Sequence):
4758 seq["erste"] = Integer(127)
4759 seq["zweite"] = None
4760 nested = NestedSeq()
4761 nested["nest"] = seq
4762 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
4764 self.assertSequenceEqual(
4765 OctetString(b"\x01\x02\x03").encode(),
4766 hexdec("0403010203"),
4769 class Seq(Sequence):
4771 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
4774 seq["erste"] = Integer(64)
4775 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
4777 class Seq(Sequence):
4779 ("erste", Integer(expl=tag_ctxc(5))),
4782 seq["erste"] = Integer(64)
4783 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
4785 class Seq(Sequence):
4788 impl=tag_encode(0, klass=TagClassContext),
4793 seq["erste"] = Null()
4794 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
4796 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4798 self.assertSequenceEqual(
4799 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
4800 hexdec("170d3730303130313030303030305a"),
4802 self.assertSequenceEqual(
4803 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
4804 hexdec("170d3039313131353232353631365a"),
4806 self.assertSequenceEqual(
4807 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
4808 hexdec("180f32313030303430353132303130315a"),
4811 class Seq(Sequence):
4813 ("erste", GeneralizedTime()),
4816 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
4817 self.assertSequenceEqual(
4819 hexdec("3011180f32303039313131353232353631365a"),
4822 self.assertSequenceEqual(
4823 BitString((1, b"\x80")).encode(),
4826 self.assertSequenceEqual(
4827 BitString((12, b"\x81\xF0")).encode(),
4828 hexdec("03030481f0"),
4831 self.assertSequenceEqual(
4832 ObjectIdentifier("1.2.3.4").encode(),
4833 hexdec("06032a0304"),
4835 self.assertSequenceEqual(
4836 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
4837 hexdec("06092a864888932d010105"),
4839 self.assertSequenceEqual(
4840 ObjectIdentifier("2.100.3").encode(),
4841 hexdec("0603813403"),
4844 self.assertSequenceEqual(
4845 PrintableString("test").encode(),
4846 hexdec("130474657374"),
4848 self.assertSequenceEqual(
4849 PrintableString("x" * 127).encode(),
4850 hexdec("137F" + "78" * 127),
4852 self.assertSequenceEqual(
4853 PrintableString("x" * 128).encode(),
4854 hexdec("138180" + "78" * 128),
4856 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
4858 class Seq(Sequence):
4860 ("erste", IA5String()),
4863 seq["erste"] = IA5String("test")
4864 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
4866 class Seq(Sequence):
4868 ("erste", PrintableString()),
4871 seq["erste"] = PrintableString("test")
4872 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
4873 seq["erste"] = PrintableString("test*")
4874 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
4876 class Seq(Sequence):
4878 ("erste", Any(optional=True)),
4879 ("zweite", Integer()),
4882 seq["zweite"] = Integer(64)
4883 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4888 seq.append(Integer(10))
4889 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
4891 class _SeqOf(SequenceOf):
4892 schema = PrintableString()
4894 class SeqOf(SequenceOf):
4897 _seqof.append(PrintableString("1"))
4899 seqof.append(_seqof)
4900 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
4902 class Seq(Sequence):
4904 ("erste", Integer(default=1)),
4907 seq["erste"] = Integer(0)
4908 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
4909 seq["erste"] = Integer(1)
4910 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4911 seq["erste"] = Integer(2)
4912 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
4915 class TestPP(TestCase):
4916 @given(data_strategy())
4917 def test_oid_printing(self, d):
4919 str(ObjectIdentifier(k)): v * 2
4920 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
4922 chosen = d.draw(sampled_from(sorted(oids)))
4923 chosen_id = oids[chosen]
4924 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
4925 self.assertNotIn(chosen_id, pp_console_row(pp))
4926 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
4929 class TestAutoAddSlots(TestCase):
4931 class Inher(Integer):
4934 with self.assertRaises(AttributeError):
4936 inher.unexistent = "whatever"
4939 class TestOIDDefines(TestCase):
4940 @given(data_strategy())
4941 def runTest(self, d):
4942 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
4943 value_name_chosen = d.draw(sampled_from(value_names))
4945 ObjectIdentifier(oid)
4946 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
4948 oid_chosen = d.draw(sampled_from(oids))
4949 values = d.draw(lists(
4951 min_size=len(value_names),
4952 max_size=len(value_names),
4955 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
4956 oid: Integer() for oid in oids[:-1]
4959 for i, value_name in enumerate(value_names):
4960 _schema.append((value_name, Any(expl=tag_ctxp(i))))
4962 class Seq(Sequence):
4965 for value_name, value in zip(value_names, values):
4966 seq[value_name] = Any(Integer(value).encode())
4967 seq["type"] = oid_chosen
4968 seq, _ = Seq().decode(seq.encode())
4969 for value_name in value_names:
4970 if value_name == value_name_chosen:
4972 self.assertIsNone(seq[value_name].defined)
4973 if value_name_chosen in oids[:-1]:
4974 self.assertIsNotNone(seq[value_name_chosen].defined)
4975 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
4976 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
4979 class TestDefinesByPath(TestCase):
4980 def test_generated(self):
4981 class Seq(Sequence):
4983 ("type", ObjectIdentifier()),
4984 ("value", OctetString(expl=tag_ctxc(123))),
4987 class SeqInner(Sequence):
4989 ("typeInner", ObjectIdentifier()),
4990 ("valueInner", Any()),
4993 class PairValue(SetOf):
4996 class Pair(Sequence):
4998 ("type", ObjectIdentifier()),
4999 ("value", PairValue()),
5002 class Pairs(SequenceOf):
5009 type_octet_stringed,
5011 ObjectIdentifier(oid)
5012 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5014 seq_integered = Seq()
5015 seq_integered["type"] = type_integered
5016 seq_integered["value"] = OctetString(Integer(123).encode())
5017 seq_integered_raw = seq_integered.encode()
5021 (type_octet_stringed, OctetString(b"whatever")),
5022 (type_integered, Integer(123)),
5023 (type_octet_stringed, OctetString(b"whenever")),
5024 (type_integered, Integer(234)),
5026 for t, v in pairs_input:
5029 pair["value"] = PairValue((Any(v),))
5031 seq_inner = SeqInner()
5032 seq_inner["typeInner"] = type_innered
5033 seq_inner["valueInner"] = Any(pairs)
5034 seq_sequenced = Seq()
5035 seq_sequenced["type"] = type_sequenced
5036 seq_sequenced["value"] = OctetString(seq_inner.encode())
5037 seq_sequenced_raw = seq_sequenced.encode()
5039 defines_by_path = []
5040 seq_integered, _ = Seq().decode(seq_integered_raw)
5041 self.assertIsNone(seq_integered["value"].defined)
5042 defines_by_path.append(
5043 (("type",), ((("value",), {
5044 type_integered: Integer(),
5045 type_sequenced: SeqInner(),
5048 seq_integered, _ = Seq().decode(
5050 ctx={"defines_by_path": defines_by_path},
5052 self.assertIsNotNone(seq_integered["value"].defined)
5053 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5054 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5055 self.assertTrue(seq_integered_raw[
5056 seq_integered["value"].defined[1].offset:
5057 ].startswith(Integer(123).encode()))
5059 seq_sequenced, _ = Seq().decode(
5061 ctx={"defines_by_path": defines_by_path},
5063 self.assertIsNotNone(seq_sequenced["value"].defined)
5064 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5065 seq_inner = seq_sequenced["value"].defined[1]
5066 self.assertIsNone(seq_inner["valueInner"].defined)
5068 defines_by_path.append((
5069 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5070 ((("valueInner",), {type_innered: Pairs()}),),
5072 seq_sequenced, _ = Seq().decode(
5074 ctx={"defines_by_path": defines_by_path},
5076 self.assertIsNotNone(seq_sequenced["value"].defined)
5077 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5078 seq_inner = seq_sequenced["value"].defined[1]
5079 self.assertIsNotNone(seq_inner["valueInner"].defined)
5080 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5081 pairs = seq_inner["valueInner"].defined[1]
5083 self.assertIsNone(pair["value"][0].defined)
5085 defines_by_path.append((
5088 DecodePathDefBy(type_sequenced),
5090 DecodePathDefBy(type_innered),
5095 type_integered: Integer(),
5096 type_octet_stringed: OctetString(),
5099 seq_sequenced, _ = Seq().decode(
5101 ctx={"defines_by_path": defines_by_path},
5103 self.assertIsNotNone(seq_sequenced["value"].defined)
5104 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5105 seq_inner = seq_sequenced["value"].defined[1]
5106 self.assertIsNotNone(seq_inner["valueInner"].defined)
5107 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5108 pairs_got = seq_inner["valueInner"].defined[1]
5109 for pair_input, pair_got in zip(pairs_input, pairs_got):
5110 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5111 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5113 @given(oid_strategy(), integers())
5114 def test_simple(self, oid, tgt):
5115 class Inner(Sequence):
5117 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5118 ObjectIdentifier(oid): Integer(),
5122 class Outer(Sequence):
5125 ("tgt", OctetString()),
5129 inner["oid"] = ObjectIdentifier(oid)
5131 outer["inner"] = inner
5132 outer["tgt"] = OctetString(Integer(tgt).encode())
5133 decoded, _ = Outer().decode(outer.encode())
5134 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5137 class TestAbsDecodePath(TestCase):
5139 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5140 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5142 def test_concat(self, decode_path, rel_path):
5143 self.assertSequenceEqual(
5144 abs_decode_path(decode_path, rel_path),
5145 decode_path + rel_path,
5149 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5150 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5152 def test_abs(self, decode_path, rel_path):
5153 self.assertSequenceEqual(
5154 abs_decode_path(decode_path, ("/",) + rel_path),
5159 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5160 integers(min_value=1, max_value=3),
5161 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5163 def test_dots(self, decode_path, number_of_dots, rel_path):
5164 self.assertSequenceEqual(
5165 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5166 decode_path[:-number_of_dots] + rel_path,
5170 class TestStrictDefaultExistence(TestCase):
5171 @given(data_strategy())
5172 def runTest(self, d):
5173 count = d.draw(integers(min_value=1, max_value=10))
5174 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5176 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5177 for i in range(count)
5180 class Seq(Sequence):
5183 for i in range(count):
5184 seq["int%d" % i] = Integer(123)
5186 chosen = "int%d" % chosen
5187 seq.specs[chosen] = seq.specs[chosen](default=123)
5189 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5190 seq.decode(raw, ctx={"strict_default_existence": True})