2 # PyDERASN -- Python ASN.1 DER codec with abstract structures
3 # Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from datetime import datetime
20 from string import ascii_letters
21 from string import digits
22 from string import printable
23 from string import whitespace
24 from unittest import TestCase
26 from hypothesis import assume
27 from hypothesis import given
28 from hypothesis import settings
29 from hypothesis.strategies import binary
30 from hypothesis.strategies import booleans
31 from hypothesis.strategies import composite
32 from hypothesis.strategies import data as data_strategy
33 from hypothesis.strategies import datetimes
34 from hypothesis.strategies import dictionaries
35 from hypothesis.strategies import integers
36 from hypothesis.strategies import just
37 from hypothesis.strategies import lists
38 from hypothesis.strategies import none
39 from hypothesis.strategies import one_of
40 from hypothesis.strategies import permutations
41 from hypothesis.strategies import sampled_from
42 from hypothesis.strategies import sets
43 from hypothesis.strategies import text
44 from hypothesis.strategies import tuples
45 from six import assertRaisesRegex
46 from six import byte2int
47 from six import indexbytes
48 from six import int2byte
49 from six import iterbytes
51 from six import text_type
52 from six import unichr as six_unichr
54 from pyderasn import _pp
55 from pyderasn import abs_decode_path
56 from pyderasn import Any
57 from pyderasn import BitString
58 from pyderasn import BMPString
59 from pyderasn import Boolean
60 from pyderasn import BoundsError
61 from pyderasn import Choice
62 from pyderasn import DecodeError
63 from pyderasn import DecodePathDefBy
64 from pyderasn import Enumerated
65 from pyderasn import GeneralizedTime
66 from pyderasn import GeneralString
67 from pyderasn import GraphicString
68 from pyderasn import hexdec
69 from pyderasn import hexenc
70 from pyderasn import IA5String
71 from pyderasn import Integer
72 from pyderasn import InvalidLength
73 from pyderasn import InvalidOID
74 from pyderasn import InvalidValueType
75 from pyderasn import len_decode
76 from pyderasn import len_encode
77 from pyderasn import NotEnoughData
78 from pyderasn import Null
79 from pyderasn import NumericString
80 from pyderasn import ObjectIdentifier
81 from pyderasn import ObjNotReady
82 from pyderasn import ObjUnknown
83 from pyderasn import OctetString
84 from pyderasn import pp_console_row
85 from pyderasn import pprint
86 from pyderasn import PrintableString
87 from pyderasn import Sequence
88 from pyderasn import SequenceOf
89 from pyderasn import Set
90 from pyderasn import SetOf
91 from pyderasn import tag_ctxc
92 from pyderasn import tag_ctxp
93 from pyderasn import tag_decode
94 from pyderasn import tag_encode
95 from pyderasn import tag_strip
96 from pyderasn import TagClassApplication
97 from pyderasn import TagClassContext
98 from pyderasn import TagClassPrivate
99 from pyderasn import TagClassUniversal
100 from pyderasn import TagFormConstructed
101 from pyderasn import TagFormPrimitive
102 from pyderasn import TagMismatch
103 from pyderasn import TeletexString
104 from pyderasn import UniversalString
105 from pyderasn import UTCTime
106 from pyderasn import UTF8String
107 from pyderasn import VideotexString
108 from pyderasn import VisibleString
111 settings.register_profile('local', settings(
113 perform_health_check=False,
115 settings.load_profile('local')
116 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
118 tag_classes = sampled_from((
124 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
127 class TestHex(TestCase):
129 def test_symmetric(self, data):
130 self.assertEqual(hexdec(hexenc(data)), data)
133 class TestTagCoder(TestCase):
134 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
138 integers(min_value=0, max_value=30),
141 def test_short(self, klass, form, num, junk):
142 raw = tag_encode(klass=klass, form=form, num=num)
143 self.assertEqual(tag_decode(raw), (klass, form, num))
144 self.assertEqual(len(raw), 1)
146 byte2int(tag_encode(klass=klass, form=form, num=0)),
147 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
149 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
150 self.assertSequenceEqual(stripped.tobytes(), raw)
151 self.assertEqual(tlen, len(raw))
152 self.assertSequenceEqual(tail, junk)
154 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
158 integers(min_value=31),
161 def test_long(self, klass, form, num, junk):
162 raw = tag_encode(klass=klass, form=form, num=num)
163 self.assertEqual(tag_decode(raw), (klass, form, num))
164 self.assertGreater(len(raw), 1)
166 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
169 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
170 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
171 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
172 self.assertSequenceEqual(stripped.tobytes(), raw)
173 self.assertEqual(tlen, len(raw))
174 self.assertSequenceEqual(tail, junk)
176 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
177 @given(integers(min_value=31))
178 def test_unfinished_tag(self, num):
179 raw = bytearray(tag_encode(num=num))
180 for i in range(1, len(raw)):
182 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
183 tag_strip(bytes(raw))
185 def test_go_vectors_valid(self):
186 for data, (eklass, etag, elen, eform) in (
187 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
188 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
189 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
190 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
191 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
192 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
193 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
194 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
195 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
196 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
198 tag, _, len_encoded = tag_strip(memoryview(data))
199 klass, form, num = tag_decode(tag)
200 _len, _, tail = len_decode(len_encoded)
201 self.assertSequenceEqual(tail, b"")
202 self.assertEqual(klass, eklass)
203 self.assertEqual(num, etag)
204 self.assertEqual(_len, elen)
205 self.assertEqual(form, eform)
207 def test_go_vectors_invalid(self):
215 with self.assertRaises(DecodeError):
216 _, _, len_encoded = tag_strip(memoryview(data))
217 len_decode(len_encoded)
220 integers(min_value=0, max_value=127),
221 integers(min_value=0, max_value=2),
223 def test_long_instead_of_short(self, l, dummy_num):
224 octets = (b"\x00" * dummy_num) + int2byte(l)
225 octets = int2byte((dummy_num + 1) | 0x80) + octets
226 with self.assertRaises(DecodeError):
230 class TestLenCoder(TestCase):
231 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
233 integers(min_value=0, max_value=127),
236 def test_short(self, l, junk):
237 raw = len_encode(l) + junk
238 decoded, llen, tail = len_decode(memoryview(raw))
239 self.assertEqual(decoded, l)
240 self.assertEqual(llen, 1)
241 self.assertEqual(len(raw), 1 + len(junk))
242 self.assertEqual(tail.tobytes(), junk)
244 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
246 integers(min_value=128),
249 def test_long(self, l, junk):
250 raw = len_encode(l) + junk
251 decoded, llen, tail = len_decode(memoryview(raw))
252 self.assertEqual(decoded, l)
253 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
254 self.assertEqual(llen, len(raw) - len(junk))
255 self.assertNotEqual(indexbytes(raw, 1), 0)
256 self.assertSequenceEqual(tail.tobytes(), junk)
258 def test_empty(self):
259 with self.assertRaises(NotEnoughData):
262 @given(integers(min_value=128))
263 def test_stripped(self, _len):
264 with self.assertRaises(NotEnoughData):
265 len_decode(len_encode(_len)[:-1])
268 text_printable = text(alphabet=printable, min_size=1)
272 def text_letters(draw):
273 result = draw(text(alphabet=ascii_letters, min_size=1))
275 result = result.encode("ascii")
279 class CommonMixin(object):
280 def test_tag_default(self):
281 obj = self.base_klass()
282 self.assertEqual(obj.tag, obj.tag_default)
284 def test_simultaneous_impl_expl(self):
285 with self.assertRaises(ValueError):
286 self.base_klass(impl=b"whatever", expl=b"whenever")
288 @given(binary(), integers(), integers(), integers())
289 def test_decoded(self, impl, offset, llen, vlen):
290 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
291 self.assertEqual(obj.offset, offset)
292 self.assertEqual(obj.llen, llen)
293 self.assertEqual(obj.vlen, vlen)
294 self.assertEqual(obj.tlen, len(impl))
295 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
298 def test_impl_inherited(self, impl_tag):
299 class Inherited(self.base_klass):
302 self.assertSequenceEqual(obj.impl, impl_tag)
303 self.assertFalse(obj.expled)
306 def test_expl_inherited(self, expl_tag):
307 class Inherited(self.base_klass):
310 self.assertSequenceEqual(obj.expl, expl_tag)
311 self.assertTrue(obj.expled)
313 def assert_copied_basic_fields(self, obj, obj_copied):
314 self.assertEqual(obj, obj_copied)
315 self.assertSequenceEqual(obj.tag, obj_copied.tag)
316 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
317 self.assertEqual(obj.default, obj_copied.default)
318 self.assertEqual(obj.optional, obj_copied.optional)
319 self.assertEqual(obj.offset, obj_copied.offset)
320 self.assertEqual(obj.llen, obj_copied.llen)
321 self.assertEqual(obj.vlen, obj_copied.vlen)
325 def boolean_values_strategy(draw, do_expl=False):
326 value = draw(one_of(none(), booleans()))
330 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
332 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
333 default = draw(one_of(none(), booleans()))
334 optional = draw(one_of(none(), booleans()))
336 draw(integers(min_value=0)),
337 draw(integers(min_value=0)),
338 draw(integers(min_value=0)),
340 return (value, impl, expl, default, optional, _decoded)
343 class BooleanInherited(Boolean):
347 class TestBoolean(CommonMixin, TestCase):
350 def test_invalid_value_type(self):
351 with self.assertRaises(InvalidValueType) as err:
356 def test_optional(self, optional):
357 obj = Boolean(default=Boolean(False), optional=optional)
358 self.assertTrue(obj.optional)
361 def test_ready(self, value):
363 self.assertFalse(obj.ready)
366 with self.assertRaises(ObjNotReady) as err:
370 self.assertTrue(obj.ready)
374 @given(booleans(), booleans(), binary(), binary())
375 def test_comparison(self, value1, value2, tag1, tag2):
376 for klass in (Boolean, BooleanInherited):
379 self.assertEqual(obj1 == obj2, value1 == value2)
380 self.assertEqual(obj1 != obj2, value1 != value2)
381 self.assertEqual(obj1 == bool(obj2), value1 == value2)
382 obj1 = klass(value1, impl=tag1)
383 obj2 = klass(value1, impl=tag2)
384 self.assertEqual(obj1 == obj2, tag1 == tag2)
385 self.assertEqual(obj1 != obj2, tag1 != tag2)
387 @given(data_strategy())
388 def test_call(self, d):
389 for klass in (Boolean, BooleanInherited):
397 ) = d.draw(boolean_values_strategy())
403 optional_initial or False,
413 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
414 obj = obj_initial(value, impl, expl, default, optional)
416 value_expected = default if value is None else value
418 default_initial if value_expected is None
421 self.assertEqual(obj, value_expected)
422 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
423 self.assertEqual(obj.expl_tag, expl or expl_initial)
426 default_initial if default is None else default,
428 if obj.default is None:
429 optional = optional_initial if optional is None else optional
430 optional = False if optional is None else optional
433 self.assertEqual(obj.optional, optional)
435 @given(boolean_values_strategy())
436 def test_copy(self, values):
437 for klass in (Boolean, BooleanInherited):
439 obj_copied = obj.copy()
440 self.assert_copied_basic_fields(obj, obj_copied)
444 integers(min_value=1).map(tag_encode),
446 def test_stripped(self, value, tag_impl):
447 obj = Boolean(value, impl=tag_impl)
448 with self.assertRaises(NotEnoughData):
449 obj.decode(obj.encode()[:-1])
453 integers(min_value=1).map(tag_ctxc),
455 def test_stripped_expl(self, value, tag_expl):
456 obj = Boolean(value, expl=tag_expl)
457 with self.assertRaises(NotEnoughData):
458 obj.decode(obj.encode()[:-1])
461 integers(min_value=31),
462 integers(min_value=0),
465 def test_bad_tag(self, tag, offset, decode_path):
466 decode_path = tuple(str(i) for i in decode_path)
467 with self.assertRaises(DecodeError) as err:
469 tag_encode(tag)[:-1],
471 decode_path=decode_path,
474 self.assertEqual(err.exception.offset, offset)
475 self.assertEqual(err.exception.decode_path, decode_path)
478 integers(min_value=31),
479 integers(min_value=0),
482 def test_bad_expl_tag(self, tag, offset, decode_path):
483 decode_path = tuple(str(i) for i in decode_path)
484 with self.assertRaises(DecodeError) as err:
485 Boolean(expl=Boolean.tag_default).decode(
486 tag_encode(tag)[:-1],
488 decode_path=decode_path,
491 self.assertEqual(err.exception.offset, offset)
492 self.assertEqual(err.exception.decode_path, decode_path)
495 integers(min_value=128),
496 integers(min_value=0),
499 def test_bad_len(self, l, offset, decode_path):
500 decode_path = tuple(str(i) for i in decode_path)
501 with self.assertRaises(DecodeError) as err:
503 Boolean.tag_default + len_encode(l)[:-1],
505 decode_path=decode_path,
508 self.assertEqual(err.exception.offset, offset)
509 self.assertEqual(err.exception.decode_path, decode_path)
512 integers(min_value=128),
513 integers(min_value=0),
516 def test_bad_expl_len(self, l, offset, decode_path):
517 decode_path = tuple(str(i) for i in decode_path)
518 with self.assertRaises(DecodeError) as err:
519 Boolean(expl=Boolean.tag_default).decode(
520 Boolean.tag_default + len_encode(l)[:-1],
522 decode_path=decode_path,
525 self.assertEqual(err.exception.offset, offset)
526 self.assertEqual(err.exception.decode_path, decode_path)
528 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
530 boolean_values_strategy(),
532 integers(min_value=1).map(tag_ctxc),
533 integers(min_value=0),
536 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
537 for klass in (Boolean, BooleanInherited):
538 _, _, _, default, optional, _decoded = values
547 self.assertFalse(obj.expled)
548 obj_encoded = obj.encode()
549 obj_expled = obj(value, expl=tag_expl)
550 self.assertTrue(obj_expled.expled)
553 obj_expled_encoded = obj_expled.encode()
554 obj_decoded, tail = obj_expled.decode(
555 obj_expled_encoded + tail_junk,
560 self.assertEqual(tail, tail_junk)
561 self.assertEqual(obj_decoded, obj_expled)
562 self.assertNotEqual(obj_decoded, obj)
563 self.assertEqual(bool(obj_decoded), bool(obj_expled))
564 self.assertEqual(bool(obj_decoded), bool(obj))
565 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
566 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
567 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
569 obj_decoded.expl_llen,
570 len(len_encode(len(obj_encoded))),
572 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
573 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
576 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
578 self.assertEqual(obj_decoded.expl_offset, offset)
580 @given(integers(min_value=2))
581 def test_invalid_len(self, l):
582 with self.assertRaises(InvalidLength):
583 Boolean().decode(b"".join((
589 @given(integers(min_value=0 + 1, max_value=255 - 1))
590 def test_invalid_value(self, value):
591 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
592 Boolean().decode(b"".join((
600 def integer_values_strategy(draw, do_expl=False):
601 bound_min, value, default, bound_max = sorted(draw(sets(
610 _specs = draw(sets(text_letters()))
613 min_size=len(_specs),
614 max_size=len(_specs),
616 _specs = list(zip(_specs, values))
619 bounds = (bound_min, bound_max)
623 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
625 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
628 optional = draw(one_of(none(), booleans()))
630 draw(integers(min_value=0)),
631 draw(integers(min_value=0)),
632 draw(integers(min_value=0)),
634 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
637 class IntegerInherited(Integer):
641 class TestInteger(CommonMixin, TestCase):
644 def test_invalid_value_type(self):
645 with self.assertRaises(InvalidValueType) as err:
649 @given(sets(text_letters(), min_size=2))
650 def test_unknown_name(self, names_input):
651 missing = names_input.pop()
654 schema = [(n, 123) for n in names_input]
655 with self.assertRaises(ObjUnknown) as err:
659 @given(sets(text_letters(), min_size=2))
660 def test_known_name(self, names_input):
662 schema = [(n, 123) for n in names_input]
663 Int(names_input.pop())
666 def test_optional(self, optional):
667 obj = Integer(default=Integer(0), optional=optional)
668 self.assertTrue(obj.optional)
671 def test_ready(self, value):
673 self.assertFalse(obj.ready)
676 with self.assertRaises(ObjNotReady) as err:
680 self.assertTrue(obj.ready)
685 @given(integers(), integers(), binary(), binary())
686 def test_comparison(self, value1, value2, tag1, tag2):
687 for klass in (Integer, IntegerInherited):
690 self.assertEqual(obj1 == obj2, value1 == value2)
691 self.assertEqual(obj1 != obj2, value1 != value2)
692 self.assertEqual(obj1 == int(obj2), value1 == value2)
693 obj1 = klass(value1, impl=tag1)
694 obj2 = klass(value1, impl=tag2)
695 self.assertEqual(obj1 == obj2, tag1 == tag2)
696 self.assertEqual(obj1 != obj2, tag1 != tag2)
698 @given(lists(integers()))
699 def test_sorted_works(self, values):
700 self.assertSequenceEqual(
701 [int(v) for v in sorted(Integer(v) for v in values)],
705 @given(data_strategy())
706 def test_named(self, d):
707 names_input = list(d.draw(sets(text_letters(), min_size=1)))
708 values_input = list(d.draw(sets(
710 min_size=len(names_input),
711 max_size=len(names_input),
713 chosen_name = d.draw(sampled_from(names_input))
714 names_input = dict(zip(names_input, values_input))
718 _int = Int(chosen_name)
719 self.assertEqual(_int.named, chosen_name)
720 self.assertEqual(int(_int), names_input[chosen_name])
722 @given(integers(), integers(min_value=0), integers(min_value=0))
723 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
724 value = bound_min + value_delta
725 bound_max = value + bound_delta
726 Integer(value=value, bounds=(bound_min, bound_max))
728 @given(sets(integers(), min_size=3, max_size=3))
729 def test_bounds_unsatisfied(self, values):
730 values = sorted(values)
731 with self.assertRaises(BoundsError) as err:
732 Integer(value=values[0], bounds=(values[1], values[2]))
734 with self.assertRaises(BoundsError) as err:
735 Integer(value=values[2], bounds=(values[0], values[1]))
738 @given(data_strategy())
739 def test_call(self, d):
740 for klass in (Integer, IntegerInherited):
750 ) = d.draw(integer_values_strategy())
757 optional_initial or False,
770 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
771 if (default is None) and (obj_initial.default is not None):
775 (value is not None) and
776 (bounds_initial is not None) and
777 not (bounds_initial[0] <= value <= bounds_initial[1])
782 (default is not None) and
783 (bounds_initial is not None) and
784 not (bounds_initial[0] <= default <= bounds_initial[1])
787 obj = obj_initial(value, bounds, impl, expl, default, optional)
789 value_expected = default if value is None else value
791 default_initial if value_expected is None
794 self.assertEqual(obj, value_expected)
795 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
796 self.assertEqual(obj.expl_tag, expl or expl_initial)
799 default_initial if default is None else default,
801 if obj.default is None:
802 optional = optional_initial if optional is None else optional
803 optional = False if optional is None else optional
806 self.assertEqual(obj.optional, optional)
808 (obj._bound_min, obj._bound_max),
809 bounds or bounds_initial or (float("-inf"), float("+inf")),
813 {} if _specs_initial is None else dict(_specs_initial),
816 @given(integer_values_strategy())
817 def test_copy(self, values):
818 for klass in (Integer, IntegerInherited):
820 obj_copied = obj.copy()
821 self.assert_copied_basic_fields(obj, obj_copied)
822 self.assertEqual(obj.specs, obj_copied.specs)
823 self.assertEqual(obj._bound_min, obj_copied._bound_min)
824 self.assertEqual(obj._bound_max, obj_copied._bound_max)
825 self.assertEqual(obj._value, obj_copied._value)
829 integers(min_value=1).map(tag_encode),
831 def test_stripped(self, value, tag_impl):
832 obj = Integer(value, impl=tag_impl)
833 with self.assertRaises(NotEnoughData):
834 obj.decode(obj.encode()[:-1])
838 integers(min_value=1).map(tag_ctxc),
840 def test_stripped_expl(self, value, tag_expl):
841 obj = Integer(value, expl=tag_expl)
842 with self.assertRaises(NotEnoughData):
843 obj.decode(obj.encode()[:-1])
845 def test_zero_len(self):
846 with self.assertRaises(NotEnoughData):
847 Integer().decode(b"".join((
853 integers(min_value=31),
854 integers(min_value=0),
857 def test_bad_tag(self, tag, offset, decode_path):
858 decode_path = tuple(str(i) for i in decode_path)
859 with self.assertRaises(DecodeError) as err:
861 tag_encode(tag)[:-1],
863 decode_path=decode_path,
866 self.assertEqual(err.exception.offset, offset)
867 self.assertEqual(err.exception.decode_path, decode_path)
870 integers(min_value=128),
871 integers(min_value=0),
874 def test_bad_len(self, l, offset, decode_path):
875 decode_path = tuple(str(i) for i in decode_path)
876 with self.assertRaises(DecodeError) as err:
878 Integer.tag_default + len_encode(l)[:-1],
880 decode_path=decode_path,
883 self.assertEqual(err.exception.offset, offset)
884 self.assertEqual(err.exception.decode_path, decode_path)
887 sets(integers(), min_size=2, max_size=2),
888 integers(min_value=0),
891 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
892 decode_path = tuple(str(i) for i in decode_path)
893 value, bound_min = list(sorted(ints))
896 bounds = (bound_min, bound_min)
897 with self.assertRaises(DecodeError) as err:
899 Integer(value).encode(),
901 decode_path=decode_path,
904 self.assertEqual(err.exception.offset, offset)
905 self.assertEqual(err.exception.decode_path, decode_path)
907 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
909 integer_values_strategy(),
911 integers(min_value=1).map(tag_ctxc),
912 integers(min_value=0),
915 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
916 for klass in (Integer, IntegerInherited):
917 _, _, _, _, default, optional, _, _decoded = values
926 self.assertFalse(obj.expled)
927 obj_encoded = obj.encode()
928 obj_expled = obj(value, expl=tag_expl)
929 self.assertTrue(obj_expled.expled)
932 obj_expled_encoded = obj_expled.encode()
933 obj_decoded, tail = obj_expled.decode(
934 obj_expled_encoded + tail_junk,
939 self.assertEqual(tail, tail_junk)
940 self.assertEqual(obj_decoded, obj_expled)
941 self.assertNotEqual(obj_decoded, obj)
942 self.assertEqual(int(obj_decoded), int(obj_expled))
943 self.assertEqual(int(obj_decoded), int(obj))
944 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
945 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
946 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
948 obj_decoded.expl_llen,
949 len(len_encode(len(obj_encoded))),
951 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
952 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
955 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
957 self.assertEqual(obj_decoded.expl_offset, offset)
959 def test_go_vectors_valid(self):
960 for data, expect in ((
972 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
973 (b"\x80\x00\x00\x00", -2147483648),
976 Integer().decode(b"".join((
978 len_encode(len(data)),
984 def test_go_vectors_invalid(self):
989 with self.assertRaises(DecodeError):
990 Integer().decode(b"".join((
992 len_encode(len(data)),
998 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1001 if draw(booleans()):
1002 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1004 integers(min_value=0, max_value=255),
1005 min_size=len(schema),
1006 max_size=len(schema),
1008 schema = list(zip(schema, bits))
1010 def _value(value_required):
1011 if not value_required and draw(booleans()):
1013 generation_choice = 0
1015 generation_choice = draw(sampled_from((1, 2, 3)))
1016 if generation_choice == 1 or draw(booleans()):
1017 return "'%s'B" % "".join(draw(lists(
1018 sampled_from(("0", "1")),
1019 max_size=len(schema),
1021 elif generation_choice == 2 or draw(booleans()):
1022 return draw(binary(max_size=len(schema) // 8))
1023 elif generation_choice == 3 or draw(booleans()):
1024 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1026 value = _value(value_required)
1027 default = _value(value_required=False)
1031 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1033 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1034 optional = draw(one_of(none(), booleans()))
1036 draw(integers(min_value=0)),
1037 draw(integers(min_value=0)),
1038 draw(integers(min_value=0)),
1040 return (schema, value, impl, expl, default, optional, _decoded)
1043 class BitStringInherited(BitString):
1047 class TestBitString(CommonMixin, TestCase):
1048 base_klass = BitString
1050 @given(lists(booleans()))
1051 def test_b_encoding(self, bits):
1052 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1053 self.assertEqual(obj.bit_len, len(bits))
1054 self.assertSequenceEqual(list(obj), bits)
1055 for i, bit in enumerate(bits):
1056 self.assertEqual(obj[i], bit)
1058 @given(lists(booleans()))
1059 def test_out_of_bounds_bits(self, bits):
1060 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1061 for i in range(len(bits), len(bits) * 2):
1062 self.assertFalse(obj[i])
1064 def test_bad_b_encoding(self):
1065 with self.assertRaises(ValueError):
1066 BitString("'010120101'B")
1069 integers(min_value=1, max_value=255),
1070 integers(min_value=1, max_value=255),
1072 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1073 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1074 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1075 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1077 class BS(BitString):
1078 schema = (("whatever", 0),)
1079 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1080 self.assertEqual(obj.bit_len, leading_zeros + 1)
1081 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1083 def test_zero_len(self):
1084 with self.assertRaises(NotEnoughData):
1085 BitString().decode(b"".join((
1086 BitString.tag_default,
1090 def test_invalid_value_type(self):
1091 with self.assertRaises(InvalidValueType) as err:
1094 with self.assertRaises(InvalidValueType) as err:
1098 def test_obj_unknown(self):
1099 with self.assertRaises(ObjUnknown) as err:
1100 BitString(b"whatever")["whenever"]
1103 def test_get_invalid_type(self):
1104 with self.assertRaises(InvalidValueType) as err:
1105 BitString(b"whatever")[(1, 2, 3)]
1108 @given(data_strategy())
1109 def test_unknown_name(self, d):
1110 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1111 missing = _schema.pop()
1113 class BS(BitString):
1114 schema = [(n, i) for i, n in enumerate(_schema)]
1115 with self.assertRaises(ObjUnknown) as err:
1120 def test_optional(self, optional):
1121 obj = BitString(default=BitString(b""), optional=optional)
1122 self.assertTrue(obj.optional)
1125 def test_ready(self, value):
1127 self.assertFalse(obj.ready)
1130 with self.assertRaises(ObjNotReady) as err:
1133 obj = BitString(value)
1134 self.assertTrue(obj.ready)
1139 tuples(integers(min_value=0), binary()),
1140 tuples(integers(min_value=0), binary()),
1144 def test_comparison(self, value1, value2, tag1, tag2):
1145 for klass in (BitString, BitStringInherited):
1146 obj1 = klass(value1)
1147 obj2 = klass(value2)
1148 self.assertEqual(obj1 == obj2, value1 == value2)
1149 self.assertEqual(obj1 != obj2, value1 != value2)
1150 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1151 obj1 = klass(value1, impl=tag1)
1152 obj2 = klass(value1, impl=tag2)
1153 self.assertEqual(obj1 == obj2, tag1 == tag2)
1154 self.assertEqual(obj1 != obj2, tag1 != tag2)
1156 @given(data_strategy())
1157 def test_call(self, d):
1158 for klass in (BitString, BitStringInherited):
1167 ) = d.draw(bit_string_values_strategy())
1170 schema = schema_initial
1172 value=value_initial,
1175 default=default_initial,
1176 optional=optional_initial or False,
1177 _decoded=_decoded_initial,
1187 ) = d.draw(bit_string_values_strategy(
1188 schema=schema_initial,
1189 do_expl=impl_initial is None,
1198 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1199 self.assertEqual(obj.expl_tag, expl or expl_initial)
1200 if obj.default is None:
1201 optional = optional_initial if optional is None else optional
1202 optional = False if optional is None else optional
1205 self.assertEqual(obj.optional, optional)
1206 self.assertEqual(obj.specs, obj_initial.specs)
1208 @given(bit_string_values_strategy())
1209 def test_copy(self, values):
1210 for klass in (BitString, BitStringInherited):
1211 _schema, value, impl, expl, default, optional, _decoded = values
1220 optional=optional or False,
1223 obj_copied = obj.copy()
1224 self.assert_copied_basic_fields(obj, obj_copied)
1225 self.assertEqual(obj.specs, obj_copied.specs)
1226 self.assertEqual(obj._value, obj_copied._value)
1230 integers(min_value=1).map(tag_encode),
1232 def test_stripped(self, value, tag_impl):
1233 obj = BitString(value, impl=tag_impl)
1234 with self.assertRaises(NotEnoughData):
1235 obj.decode(obj.encode()[:-1])
1239 integers(min_value=1).map(tag_ctxc),
1241 def test_stripped_expl(self, value, tag_expl):
1242 obj = BitString(value, expl=tag_expl)
1243 with self.assertRaises(NotEnoughData):
1244 obj.decode(obj.encode()[:-1])
1247 integers(min_value=31),
1248 integers(min_value=0),
1251 def test_bad_tag(self, tag, offset, decode_path):
1252 decode_path = tuple(str(i) for i in decode_path)
1253 with self.assertRaises(DecodeError) as err:
1255 tag_encode(tag)[:-1],
1257 decode_path=decode_path,
1260 self.assertEqual(err.exception.offset, offset)
1261 self.assertEqual(err.exception.decode_path, decode_path)
1264 integers(min_value=128),
1265 integers(min_value=0),
1268 def test_bad_len(self, l, offset, decode_path):
1269 decode_path = tuple(str(i) for i in decode_path)
1270 with self.assertRaises(DecodeError) as err:
1272 BitString.tag_default + len_encode(l)[:-1],
1274 decode_path=decode_path,
1277 self.assertEqual(err.exception.offset, offset)
1278 self.assertEqual(err.exception.decode_path, decode_path)
1280 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1281 @given(data_strategy())
1282 def test_symmetric(self, d):
1291 ) = d.draw(bit_string_values_strategy(value_required=True))
1292 tail_junk = d.draw(binary(max_size=5))
1293 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1294 offset = d.draw(integers(min_value=0))
1295 for klass in (BitString, BitStringInherited):
1306 self.assertFalse(obj.expled)
1307 obj_encoded = obj.encode()
1308 obj_expled = obj(value, expl=tag_expl)
1309 self.assertTrue(obj_expled.expled)
1312 obj_expled_encoded = obj_expled.encode()
1313 obj_decoded, tail = obj_expled.decode(
1314 obj_expled_encoded + tail_junk,
1319 self.assertEqual(tail, tail_junk)
1320 self.assertEqual(obj_decoded, obj_expled)
1321 self.assertNotEqual(obj_decoded, obj)
1322 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1323 self.assertEqual(bytes(obj_decoded), bytes(obj))
1324 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1325 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1326 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1328 obj_decoded.expl_llen,
1329 len(len_encode(len(obj_encoded))),
1331 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1332 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1335 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1337 self.assertEqual(obj_decoded.expl_offset, offset)
1338 if isinstance(value, tuple):
1339 self.assertSetEqual(set(value), set(obj_decoded.named))
1343 @given(integers(min_value=1, max_value=255))
1344 def test_bad_zero_value(self, pad_size):
1345 with self.assertRaises(DecodeError):
1346 BitString().decode(b"".join((
1347 BitString.tag_default,
1352 def test_go_vectors_invalid(self):
1358 with self.assertRaises(DecodeError):
1359 BitString().decode(b"".join((
1360 BitString.tag_default,
1365 def test_go_vectors_valid(self):
1366 obj, _ = BitString().decode(b"".join((
1367 BitString.tag_default,
1371 self.assertEqual(bytes(obj), b"")
1372 self.assertEqual(obj.bit_len, 0)
1374 obj, _ = BitString().decode(b"".join((
1375 BitString.tag_default,
1379 self.assertEqual(bytes(obj), b"\x00")
1380 self.assertEqual(obj.bit_len, 1)
1382 obj = BitString((16, b"\x82\x40"))
1383 self.assertTrue(obj[0])
1384 self.assertFalse(obj[1])
1385 self.assertTrue(obj[6])
1386 self.assertTrue(obj[9])
1387 self.assertFalse(obj[17])
1391 def octet_string_values_strategy(draw, do_expl=False):
1392 bound_min, bound_max = sorted(draw(sets(
1393 integers(min_value=0, max_value=1 << 7),
1397 value = draw(one_of(
1399 binary(min_size=bound_min, max_size=bound_max),
1401 default = draw(one_of(
1403 binary(min_size=bound_min, max_size=bound_max),
1406 if draw(booleans()):
1407 bounds = (bound_min, bound_max)
1411 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1413 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1414 optional = draw(one_of(none(), booleans()))
1416 draw(integers(min_value=0)),
1417 draw(integers(min_value=0)),
1418 draw(integers(min_value=0)),
1420 return (value, bounds, impl, expl, default, optional, _decoded)
1423 class OctetStringInherited(OctetString):
1427 class TestOctetString(CommonMixin, TestCase):
1428 base_klass = OctetString
1430 def test_invalid_value_type(self):
1431 with self.assertRaises(InvalidValueType) as err:
1432 OctetString(text_type(123))
1436 def test_optional(self, optional):
1437 obj = OctetString(default=OctetString(b""), optional=optional)
1438 self.assertTrue(obj.optional)
1441 def test_ready(self, value):
1443 self.assertFalse(obj.ready)
1446 with self.assertRaises(ObjNotReady) as err:
1449 obj = OctetString(value)
1450 self.assertTrue(obj.ready)
1454 @given(binary(), binary(), binary(), binary())
1455 def test_comparison(self, value1, value2, tag1, tag2):
1456 for klass in (OctetString, OctetStringInherited):
1457 obj1 = klass(value1)
1458 obj2 = klass(value2)
1459 self.assertEqual(obj1 == obj2, value1 == value2)
1460 self.assertEqual(obj1 != obj2, value1 != value2)
1461 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1462 obj1 = klass(value1, impl=tag1)
1463 obj2 = klass(value1, impl=tag2)
1464 self.assertEqual(obj1 == obj2, tag1 == tag2)
1465 self.assertEqual(obj1 != obj2, tag1 != tag2)
1467 @given(lists(binary()))
1468 def test_sorted_works(self, values):
1469 self.assertSequenceEqual(
1470 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1474 @given(data_strategy())
1475 def test_bounds_satisfied(self, d):
1476 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1477 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1478 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1479 OctetString(value=value, bounds=(bound_min, bound_max))
1481 @given(data_strategy())
1482 def test_bounds_unsatisfied(self, d):
1483 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1484 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1485 value = d.draw(binary(max_size=bound_min - 1))
1486 with self.assertRaises(BoundsError) as err:
1487 OctetString(value=value, bounds=(bound_min, bound_max))
1489 value = d.draw(binary(min_size=bound_max + 1))
1490 with self.assertRaises(BoundsError) as err:
1491 OctetString(value=value, bounds=(bound_min, bound_max))
1494 @given(data_strategy())
1495 def test_call(self, d):
1496 for klass in (OctetString, OctetStringInherited):
1505 ) = d.draw(octet_string_values_strategy())
1506 obj_initial = klass(
1512 optional_initial or False,
1523 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1524 if (default is None) and (obj_initial.default is not None):
1527 (bounds is None) and
1528 (value is not None) and
1529 (bounds_initial is not None) and
1530 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1534 (bounds is None) and
1535 (default is not None) and
1536 (bounds_initial is not None) and
1537 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1540 obj = obj_initial(value, bounds, impl, expl, default, optional)
1542 value_expected = default if value is None else value
1544 default_initial if value_expected is None
1547 self.assertEqual(obj, value_expected)
1548 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1549 self.assertEqual(obj.expl_tag, expl or expl_initial)
1552 default_initial if default is None else default,
1554 if obj.default is None:
1555 optional = optional_initial if optional is None else optional
1556 optional = False if optional is None else optional
1559 self.assertEqual(obj.optional, optional)
1561 (obj._bound_min, obj._bound_max),
1562 bounds or bounds_initial or (0, float("+inf")),
1565 @given(octet_string_values_strategy())
1566 def test_copy(self, values):
1567 for klass in (OctetString, OctetStringInherited):
1568 obj = klass(*values)
1569 obj_copied = obj.copy()
1570 self.assert_copied_basic_fields(obj, obj_copied)
1571 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1572 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1573 self.assertEqual(obj._value, obj_copied._value)
1577 integers(min_value=1).map(tag_encode),
1579 def test_stripped(self, value, tag_impl):
1580 obj = OctetString(value, impl=tag_impl)
1581 with self.assertRaises(NotEnoughData):
1582 obj.decode(obj.encode()[:-1])
1586 integers(min_value=1).map(tag_ctxc),
1588 def test_stripped_expl(self, value, tag_expl):
1589 obj = OctetString(value, expl=tag_expl)
1590 with self.assertRaises(NotEnoughData):
1591 obj.decode(obj.encode()[:-1])
1594 integers(min_value=31),
1595 integers(min_value=0),
1598 def test_bad_tag(self, tag, offset, decode_path):
1599 decode_path = tuple(str(i) for i in decode_path)
1600 with self.assertRaises(DecodeError) as err:
1601 OctetString().decode(
1602 tag_encode(tag)[:-1],
1604 decode_path=decode_path,
1607 self.assertEqual(err.exception.offset, offset)
1608 self.assertEqual(err.exception.decode_path, decode_path)
1611 integers(min_value=128),
1612 integers(min_value=0),
1615 def test_bad_len(self, l, offset, decode_path):
1616 decode_path = tuple(str(i) for i in decode_path)
1617 with self.assertRaises(DecodeError) as err:
1618 OctetString().decode(
1619 OctetString.tag_default + len_encode(l)[:-1],
1621 decode_path=decode_path,
1624 self.assertEqual(err.exception.offset, offset)
1625 self.assertEqual(err.exception.decode_path, decode_path)
1628 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1629 integers(min_value=0),
1632 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1633 decode_path = tuple(str(i) for i in decode_path)
1634 value, bound_min = list(sorted(ints))
1636 class String(OctetString):
1637 bounds = (bound_min, bound_min)
1638 with self.assertRaises(DecodeError) as err:
1640 OctetString(b"\x00" * value).encode(),
1642 decode_path=decode_path,
1645 self.assertEqual(err.exception.offset, offset)
1646 self.assertEqual(err.exception.decode_path, decode_path)
1648 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1650 octet_string_values_strategy(),
1652 integers(min_value=1).map(tag_ctxc),
1653 integers(min_value=0),
1656 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1657 for klass in (OctetString, OctetStringInherited):
1658 _, _, _, _, default, optional, _decoded = values
1667 self.assertFalse(obj.expled)
1668 obj_encoded = obj.encode()
1669 obj_expled = obj(value, expl=tag_expl)
1670 self.assertTrue(obj_expled.expled)
1673 obj_expled_encoded = obj_expled.encode()
1674 obj_decoded, tail = obj_expled.decode(
1675 obj_expled_encoded + tail_junk,
1680 self.assertEqual(tail, tail_junk)
1681 self.assertEqual(obj_decoded, obj_expled)
1682 self.assertNotEqual(obj_decoded, obj)
1683 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1684 self.assertEqual(bytes(obj_decoded), bytes(obj))
1685 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1686 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1687 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1689 obj_decoded.expl_llen,
1690 len(len_encode(len(obj_encoded))),
1692 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1693 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1696 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1698 self.assertEqual(obj_decoded.expl_offset, offset)
1702 def null_values_strategy(draw, do_expl=False):
1706 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1708 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1709 optional = draw(one_of(none(), booleans()))
1711 draw(integers(min_value=0)),
1712 draw(integers(min_value=0)),
1713 draw(integers(min_value=0)),
1715 return (impl, expl, optional, _decoded)
1718 class NullInherited(Null):
1722 class TestNull(CommonMixin, TestCase):
1725 def test_ready(self):
1727 self.assertTrue(obj.ready)
1731 @given(binary(), binary())
1732 def test_comparison(self, tag1, tag2):
1733 for klass in (Null, NullInherited):
1734 obj1 = klass(impl=tag1)
1735 obj2 = klass(impl=tag2)
1736 self.assertEqual(obj1 == obj2, tag1 == tag2)
1737 self.assertEqual(obj1 != obj2, tag1 != tag2)
1738 self.assertNotEqual(obj1, tag2)
1740 @given(data_strategy())
1741 def test_call(self, d):
1742 for klass in (Null, NullInherited):
1748 ) = d.draw(null_values_strategy())
1749 obj_initial = klass(
1752 optional=optional_initial or False,
1753 _decoded=_decoded_initial,
1760 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
1761 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1762 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1763 self.assertEqual(obj.expl_tag, expl or expl_initial)
1764 optional = optional_initial if optional is None else optional
1765 optional = False if optional is None else optional
1766 self.assertEqual(obj.optional, optional)
1768 @given(null_values_strategy())
1769 def test_copy(self, values):
1770 for klass in (Null, NullInherited):
1771 impl, expl, optional, _decoded = values
1775 optional=optional or False,
1778 obj_copied = obj.copy()
1779 self.assert_copied_basic_fields(obj, obj_copied)
1781 @given(integers(min_value=1).map(tag_encode))
1782 def test_stripped(self, tag_impl):
1783 obj = Null(impl=tag_impl)
1784 with self.assertRaises(NotEnoughData):
1785 obj.decode(obj.encode()[:-1])
1787 @given(integers(min_value=1).map(tag_ctxc))
1788 def test_stripped_expl(self, tag_expl):
1789 obj = Null(expl=tag_expl)
1790 with self.assertRaises(NotEnoughData):
1791 obj.decode(obj.encode()[:-1])
1794 integers(min_value=31),
1795 integers(min_value=0),
1798 def test_bad_tag(self, tag, offset, decode_path):
1799 decode_path = tuple(str(i) for i in decode_path)
1800 with self.assertRaises(DecodeError) as err:
1802 tag_encode(tag)[:-1],
1804 decode_path=decode_path,
1807 self.assertEqual(err.exception.offset, offset)
1808 self.assertEqual(err.exception.decode_path, decode_path)
1811 integers(min_value=128),
1812 integers(min_value=0),
1815 def test_bad_len(self, l, offset, decode_path):
1816 decode_path = tuple(str(i) for i in decode_path)
1817 with self.assertRaises(DecodeError) as err:
1819 Null.tag_default + len_encode(l)[:-1],
1821 decode_path=decode_path,
1824 self.assertEqual(err.exception.offset, offset)
1825 self.assertEqual(err.exception.decode_path, decode_path)
1827 @given(binary(min_size=1))
1828 def test_tag_mismatch(self, impl):
1829 assume(impl != Null.tag_default)
1830 with self.assertRaises(TagMismatch):
1831 Null(impl=impl).decode(Null().encode())
1834 null_values_strategy(),
1835 integers(min_value=1).map(tag_ctxc),
1836 integers(min_value=0),
1839 def test_symmetric(self, values, tag_expl, offset, tail_junk):
1840 for klass in (Null, NullInherited):
1841 _, _, optional, _decoded = values
1842 obj = klass(optional=optional, _decoded=_decoded)
1845 self.assertFalse(obj.expled)
1846 obj_encoded = obj.encode()
1847 obj_expled = obj(expl=tag_expl)
1848 self.assertTrue(obj_expled.expled)
1851 obj_expled_encoded = obj_expled.encode()
1852 obj_decoded, tail = obj_expled.decode(
1853 obj_expled_encoded + tail_junk,
1858 self.assertEqual(tail, tail_junk)
1859 self.assertEqual(obj_decoded, obj_expled)
1860 self.assertNotEqual(obj_decoded, obj)
1861 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1862 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1863 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1865 obj_decoded.expl_llen,
1866 len(len_encode(len(obj_encoded))),
1868 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1869 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1872 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1874 self.assertEqual(obj_decoded.expl_offset, offset)
1876 @given(integers(min_value=1))
1877 def test_invalid_len(self, l):
1878 with self.assertRaises(InvalidLength):
1879 Null().decode(b"".join((
1886 def oid_strategy(draw):
1887 first_arc = draw(integers(min_value=0, max_value=2))
1889 if first_arc in (0, 1):
1890 second_arc = draw(integers(min_value=0, max_value=39))
1892 second_arc = draw(integers(min_value=0))
1893 other_arcs = draw(lists(integers(min_value=0)))
1894 return tuple([first_arc, second_arc] + other_arcs)
1898 def oid_values_strategy(draw, do_expl=False):
1899 value = draw(one_of(none(), oid_strategy()))
1903 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1905 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1906 default = draw(one_of(none(), oid_strategy()))
1907 optional = draw(one_of(none(), booleans()))
1909 draw(integers(min_value=0)),
1910 draw(integers(min_value=0)),
1911 draw(integers(min_value=0)),
1913 return (value, impl, expl, default, optional, _decoded)
1916 class ObjectIdentifierInherited(ObjectIdentifier):
1920 class TestObjectIdentifier(CommonMixin, TestCase):
1921 base_klass = ObjectIdentifier
1923 def test_invalid_value_type(self):
1924 with self.assertRaises(InvalidValueType) as err:
1925 ObjectIdentifier(123)
1929 def test_optional(self, optional):
1930 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
1931 self.assertTrue(obj.optional)
1933 @given(oid_strategy())
1934 def test_ready(self, value):
1935 obj = ObjectIdentifier()
1936 self.assertFalse(obj.ready)
1939 with self.assertRaises(ObjNotReady) as err:
1942 obj = ObjectIdentifier(value)
1943 self.assertTrue(obj.ready)
1948 @given(oid_strategy(), oid_strategy(), binary(), binary())
1949 def test_comparison(self, value1, value2, tag1, tag2):
1950 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1951 obj1 = klass(value1)
1952 obj2 = klass(value2)
1953 self.assertEqual(obj1 == obj2, value1 == value2)
1954 self.assertEqual(obj1 != obj2, value1 != value2)
1955 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
1956 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
1957 obj1 = klass(value1, impl=tag1)
1958 obj2 = klass(value1, impl=tag2)
1959 self.assertEqual(obj1 == obj2, tag1 == tag2)
1960 self.assertEqual(obj1 != obj2, tag1 != tag2)
1962 @given(lists(oid_strategy()))
1963 def test_sorted_works(self, values):
1964 self.assertSequenceEqual(
1965 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
1969 @given(data_strategy())
1970 def test_call(self, d):
1971 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1979 ) = d.draw(oid_values_strategy())
1980 obj_initial = klass(
1981 value=value_initial,
1984 default=default_initial,
1985 optional=optional_initial or False,
1986 _decoded=_decoded_initial,
1995 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2004 value_expected = default if value is None else value
2006 default_initial if value_expected is None
2009 self.assertEqual(obj, value_expected)
2010 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2011 self.assertEqual(obj.expl_tag, expl or expl_initial)
2014 default_initial if default is None else default,
2016 if obj.default is None:
2017 optional = optional_initial if optional is None else optional
2018 optional = False if optional is None else optional
2021 self.assertEqual(obj.optional, optional)
2023 @given(oid_values_strategy())
2024 def test_copy(self, values):
2025 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2042 obj_copied = obj.copy()
2043 self.assert_copied_basic_fields(obj, obj_copied)
2044 self.assertEqual(obj._value, obj_copied._value)
2046 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2049 integers(min_value=1).map(tag_encode),
2051 def test_stripped(self, value, tag_impl):
2052 obj = ObjectIdentifier(value, impl=tag_impl)
2053 with self.assertRaises(NotEnoughData):
2054 obj.decode(obj.encode()[:-1])
2058 integers(min_value=1).map(tag_ctxc),
2060 def test_stripped_expl(self, value, tag_expl):
2061 obj = ObjectIdentifier(value, expl=tag_expl)
2062 with self.assertRaises(NotEnoughData):
2063 obj.decode(obj.encode()[:-1])
2066 integers(min_value=31),
2067 integers(min_value=0),
2070 def test_bad_tag(self, tag, offset, decode_path):
2071 decode_path = tuple(str(i) for i in decode_path)
2072 with self.assertRaises(DecodeError) as err:
2073 ObjectIdentifier().decode(
2074 tag_encode(tag)[:-1],
2076 decode_path=decode_path,
2079 self.assertEqual(err.exception.offset, offset)
2080 self.assertEqual(err.exception.decode_path, decode_path)
2083 integers(min_value=128),
2084 integers(min_value=0),
2087 def test_bad_len(self, l, offset, decode_path):
2088 decode_path = tuple(str(i) for i in decode_path)
2089 with self.assertRaises(DecodeError) as err:
2090 ObjectIdentifier().decode(
2091 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2093 decode_path=decode_path,
2096 self.assertEqual(err.exception.offset, offset)
2097 self.assertEqual(err.exception.decode_path, decode_path)
2099 def test_zero_oid(self):
2100 with self.assertRaises(NotEnoughData):
2101 ObjectIdentifier().decode(
2102 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2105 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2106 @given(oid_strategy())
2107 def test_unfinished_oid(self, value):
2108 assume(list(value)[-1] > 255)
2109 obj_encoded = ObjectIdentifier(value).encode()
2110 obj, _ = ObjectIdentifier().decode(obj_encoded)
2111 data = obj_encoded[obj.tlen + obj.llen:-1]
2113 ObjectIdentifier.tag_default,
2114 len_encode(len(data)),
2117 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2120 @given(integers(min_value=0))
2121 def test_invalid_short(self, value):
2122 with self.assertRaises(InvalidOID):
2123 ObjectIdentifier((value,))
2124 with self.assertRaises(InvalidOID):
2125 ObjectIdentifier("%d" % value)
2127 @given(integers(min_value=3), integers(min_value=0))
2128 def test_invalid_first_arc(self, first_arc, second_arc):
2129 with self.assertRaises(InvalidOID):
2130 ObjectIdentifier((first_arc, second_arc))
2131 with self.assertRaises(InvalidOID):
2132 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2134 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2135 def test_invalid_second_arc(self, first_arc, second_arc):
2136 with self.assertRaises(InvalidOID):
2137 ObjectIdentifier((first_arc, second_arc))
2138 with self.assertRaises(InvalidOID):
2139 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2141 @given(text(alphabet=ascii_letters + ".", min_size=1))
2142 def test_junk(self, oid):
2143 with self.assertRaises(InvalidOID):
2144 ObjectIdentifier(oid)
2146 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2147 @given(oid_strategy())
2148 def test_validness(self, oid):
2149 obj = ObjectIdentifier(oid)
2150 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2155 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2157 oid_values_strategy(),
2159 integers(min_value=1).map(tag_ctxc),
2160 integers(min_value=0),
2163 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2164 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2165 _, _, _, default, optional, _decoded = values
2174 self.assertFalse(obj.expled)
2175 obj_encoded = obj.encode()
2176 obj_expled = obj(value, expl=tag_expl)
2177 self.assertTrue(obj_expled.expled)
2180 obj_expled_encoded = obj_expled.encode()
2181 obj_decoded, tail = obj_expled.decode(
2182 obj_expled_encoded + tail_junk,
2187 self.assertEqual(tail, tail_junk)
2188 self.assertEqual(obj_decoded, obj_expled)
2189 self.assertNotEqual(obj_decoded, obj)
2190 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2191 self.assertEqual(tuple(obj_decoded), tuple(obj))
2192 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2193 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2194 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2196 obj_decoded.expl_llen,
2197 len(len_encode(len(obj_encoded))),
2199 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2200 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2203 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2205 self.assertEqual(obj_decoded.expl_offset, offset)
2208 oid_strategy().map(ObjectIdentifier),
2209 oid_strategy().map(ObjectIdentifier),
2211 def test_add(self, oid1, oid2):
2212 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2213 for oid_to_add in (oid2, tuple(oid2)):
2214 self.assertEqual(oid1 + oid_to_add, oid_expect)
2215 with self.assertRaises(InvalidValueType):
2218 def test_go_vectors_valid(self):
2219 for data, expect in (
2221 (b"\x55\x02", (2, 5, 2)),
2222 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2223 (b"\x81\x34\x03", (2, 100, 3)),
2226 ObjectIdentifier().decode(b"".join((
2227 ObjectIdentifier.tag_default,
2228 len_encode(len(data)),
2234 def test_go_vectors_invalid(self):
2235 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2236 with self.assertRaises(DecodeError):
2237 ObjectIdentifier().decode(b"".join((
2238 Integer.tag_default,
2239 len_encode(len(data)),
2245 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2247 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2248 values = list(draw(sets(
2250 min_size=len(schema),
2251 max_size=len(schema),
2253 schema = list(zip(schema, values))
2254 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2258 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2260 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2261 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2262 optional = draw(one_of(none(), booleans()))
2264 draw(integers(min_value=0)),
2265 draw(integers(min_value=0)),
2266 draw(integers(min_value=0)),
2268 return (schema, value, impl, expl, default, optional, _decoded)
2271 class TestEnumerated(CommonMixin, TestCase):
2272 class EWhatever(Enumerated):
2273 schema = (("whatever", 0),)
2275 base_klass = EWhatever
2277 def test_schema_required(self):
2278 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2281 def test_invalid_value_type(self):
2282 with self.assertRaises(InvalidValueType) as err:
2283 self.base_klass((1, 2))
2286 @given(sets(text_letters(), min_size=2))
2287 def test_unknown_name(self, schema_input):
2288 missing = schema_input.pop()
2290 class E(Enumerated):
2291 schema = [(n, 123) for n in schema_input]
2292 with self.assertRaises(ObjUnknown) as err:
2297 sets(text_letters(), min_size=2),
2298 sets(integers(), min_size=2),
2300 def test_unknown_value(self, schema_input, values_input):
2302 missing_value = values_input.pop()
2303 _input = list(zip(schema_input, values_input))
2305 class E(Enumerated):
2307 with self.assertRaises(DecodeError) as err:
2312 def test_optional(self, optional):
2313 obj = self.base_klass(default="whatever", optional=optional)
2314 self.assertTrue(obj.optional)
2316 def test_ready(self):
2317 obj = self.base_klass()
2318 self.assertFalse(obj.ready)
2321 with self.assertRaises(ObjNotReady) as err:
2324 obj = self.base_klass("whatever")
2325 self.assertTrue(obj.ready)
2329 @given(integers(), integers(), binary(), binary())
2330 def test_comparison(self, value1, value2, tag1, tag2):
2331 class E(Enumerated):
2333 ("whatever0", value1),
2334 ("whatever1", value2),
2337 class EInherited(E):
2339 for klass in (E, EInherited):
2340 obj1 = klass(value1)
2341 obj2 = klass(value2)
2342 self.assertEqual(obj1 == obj2, value1 == value2)
2343 self.assertEqual(obj1 != obj2, value1 != value2)
2344 self.assertEqual(obj1 == int(obj2), value1 == value2)
2345 obj1 = klass(value1, impl=tag1)
2346 obj2 = klass(value1, impl=tag2)
2347 self.assertEqual(obj1 == obj2, tag1 == tag2)
2348 self.assertEqual(obj1 != obj2, tag1 != tag2)
2350 @given(data_strategy())
2351 def test_call(self, d):
2360 ) = d.draw(enumerated_values_strategy())
2362 class E(Enumerated):
2363 schema = schema_initial
2365 value=value_initial,
2368 default=default_initial,
2369 optional=optional_initial or False,
2370 _decoded=_decoded_initial,
2380 ) = d.draw(enumerated_values_strategy(
2381 schema=schema_initial,
2382 do_expl=impl_initial is None,
2392 value_expected = default if value is None else value
2394 default_initial if value_expected is None
2399 dict(schema_initial).get(value_expected, value_expected),
2401 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2402 self.assertEqual(obj.expl_tag, expl or expl_initial)
2405 default_initial if default is None else default,
2407 if obj.default is None:
2408 optional = optional_initial if optional is None else optional
2409 optional = False if optional is None else optional
2412 self.assertEqual(obj.optional, optional)
2413 self.assertEqual(obj.specs, dict(schema_initial))
2415 @given(enumerated_values_strategy())
2416 def test_copy(self, values):
2417 schema_input, value, impl, expl, default, optional, _decoded = values
2419 class E(Enumerated):
2420 schema = schema_input
2429 obj_copied = obj.copy()
2430 self.assert_copied_basic_fields(obj, obj_copied)
2431 self.assertEqual(obj.specs, obj_copied.specs)
2433 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2434 @given(data_strategy())
2435 def test_symmetric(self, d):
2436 schema_input, _, _, _, default, optional, _decoded = d.draw(
2437 enumerated_values_strategy(),
2439 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2440 offset = d.draw(integers(min_value=0))
2441 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2442 tail_junk = d.draw(binary(max_size=5))
2444 class E(Enumerated):
2445 schema = schema_input
2454 self.assertFalse(obj.expled)
2455 obj_encoded = obj.encode()
2456 obj_expled = obj(value, expl=tag_expl)
2457 self.assertTrue(obj_expled.expled)
2460 obj_expled_encoded = obj_expled.encode()
2461 obj_decoded, tail = obj_expled.decode(
2462 obj_expled_encoded + tail_junk,
2467 self.assertEqual(tail, tail_junk)
2468 self.assertEqual(obj_decoded, obj_expled)
2469 self.assertNotEqual(obj_decoded, obj)
2470 self.assertEqual(int(obj_decoded), int(obj_expled))
2471 self.assertEqual(int(obj_decoded), int(obj))
2472 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2473 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2474 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2476 obj_decoded.expl_llen,
2477 len(len_encode(len(obj_encoded))),
2479 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2480 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2483 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2485 self.assertEqual(obj_decoded.expl_offset, offset)
2489 def string_values_strategy(draw, alphabet, do_expl=False):
2490 bound_min, bound_max = sorted(draw(sets(
2491 integers(min_value=0, max_value=1 << 7),
2495 value = draw(one_of(
2497 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2499 default = draw(one_of(
2501 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2504 if draw(booleans()):
2505 bounds = (bound_min, bound_max)
2509 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2511 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2512 optional = draw(one_of(none(), booleans()))
2514 draw(integers(min_value=0)),
2515 draw(integers(min_value=0)),
2516 draw(integers(min_value=0)),
2518 return (value, bounds, impl, expl, default, optional, _decoded)
2521 class StringMixin(object):
2522 def test_invalid_value_type(self):
2523 with self.assertRaises(InvalidValueType) as err:
2524 self.base_klass((1, 2))
2527 def text_alphabet(self):
2528 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2529 return printable + whitespace
2533 def test_optional(self, optional):
2534 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2535 self.assertTrue(obj.optional)
2537 @given(data_strategy())
2538 def test_ready(self, d):
2539 obj = self.base_klass()
2540 self.assertFalse(obj.ready)
2544 with self.assertRaises(ObjNotReady) as err:
2547 value = d.draw(text(alphabet=self.text_alphabet()))
2548 obj = self.base_klass(value)
2549 self.assertTrue(obj.ready)
2554 @given(data_strategy())
2555 def test_comparison(self, d):
2556 value1 = d.draw(text(alphabet=self.text_alphabet()))
2557 value2 = d.draw(text(alphabet=self.text_alphabet()))
2558 tag1 = d.draw(binary())
2559 tag2 = d.draw(binary())
2560 obj1 = self.base_klass(value1)
2561 obj2 = self.base_klass(value2)
2562 self.assertEqual(obj1 == obj2, value1 == value2)
2563 self.assertEqual(obj1 != obj2, value1 != value2)
2564 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2565 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2566 obj1 = self.base_klass(value1, impl=tag1)
2567 obj2 = self.base_klass(value1, impl=tag2)
2568 self.assertEqual(obj1 == obj2, tag1 == tag2)
2569 self.assertEqual(obj1 != obj2, tag1 != tag2)
2571 @given(data_strategy())
2572 def test_bounds_satisfied(self, d):
2573 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2574 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2575 value = d.draw(text(
2576 alphabet=self.text_alphabet(),
2580 self.base_klass(value=value, bounds=(bound_min, bound_max))
2582 @given(data_strategy())
2583 def test_bounds_unsatisfied(self, d):
2584 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2585 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2586 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2587 with self.assertRaises(BoundsError) as err:
2588 self.base_klass(value=value, bounds=(bound_min, bound_max))
2590 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2591 with self.assertRaises(BoundsError) as err:
2592 self.base_klass(value=value, bounds=(bound_min, bound_max))
2595 @given(data_strategy())
2596 def test_call(self, d):
2605 ) = d.draw(string_values_strategy(self.text_alphabet()))
2606 obj_initial = self.base_klass(
2612 optional_initial or False,
2623 ) = d.draw(string_values_strategy(
2624 self.text_alphabet(),
2625 do_expl=impl_initial is None,
2627 if (default is None) and (obj_initial.default is not None):
2630 (bounds is None) and
2631 (value is not None) and
2632 (bounds_initial is not None) and
2633 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2637 (bounds is None) and
2638 (default is not None) and
2639 (bounds_initial is not None) and
2640 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2643 obj = obj_initial(value, bounds, impl, expl, default, optional)
2645 value_expected = default if value is None else value
2647 default_initial if value_expected is None
2650 self.assertEqual(obj, value_expected)
2651 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2652 self.assertEqual(obj.expl_tag, expl or expl_initial)
2655 default_initial if default is None else default,
2657 if obj.default is None:
2658 optional = optional_initial if optional is None else optional
2659 optional = False if optional is None else optional
2662 self.assertEqual(obj.optional, optional)
2664 (obj._bound_min, obj._bound_max),
2665 bounds or bounds_initial or (0, float("+inf")),
2668 @given(data_strategy())
2669 def test_copy(self, d):
2670 values = d.draw(string_values_strategy(self.text_alphabet()))
2671 obj = self.base_klass(*values)
2672 obj_copied = obj.copy()
2673 self.assert_copied_basic_fields(obj, obj_copied)
2674 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2675 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2676 self.assertEqual(obj._value, obj_copied._value)
2678 @given(data_strategy())
2679 def test_stripped(self, d):
2680 value = d.draw(text(alphabet=self.text_alphabet()))
2681 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2682 obj = self.base_klass(value, impl=tag_impl)
2683 with self.assertRaises(NotEnoughData):
2684 obj.decode(obj.encode()[:-1])
2686 @given(data_strategy())
2687 def test_stripped_expl(self, d):
2688 value = d.draw(text(alphabet=self.text_alphabet()))
2689 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2690 obj = self.base_klass(value, expl=tag_expl)
2691 with self.assertRaises(NotEnoughData):
2692 obj.decode(obj.encode()[:-1])
2695 integers(min_value=31),
2696 integers(min_value=0),
2699 def test_bad_tag(self, tag, offset, decode_path):
2700 decode_path = tuple(str(i) for i in decode_path)
2701 with self.assertRaises(DecodeError) as err:
2702 self.base_klass().decode(
2703 tag_encode(tag)[:-1],
2705 decode_path=decode_path,
2708 self.assertEqual(err.exception.offset, offset)
2709 self.assertEqual(err.exception.decode_path, decode_path)
2712 integers(min_value=128),
2713 integers(min_value=0),
2716 def test_bad_len(self, l, offset, decode_path):
2717 decode_path = tuple(str(i) for i in decode_path)
2718 with self.assertRaises(DecodeError) as err:
2719 self.base_klass().decode(
2720 self.base_klass.tag_default + len_encode(l)[:-1],
2722 decode_path=decode_path,
2725 self.assertEqual(err.exception.offset, offset)
2726 self.assertEqual(err.exception.decode_path, decode_path)
2729 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2730 integers(min_value=0),
2733 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2734 decode_path = tuple(str(i) for i in decode_path)
2735 value, bound_min = list(sorted(ints))
2737 class String(self.base_klass):
2738 # Multiply this value by four, to satisfy UTF-32 bounds
2739 # (4 bytes per character) validation
2740 bounds = (bound_min * 4, bound_min * 4)
2741 with self.assertRaises(DecodeError) as err:
2743 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2745 decode_path=decode_path,
2748 self.assertEqual(err.exception.offset, offset)
2749 self.assertEqual(err.exception.decode_path, decode_path)
2751 @given(data_strategy())
2752 def test_symmetric(self, d):
2753 values = d.draw(string_values_strategy(self.text_alphabet()))
2754 value = d.draw(text(alphabet=self.text_alphabet()))
2755 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2756 offset = d.draw(integers(min_value=0))
2757 tail_junk = d.draw(binary(max_size=5))
2758 _, _, _, _, default, optional, _decoded = values
2759 obj = self.base_klass(
2767 self.assertFalse(obj.expled)
2768 obj_encoded = obj.encode()
2769 obj_expled = obj(value, expl=tag_expl)
2770 self.assertTrue(obj_expled.expled)
2773 obj_expled_encoded = obj_expled.encode()
2774 obj_decoded, tail = obj_expled.decode(
2775 obj_expled_encoded + tail_junk,
2780 self.assertEqual(tail, tail_junk)
2781 self.assertEqual(obj_decoded, obj_expled)
2782 self.assertNotEqual(obj_decoded, obj)
2783 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2784 self.assertEqual(bytes(obj_decoded), bytes(obj))
2785 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2786 self.assertEqual(text_type(obj_decoded), text_type(obj))
2787 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2788 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2789 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2791 obj_decoded.expl_llen,
2792 len(len_encode(len(obj_encoded))),
2794 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2795 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2798 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2800 self.assertEqual(obj_decoded.expl_offset, offset)
2803 class TestUTF8String(StringMixin, CommonMixin, TestCase):
2804 base_klass = UTF8String
2807 class UnicodeDecodeErrorMixin(object):
2809 alphabet=''.join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
2813 def test_unicode_decode_error(self, cyrillic_text):
2814 with self.assertRaises(DecodeError):
2815 self.base_klass(cyrillic_text)
2818 class TestNumericString(StringMixin, CommonMixin, TestCase):
2819 base_klass = NumericString
2821 def text_alphabet(self):
2824 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
2825 def test_non_numeric(self, cyrillic_text):
2826 with assertRaisesRegex(self, DecodeError, "non-numeric"):
2827 self.base_klass(cyrillic_text)
2830 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2831 integers(min_value=0),
2834 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2835 decode_path = tuple(str(i) for i in decode_path)
2836 value, bound_min = list(sorted(ints))
2838 class String(self.base_klass):
2839 bounds = (bound_min, bound_min)
2840 with self.assertRaises(DecodeError) as err:
2842 self.base_klass(b"1" * value).encode(),
2844 decode_path=decode_path,
2847 self.assertEqual(err.exception.offset, offset)
2848 self.assertEqual(err.exception.decode_path, decode_path)
2851 class TestPrintableString(
2852 UnicodeDecodeErrorMixin,
2857 base_klass = PrintableString
2860 class TestTeletexString(
2861 UnicodeDecodeErrorMixin,
2866 base_klass = TeletexString
2869 class TestVideotexString(
2870 UnicodeDecodeErrorMixin,
2875 base_klass = VideotexString
2878 class TestIA5String(
2879 UnicodeDecodeErrorMixin,
2884 base_klass = IA5String
2887 class TestGraphicString(
2888 UnicodeDecodeErrorMixin,
2893 base_klass = GraphicString
2896 class TestVisibleString(
2897 UnicodeDecodeErrorMixin,
2902 base_klass = VisibleString
2905 class TestGeneralString(
2906 UnicodeDecodeErrorMixin,
2911 base_klass = GeneralString
2914 class TestUniversalString(StringMixin, CommonMixin, TestCase):
2915 base_klass = UniversalString
2918 class TestBMPString(StringMixin, CommonMixin, TestCase):
2919 base_klass = BMPString
2923 def generalized_time_values_strategy(
2931 if draw(booleans()):
2932 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2934 value = value.replace(microsecond=0)
2936 if draw(booleans()):
2937 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2939 default = default.replace(microsecond=0)
2943 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2945 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2946 optional = draw(one_of(none(), booleans()))
2948 draw(integers(min_value=0)),
2949 draw(integers(min_value=0)),
2950 draw(integers(min_value=0)),
2952 return (value, impl, expl, default, optional, _decoded)
2955 class TimeMixin(object):
2956 def test_invalid_value_type(self):
2957 with self.assertRaises(InvalidValueType) as err:
2958 self.base_klass(datetime.now().timetuple())
2961 @given(data_strategy())
2962 def test_optional(self, d):
2963 default = d.draw(datetimes(
2964 min_value=self.min_datetime,
2965 max_value=self.max_datetime,
2967 optional = d.draw(booleans())
2968 obj = self.base_klass(default=default, optional=optional)
2969 self.assertTrue(obj.optional)
2971 @given(data_strategy())
2972 def test_ready(self, d):
2973 obj = self.base_klass()
2974 self.assertFalse(obj.ready)
2977 with self.assertRaises(ObjNotReady) as err:
2980 value = d.draw(datetimes(min_value=self.min_datetime))
2981 obj = self.base_klass(value)
2982 self.assertTrue(obj.ready)
2986 @given(data_strategy())
2987 def test_comparison(self, d):
2988 value1 = d.draw(datetimes(
2989 min_value=self.min_datetime,
2990 max_value=self.max_datetime,
2992 value2 = d.draw(datetimes(
2993 min_value=self.min_datetime,
2994 max_value=self.max_datetime,
2996 tag1 = d.draw(binary())
2997 tag2 = d.draw(binary())
2999 value1 = value1.replace(microsecond=0)
3000 value2 = value2.replace(microsecond=0)
3001 obj1 = self.base_klass(value1)
3002 obj2 = self.base_klass(value2)
3003 self.assertEqual(obj1 == obj2, value1 == value2)
3004 self.assertEqual(obj1 != obj2, value1 != value2)
3005 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3006 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3007 obj1 = self.base_klass(value1, impl=tag1)
3008 obj2 = self.base_klass(value1, impl=tag2)
3009 self.assertEqual(obj1 == obj2, tag1 == tag2)
3010 self.assertEqual(obj1 != obj2, tag1 != tag2)
3012 @given(data_strategy())
3013 def test_call(self, d):
3021 ) = d.draw(generalized_time_values_strategy(
3022 min_datetime=self.min_datetime,
3023 max_datetime=self.max_datetime,
3024 omit_ms=self.omit_ms,
3026 obj_initial = self.base_klass(
3027 value=value_initial,
3030 default=default_initial,
3031 optional=optional_initial or False,
3032 _decoded=_decoded_initial,
3041 ) = d.draw(generalized_time_values_strategy(
3042 min_datetime=self.min_datetime,
3043 max_datetime=self.max_datetime,
3044 omit_ms=self.omit_ms,
3045 do_expl=impl_initial is None,
3055 value_expected = default if value is None else value
3057 default_initial if value_expected is None
3060 self.assertEqual(obj, value_expected)
3061 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3062 self.assertEqual(obj.expl_tag, expl or expl_initial)
3065 default_initial if default is None else default,
3067 if obj.default is None:
3068 optional = optional_initial if optional is None else optional
3069 optional = False if optional is None else optional
3072 self.assertEqual(obj.optional, optional)
3074 @given(data_strategy())
3075 def test_copy(self, d):
3076 values = d.draw(generalized_time_values_strategy(
3077 min_datetime=self.min_datetime,
3078 max_datetime=self.max_datetime,
3080 obj = self.base_klass(*values)
3081 obj_copied = obj.copy()
3082 self.assert_copied_basic_fields(obj, obj_copied)
3083 self.assertEqual(obj._value, obj_copied._value)
3085 @given(data_strategy())
3086 def test_stripped(self, d):
3087 value = d.draw(datetimes(
3088 min_value=self.min_datetime,
3089 max_value=self.max_datetime,
3091 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3092 obj = self.base_klass(value, impl=tag_impl)
3093 with self.assertRaises(NotEnoughData):
3094 obj.decode(obj.encode()[:-1])
3096 @given(data_strategy())
3097 def test_stripped_expl(self, d):
3098 value = d.draw(datetimes(
3099 min_value=self.min_datetime,
3100 max_value=self.max_datetime,
3102 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3103 obj = self.base_klass(value, expl=tag_expl)
3104 with self.assertRaises(NotEnoughData):
3105 obj.decode(obj.encode()[:-1])
3107 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3108 @given(data_strategy())
3109 def test_symmetric(self, d):
3110 values = d.draw(generalized_time_values_strategy(
3111 min_datetime=self.min_datetime,
3112 max_datetime=self.max_datetime,
3114 value = d.draw(datetimes(
3115 min_value=self.min_datetime,
3116 max_value=self.max_datetime,
3118 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3119 offset = d.draw(integers(min_value=0))
3120 tail_junk = d.draw(binary(max_size=5))
3121 _, _, _, default, optional, _decoded = values
3122 obj = self.base_klass(
3130 self.assertFalse(obj.expled)
3131 obj_encoded = obj.encode()
3132 obj_expled = obj(value, expl=tag_expl)
3133 self.assertTrue(obj_expled.expled)
3136 obj_expled_encoded = obj_expled.encode()
3137 obj_decoded, tail = obj_expled.decode(
3138 obj_expled_encoded + tail_junk,
3143 self.assertEqual(tail, tail_junk)
3144 self.assertEqual(obj_decoded, obj_expled)
3145 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3146 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3147 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3148 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3149 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3151 obj_decoded.expl_llen,
3152 len(len_encode(len(obj_encoded))),
3154 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3155 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3158 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3160 self.assertEqual(obj_decoded.expl_offset, offset)
3163 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3164 base_klass = GeneralizedTime
3166 min_datetime = datetime(1900, 1, 1)
3167 max_datetime = datetime(9999, 12, 31)
3169 def test_go_vectors_invalid(self):
3181 b"-20100102030410Z",
3182 b"2010-0102030410Z",
3183 b"2010-0002030410Z",
3184 b"201001-02030410Z",
3185 b"20100102-030410Z",
3186 b"2010010203-0410Z",
3187 b"201001020304-10Z",
3188 # These ones are INVALID in *DER*, but accepted
3189 # by Go's encoding/asn1
3190 b"20100102030405+0607",
3191 b"20100102030405-0607",
3193 with self.assertRaises(DecodeError) as err:
3194 GeneralizedTime(data)
3197 def test_go_vectors_valid(self):
3199 GeneralizedTime(b"20100102030405Z").todatetime(),
3200 datetime(2010, 1, 2, 3, 4, 5, 0),
3204 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3205 base_klass = UTCTime
3207 min_datetime = datetime(2000, 1, 1)
3208 max_datetime = datetime(2049, 12, 31)
3210 def test_go_vectors_invalid(self):
3236 # These ones are INVALID in *DER*, but accepted
3237 # by Go's encoding/asn1
3238 b"910506164540-0700",
3239 b"910506164540+0730",
3243 with self.assertRaises(DecodeError) as err:
3247 def test_go_vectors_valid(self):
3249 UTCTime(b"910506234540Z").todatetime(),
3250 datetime(1991, 5, 6, 23, 45, 40, 0),
3253 @given(integers(min_value=0, max_value=49))
3254 def test_pre50(self, year):
3256 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3260 @given(integers(min_value=50, max_value=99))
3261 def test_post50(self, year):
3263 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3269 def any_values_strategy(draw, do_expl=False):
3270 value = draw(one_of(none(), binary()))
3273 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3274 optional = draw(one_of(none(), booleans()))
3276 draw(integers(min_value=0)),
3277 draw(integers(min_value=0)),
3278 draw(integers(min_value=0)),
3280 return (value, expl, optional, _decoded)
3283 class AnyInherited(Any):
3287 class TestAny(CommonMixin, TestCase):
3290 def test_invalid_value_type(self):
3291 with self.assertRaises(InvalidValueType) as err:
3296 def test_optional(self, optional):
3297 obj = Any(optional=optional)
3298 self.assertEqual(obj.optional, optional)
3301 def test_ready(self, value):
3303 self.assertFalse(obj.ready)
3306 with self.assertRaises(ObjNotReady) as err:
3310 self.assertTrue(obj.ready)
3315 def test_basic(self, value):
3316 integer_encoded = Integer(value).encode()
3318 Any(integer_encoded),
3319 Any(Integer(value)),
3320 Any(Any(Integer(value))),
3322 self.assertSequenceEqual(bytes(obj), integer_encoded)
3324 obj.decode(obj.encode())[0].vlen,
3325 len(integer_encoded),
3329 self.assertSequenceEqual(obj.encode(), integer_encoded)
3331 @given(binary(), binary())
3332 def test_comparison(self, value1, value2):
3333 for klass in (Any, AnyInherited):
3334 obj1 = klass(value1)
3335 obj2 = klass(value2)
3336 self.assertEqual(obj1 == obj2, value1 == value2)
3337 self.assertEqual(obj1 != obj2, value1 != value2)
3338 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3340 @given(data_strategy())
3341 def test_call(self, d):
3342 for klass in (Any, AnyInherited):
3348 ) = d.draw(any_values_strategy())
3349 obj_initial = klass(
3352 optional_initial or False,
3360 ) = d.draw(any_values_strategy(do_expl=True))
3361 obj = obj_initial(value, expl, optional)
3363 value_expected = None if value is None else value
3364 self.assertEqual(obj, value_expected)
3365 self.assertEqual(obj.expl_tag, expl or expl_initial)
3366 if obj.default is None:
3367 optional = optional_initial if optional is None else optional
3368 optional = False if optional is None else optional
3369 self.assertEqual(obj.optional, optional)
3371 def test_simultaneous_impl_expl(self):
3372 # override it, as Any does not have implicit tag
3375 def test_decoded(self):
3376 # override it, as Any does not have implicit tag
3379 @given(any_values_strategy())
3380 def test_copy(self, values):
3381 for klass in (Any, AnyInherited):
3382 obj = klass(*values)
3383 obj_copied = obj.copy()
3384 self.assert_copied_basic_fields(obj, obj_copied)
3385 self.assertEqual(obj._value, obj_copied._value)
3387 @given(binary().map(OctetString))
3388 def test_stripped(self, value):
3390 with self.assertRaises(NotEnoughData):
3391 obj.decode(obj.encode()[:-1])
3395 integers(min_value=1).map(tag_ctxc),
3397 def test_stripped_expl(self, value, tag_expl):
3398 obj = Any(value, expl=tag_expl)
3399 with self.assertRaises(NotEnoughData):
3400 obj.decode(obj.encode()[:-1])
3403 integers(min_value=31),
3404 integers(min_value=0),
3407 def test_bad_tag(self, tag, offset, decode_path):
3408 decode_path = tuple(str(i) for i in decode_path)
3409 with self.assertRaises(DecodeError) as err:
3411 tag_encode(tag)[:-1],
3413 decode_path=decode_path,
3416 self.assertEqual(err.exception.offset, offset)
3417 self.assertEqual(err.exception.decode_path, decode_path)
3420 integers(min_value=128),
3421 integers(min_value=0),
3424 def test_bad_len(self, l, offset, decode_path):
3425 decode_path = tuple(str(i) for i in decode_path)
3426 with self.assertRaises(DecodeError) as err:
3428 Any.tag_default + len_encode(l)[:-1],
3430 decode_path=decode_path,
3433 self.assertEqual(err.exception.offset, offset)
3434 self.assertEqual(err.exception.decode_path, decode_path)
3436 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3438 any_values_strategy(),
3439 integers().map(lambda x: Integer(x).encode()),
3440 integers(min_value=1).map(tag_ctxc),
3441 integers(min_value=0),
3444 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3445 for klass in (Any, AnyInherited):
3446 _, _, optional, _decoded = values
3447 obj = klass(value=value, optional=optional, _decoded=_decoded)
3450 self.assertFalse(obj.expled)
3451 obj_encoded = obj.encode()
3452 obj_expled = obj(value, expl=tag_expl)
3453 self.assertTrue(obj_expled.expled)
3456 obj_expled_encoded = obj_expled.encode()
3457 obj_decoded, tail = obj_expled.decode(
3458 obj_expled_encoded + tail_junk,
3463 self.assertEqual(tail, tail_junk)
3464 self.assertEqual(obj_decoded, obj_expled)
3465 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3466 self.assertEqual(bytes(obj_decoded), bytes(obj))
3467 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3468 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3469 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3471 obj_decoded.expl_llen,
3472 len(len_encode(len(obj_encoded))),
3474 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3475 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3478 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3480 self.assertEqual(obj_decoded.expl_offset, offset)
3481 self.assertEqual(obj_decoded.tlen, 0)
3482 self.assertEqual(obj_decoded.llen, 0)
3483 self.assertEqual(obj_decoded.vlen, len(value))
3487 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3489 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3490 tags = [tag_encode(tag) for tag in draw(sets(
3491 integers(min_value=0),
3492 min_size=len(names),
3493 max_size=len(names),
3495 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3497 if value_required or draw(booleans()):
3498 value = draw(tuples(
3499 sampled_from([name for name, _ in schema]),
3500 integers().map(Integer),
3504 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3505 default = draw(one_of(
3507 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3509 optional = draw(one_of(none(), booleans()))
3511 draw(integers(min_value=0)),
3512 draw(integers(min_value=0)),
3513 draw(integers(min_value=0)),
3515 return (schema, value, expl, default, optional, _decoded)
3518 class ChoiceInherited(Choice):
3522 class TestChoice(CommonMixin, TestCase):
3524 schema = (("whatever", Boolean()),)
3527 def test_schema_required(self):
3528 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3531 def test_impl_forbidden(self):
3532 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3533 Choice(impl=b"whatever")
3535 def test_invalid_value_type(self):
3536 with self.assertRaises(InvalidValueType) as err:
3537 self.base_klass(123)
3539 with self.assertRaises(ObjUnknown) as err:
3540 self.base_klass(("whenever", Boolean(False)))
3542 with self.assertRaises(InvalidValueType) as err:
3543 self.base_klass(("whatever", Integer(123)))
3547 def test_optional(self, optional):
3548 obj = self.base_klass(
3549 default=self.base_klass(("whatever", Boolean(False))),
3552 self.assertTrue(obj.optional)
3555 def test_ready(self, value):
3556 obj = self.base_klass()
3557 self.assertFalse(obj.ready)
3560 self.assertIsNone(obj["whatever"])
3561 with self.assertRaises(ObjNotReady) as err:
3564 obj["whatever"] = Boolean()
3565 self.assertFalse(obj.ready)
3568 obj["whatever"] = Boolean(value)
3569 self.assertTrue(obj.ready)
3573 @given(booleans(), booleans())
3574 def test_comparison(self, value1, value2):
3575 class WahlInherited(self.base_klass):
3577 for klass in (self.base_klass, WahlInherited):
3578 obj1 = klass(("whatever", Boolean(value1)))
3579 obj2 = klass(("whatever", Boolean(value2)))
3580 self.assertEqual(obj1 == obj2, value1 == value2)
3581 self.assertEqual(obj1 != obj2, value1 != value2)
3582 self.assertEqual(obj1 == obj2._value, value1 == value2)
3583 self.assertFalse(obj1 == obj2._value[1])
3585 @given(data_strategy())
3586 def test_call(self, d):
3587 for klass in (Choice, ChoiceInherited):
3595 ) = d.draw(choice_values_strategy())
3598 schema = schema_initial
3600 value=value_initial,
3602 default=default_initial,
3603 optional=optional_initial or False,
3604 _decoded=_decoded_initial,
3613 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
3614 obj = obj_initial(value, expl, default, optional)
3616 value_expected = default if value is None else value
3618 default_initial if value_expected is None
3621 self.assertEqual(obj.choice, value_expected[0])
3622 self.assertEqual(obj.value, int(value_expected[1]))
3623 self.assertEqual(obj.expl_tag, expl or expl_initial)
3624 default_expect = default_initial if default is None else default
3625 if default_expect is not None:
3626 self.assertEqual(obj.default.choice, default_expect[0])
3627 self.assertEqual(obj.default.value, int(default_expect[1]))
3628 if obj.default is None:
3629 optional = optional_initial if optional is None else optional
3630 optional = False if optional is None else optional
3633 self.assertEqual(obj.optional, optional)
3634 self.assertEqual(obj.specs, obj_initial.specs)
3636 def test_simultaneous_impl_expl(self):
3637 # override it, as Any does not have implicit tag
3640 def test_decoded(self):
3641 # override it, as Any does not have implicit tag
3644 @given(choice_values_strategy())
3645 def test_copy(self, values):
3646 _schema, value, expl, default, optional, _decoded = values
3648 class Wahl(self.base_klass):
3654 optional=optional or False,
3657 obj_copied = obj.copy()
3658 self.assertIsNone(obj.tag)
3659 self.assertIsNone(obj_copied.tag)
3660 # hack for assert_copied_basic_fields
3661 obj.tag = "whatever"
3662 obj_copied.tag = "whatever"
3663 self.assert_copied_basic_fields(obj, obj_copied)
3664 self.assertEqual(obj._value, obj_copied._value)
3665 self.assertEqual(obj.specs, obj_copied.specs)
3668 def test_stripped(self, value):
3669 obj = self.base_klass(("whatever", Boolean(value)))
3670 with self.assertRaises(NotEnoughData):
3671 obj.decode(obj.encode()[:-1])
3675 integers(min_value=1).map(tag_ctxc),
3677 def test_stripped_expl(self, value, tag_expl):
3678 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3679 with self.assertRaises(NotEnoughData):
3680 obj.decode(obj.encode()[:-1])
3682 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3683 @given(data_strategy())
3684 def test_symmetric(self, d):
3685 _schema, value, _, default, optional, _decoded = d.draw(
3686 choice_values_strategy(value_required=True)
3688 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3689 offset = d.draw(integers(min_value=0))
3690 tail_junk = d.draw(binary(max_size=5))
3692 class Wahl(self.base_klass):
3702 self.assertFalse(obj.expled)
3703 obj_encoded = obj.encode()
3704 obj_expled = obj(value, expl=tag_expl)
3705 self.assertTrue(obj_expled.expled)
3708 obj_expled_encoded = obj_expled.encode()
3709 obj_decoded, tail = obj_expled.decode(
3710 obj_expled_encoded + tail_junk,
3715 self.assertEqual(tail, tail_junk)
3716 self.assertEqual(obj_decoded, obj_expled)
3717 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3718 self.assertEqual(obj_decoded.value, obj_expled.value)
3719 self.assertEqual(obj_decoded.choice, obj.choice)
3720 self.assertEqual(obj_decoded.value, obj.value)
3721 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3722 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3723 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3725 obj_decoded.expl_llen,
3726 len(len_encode(len(obj_encoded))),
3728 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3729 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3732 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3734 self.assertEqual(obj_decoded.expl_offset, offset)
3735 self.assertSequenceEqual(
3737 obj_decoded.value.offset - offset:
3738 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3744 def test_set_get(self, value):
3747 ("erste", Boolean()),
3748 ("zweite", Integer()),
3751 with self.assertRaises(ObjUnknown) as err:
3752 obj["whatever"] = "whenever"
3753 with self.assertRaises(InvalidValueType) as err:
3754 obj["zweite"] = Boolean(False)
3755 obj["zweite"] = Integer(value)
3757 with self.assertRaises(ObjUnknown) as err:
3760 self.assertIsNone(obj["erste"])
3761 self.assertEqual(obj["zweite"], Integer(value))
3763 def test_tag_mismatch(self):
3766 ("erste", Boolean()),
3768 int_encoded = Integer(123).encode()
3769 bool_encoded = Boolean(False).encode()
3771 obj.decode(bool_encoded)
3772 with self.assertRaises(TagMismatch):
3773 obj.decode(int_encoded)
3777 def seq_values_strategy(draw, seq_klass, do_expl=False):
3779 if draw(booleans()):
3782 k: v for k, v in draw(dictionaries(
3785 booleans().map(Boolean),
3786 integers().map(Integer),
3791 if draw(booleans()):
3792 schema = list(draw(dictionaries(
3795 booleans().map(Boolean),
3796 integers().map(Integer),
3802 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3804 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3806 if draw(booleans()):
3807 default = seq_klass()
3809 k: v for k, v in draw(dictionaries(
3812 booleans().map(Boolean),
3813 integers().map(Integer),
3817 optional = draw(one_of(none(), booleans()))
3819 draw(integers(min_value=0)),
3820 draw(integers(min_value=0)),
3821 draw(integers(min_value=0)),
3823 return (value, schema, impl, expl, default, optional, _decoded)
3827 def sequence_strategy(draw, seq_klass):
3828 inputs = draw(lists(
3830 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
3831 tuples(just(Integer), integers(), one_of(none(), integers())),
3836 integers(min_value=1),
3837 min_size=len(inputs),
3838 max_size=len(inputs),
3841 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3842 for tag, expled in zip(tags, draw(lists(
3844 min_size=len(inputs),
3845 max_size=len(inputs),
3849 for i, optional in enumerate(draw(lists(
3850 sampled_from(("required", "optional", "empty")),
3851 min_size=len(inputs),
3852 max_size=len(inputs),
3854 if optional in ("optional", "empty"):
3855 inits[i]["optional"] = True
3856 if optional == "empty":
3858 empties = set(empties)
3859 names = list(draw(sets(
3861 min_size=len(inputs),
3862 max_size=len(inputs),
3865 for i, (klass, value, default) in enumerate(inputs):
3866 schema.append((names[i], klass(default=default, **inits[i])))
3867 seq_name = draw(text_letters())
3868 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3871 for i, (klass, value, default) in enumerate(inputs):
3878 "default_value": None if spec.default is None else default,
3882 expect["optional"] = True
3884 expect["presented"] = True
3885 expect["value"] = value
3887 expect["optional"] = True
3888 if default is not None and default == value:
3889 expect["presented"] = False
3890 seq[name] = klass(value)
3891 expects.append(expect)
3896 def sequences_strategy(draw, seq_klass):
3897 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
3899 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3900 for tag, expled in zip(tags, draw(lists(
3907 i for i, is_default in enumerate(draw(lists(
3913 names = list(draw(sets(
3918 seq_expectses = draw(lists(
3919 sequence_strategy(seq_klass=seq_klass),
3923 seqs = [seq for seq, _ in seq_expectses]
3925 for i, (name, seq) in enumerate(zip(names, seqs)):
3928 seq(default=(seq if i in defaulted else None), **inits[i]),
3930 seq_name = draw(text_letters())
3931 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3934 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
3937 "expects": expects_inner,
3940 seq_outer[name] = seq_inner
3941 if seq_outer.specs[name].default is None:
3942 expect["presented"] = True
3943 expect_outers.append(expect)
3944 return seq_outer, expect_outers
3947 class SeqMixing(object):
3948 def test_invalid_value_type(self):
3949 with self.assertRaises(InvalidValueType) as err:
3950 self.base_klass((1, 2, 3))
3953 def test_invalid_value_type_set(self):
3954 class Seq(self.base_klass):
3955 schema = (("whatever", Boolean()),)
3957 with self.assertRaises(InvalidValueType) as err:
3958 seq["whatever"] = Integer(123)
3962 def test_optional(self, optional):
3963 obj = self.base_klass(default=self.base_klass(), optional=optional)
3964 self.assertTrue(obj.optional)
3966 @given(data_strategy())
3967 def test_ready(self, d):
3969 str(i): v for i, v in enumerate(d.draw(lists(
3976 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
3983 for name in d.draw(permutations(
3984 list(ready.keys()) + list(non_ready.keys()),
3986 schema_input.append((name, Boolean()))
3988 class Seq(self.base_klass):
3989 schema = tuple(schema_input)
3991 for name in ready.keys():
3993 seq[name] = Boolean()
3994 self.assertFalse(seq.ready)
3997 for name, value in ready.items():
3998 seq[name] = Boolean(value)
3999 self.assertFalse(seq.ready)
4002 with self.assertRaises(ObjNotReady) as err:
4005 for name, value in non_ready.items():
4006 seq[name] = Boolean(value)
4007 self.assertTrue(seq.ready)
4011 @given(data_strategy())
4012 def test_call(self, d):
4013 class SeqInherited(self.base_klass):
4015 for klass in (self.base_klass, SeqInherited):
4024 ) = d.draw(seq_values_strategy(seq_klass=klass))
4025 obj_initial = klass(
4031 optional_initial or False,
4042 ) = d.draw(seq_values_strategy(
4044 do_expl=impl_initial is None,
4046 obj = obj_initial(value, impl, expl, default, optional)
4047 value_expected = default if value is None else value
4049 default_initial if value_expected is None
4052 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4053 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4054 self.assertEqual(obj.expl_tag, expl or expl_initial)
4056 {} if obj.default is None else obj.default._value,
4057 getattr(default_initial if default is None else default, "_value", {}),
4059 if obj.default is None:
4060 optional = optional_initial if optional is None else optional
4061 optional = False if optional is None else optional
4064 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4065 self.assertEqual(obj.optional, optional)
4067 @given(data_strategy())
4068 def test_copy(self, d):
4069 class SeqInherited(self.base_klass):
4071 for klass in (self.base_klass, SeqInherited):
4072 values = d.draw(seq_values_strategy(seq_klass=klass))
4073 obj = klass(*values)
4074 obj_copied = obj.copy()
4075 self.assert_copied_basic_fields(obj, obj_copied)
4076 self.assertEqual(obj.specs, obj_copied.specs)
4077 self.assertEqual(obj._value, obj_copied._value)
4079 @given(data_strategy())
4080 def test_stripped(self, d):
4081 value = d.draw(integers())
4082 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4084 class Seq(self.base_klass):
4086 schema = (("whatever", Integer()),)
4088 seq["whatever"] = Integer(value)
4089 with self.assertRaises(NotEnoughData):
4090 seq.decode(seq.encode()[:-1])
4092 @given(data_strategy())
4093 def test_stripped_expl(self, d):
4094 value = d.draw(integers())
4095 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4097 class Seq(self.base_klass):
4099 schema = (("whatever", Integer()),)
4101 seq["whatever"] = Integer(value)
4102 with self.assertRaises(NotEnoughData):
4103 seq.decode(seq.encode()[:-1])
4105 @given(binary(min_size=2))
4106 def test_non_tag_mismatch_raised(self, junk):
4108 _, _, len_encoded = tag_strip(memoryview(junk))
4109 len_decode(len_encoded)
4115 class Seq(self.base_klass):
4117 ("whatever", Integer()),
4119 ("whenever", Integer()),
4122 seq["whatever"] = Integer(123)
4123 seq["junk"] = Any(junk)
4124 seq["whenever"] = Integer(123)
4125 with self.assertRaises(DecodeError):
4126 seq.decode(seq.encode())
4129 integers(min_value=31),
4130 integers(min_value=0),
4133 def test_bad_tag(self, tag, offset, decode_path):
4134 decode_path = tuple(str(i) for i in decode_path)
4135 with self.assertRaises(DecodeError) as err:
4136 self.base_klass().decode(
4137 tag_encode(tag)[:-1],
4139 decode_path=decode_path,
4142 self.assertEqual(err.exception.offset, offset)
4143 self.assertEqual(err.exception.decode_path, decode_path)
4146 integers(min_value=128),
4147 integers(min_value=0),
4150 def test_bad_len(self, l, offset, decode_path):
4151 decode_path = tuple(str(i) for i in decode_path)
4152 with self.assertRaises(DecodeError) as err:
4153 self.base_klass().decode(
4154 self.base_klass.tag_default + len_encode(l)[:-1],
4156 decode_path=decode_path,
4159 self.assertEqual(err.exception.offset, offset)
4160 self.assertEqual(err.exception.decode_path, decode_path)
4162 def _assert_expects(self, seq, expects):
4163 for expect in expects:
4165 seq.specs[expect["name"]].optional,
4168 if expect["default_value"] is not None:
4170 seq.specs[expect["name"]].default,
4171 expect["default_value"],
4173 if expect["presented"]:
4174 self.assertIn(expect["name"], seq)
4175 self.assertEqual(seq[expect["name"]], expect["value"])
4177 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4178 @given(data_strategy())
4179 def test_symmetric(self, d):
4180 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4181 tail_junk = d.draw(binary(max_size=5))
4182 self.assertTrue(seq.ready)
4183 self.assertFalse(seq.decoded)
4184 self._assert_expects(seq, expects)
4187 seq_encoded = seq.encode()
4188 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4189 self.assertEqual(tail, tail_junk)
4190 self.assertTrue(seq.ready)
4191 self._assert_expects(seq_decoded, expects)
4192 self.assertEqual(seq, seq_decoded)
4193 self.assertEqual(seq_decoded.encode(), seq_encoded)
4194 for expect in expects:
4195 if not expect["presented"]:
4196 self.assertNotIn(expect["name"], seq_decoded)
4198 self.assertIn(expect["name"], seq_decoded)
4199 obj = seq_decoded[expect["name"]]
4200 self.assertTrue(obj.decoded)
4201 offset = obj.expl_offset if obj.expled else obj.offset
4202 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4203 self.assertSequenceEqual(
4204 seq_encoded[offset:offset + tlvlen],
4208 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4209 @given(data_strategy())
4210 def test_symmetric_with_seq(self, d):
4211 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4212 self.assertTrue(seq.ready)
4213 seq_encoded = seq.encode()
4214 seq_decoded, tail = seq.decode(seq_encoded)
4215 self.assertEqual(tail, b"")
4216 self.assertTrue(seq.ready)
4217 self.assertEqual(seq, seq_decoded)
4218 self.assertEqual(seq_decoded.encode(), seq_encoded)
4219 for expect_outer in expect_outers:
4220 if not expect_outer["presented"]:
4221 self.assertNotIn(expect_outer["name"], seq_decoded)
4223 self.assertIn(expect_outer["name"], seq_decoded)
4224 obj = seq_decoded[expect_outer["name"]]
4225 self.assertTrue(obj.decoded)
4226 offset = obj.expl_offset if obj.expled else obj.offset
4227 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4228 self.assertSequenceEqual(
4229 seq_encoded[offset:offset + tlvlen],
4232 self._assert_expects(obj, expect_outer["expects"])
4234 @given(data_strategy())
4235 def test_default_disappears(self, d):
4236 _schema = list(d.draw(dictionaries(
4238 sets(integers(), min_size=2, max_size=2),
4242 class Seq(self.base_klass):
4244 (n, Integer(default=d))
4245 for n, (_, d) in _schema
4248 for name, (value, _) in _schema:
4249 seq[name] = Integer(value)
4250 self.assertEqual(len(seq._value), len(_schema))
4251 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4252 self.assertGreater(len(seq.encode()), len(empty_seq))
4253 for name, (_, default) in _schema:
4254 seq[name] = Integer(default)
4255 self.assertEqual(len(seq._value), 0)
4256 self.assertSequenceEqual(seq.encode(), empty_seq)
4258 @given(data_strategy())
4259 def test_encoded_default_accepted(self, d):
4260 _schema = list(d.draw(dictionaries(
4265 tags = [tag_encode(tag) for tag in d.draw(sets(
4266 integers(min_value=0),
4267 min_size=len(_schema),
4268 max_size=len(_schema),
4271 class SeqWithoutDefault(self.base_klass):
4273 (n, Integer(impl=t))
4274 for (n, _), t in zip(_schema, tags)
4276 seq_without_default = SeqWithoutDefault()
4277 for name, value in _schema:
4278 seq_without_default[name] = Integer(value)
4279 seq_encoded = seq_without_default.encode()
4281 class SeqWithDefault(self.base_klass):
4283 (n, Integer(default=v, impl=t))
4284 for (n, v), t in zip(_schema, tags)
4286 seq_with_default = SeqWithDefault()
4287 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4288 for name, value in _schema:
4289 self.assertEqual(seq_decoded[name], seq_with_default[name])
4290 self.assertEqual(seq_decoded[name], value)
4292 @given(data_strategy())
4293 def test_missing_from_spec(self, d):
4294 names = list(d.draw(sets(text_letters(), min_size=2)))
4295 tags = [tag_encode(tag) for tag in d.draw(sets(
4296 integers(min_value=0),
4297 min_size=len(names),
4298 max_size=len(names),
4300 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4302 class SeqFull(self.base_klass):
4303 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4304 seq_full = SeqFull()
4305 for i, name in enumerate(names):
4306 seq_full[name] = Integer(i)
4307 seq_encoded = seq_full.encode()
4308 altered = names_tags[:-2] + names_tags[-1:]
4310 class SeqMissing(self.base_klass):
4311 schema = [(n, Integer(impl=t)) for n, t in altered]
4312 seq_missing = SeqMissing()
4313 with self.assertRaises(TagMismatch):
4314 seq_missing.decode(seq_encoded)
4317 class TestSequence(SeqMixing, CommonMixin, TestCase):
4318 base_klass = Sequence
4324 def test_remaining(self, value, junk):
4325 class Seq(Sequence):
4327 ("whatever", Integer()),
4329 int_encoded = Integer(value).encode()
4331 Sequence.tag_default,
4332 len_encode(len(int_encoded + junk)),
4335 with assertRaisesRegex(self, DecodeError, "remaining"):
4336 Seq().decode(junked)
4338 @given(sets(text_letters(), min_size=2))
4339 def test_obj_unknown(self, names):
4340 missing = names.pop()
4342 class Seq(Sequence):
4343 schema = [(n, Boolean()) for n in names]
4345 with self.assertRaises(ObjUnknown) as err:
4348 with self.assertRaises(ObjUnknown) as err:
4349 seq[missing] = Boolean()
4353 class TestSet(SeqMixing, CommonMixin, TestCase):
4356 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4357 @given(data_strategy())
4358 def test_sorted(self, d):
4360 tag_encode(tag) for tag in
4361 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4365 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4367 for name, _ in Seq.schema:
4368 seq[name] = OctetString(b"")
4369 seq_encoded = seq.encode()
4370 seq_decoded, _ = seq.decode(seq_encoded)
4371 self.assertSequenceEqual(
4372 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4373 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4378 def seqof_values_strategy(draw, schema=None, do_expl=False):
4380 schema = draw(sampled_from((Boolean(), Integer())))
4381 bound_min, bound_max = sorted(draw(sets(
4382 integers(min_value=0, max_value=10),
4386 if isinstance(schema, Boolean):
4387 values_generator = booleans().map(Boolean)
4388 elif isinstance(schema, Integer):
4389 values_generator = integers().map(Integer)
4390 values_generator = lists(
4395 values = draw(one_of(none(), values_generator))
4399 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4401 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4402 default = draw(one_of(none(), values_generator))
4403 optional = draw(one_of(none(), booleans()))
4405 draw(integers(min_value=0)),
4406 draw(integers(min_value=0)),
4407 draw(integers(min_value=0)),
4412 (bound_min, bound_max),
4421 class SeqOfMixing(object):
4422 def test_invalid_value_type(self):
4423 with self.assertRaises(InvalidValueType) as err:
4424 self.base_klass(123)
4427 def test_invalid_values_type(self):
4428 class SeqOf(self.base_klass):
4430 with self.assertRaises(InvalidValueType) as err:
4431 SeqOf([Integer(123), Boolean(False), Integer(234)])
4434 def test_schema_required(self):
4435 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4436 self.base_klass.__mro__[1]()
4438 @given(booleans(), booleans(), binary(), binary())
4439 def test_comparison(self, value1, value2, tag1, tag2):
4440 class SeqOf(self.base_klass):
4442 obj1 = SeqOf([Boolean(value1)])
4443 obj2 = SeqOf([Boolean(value2)])
4444 self.assertEqual(obj1 == obj2, value1 == value2)
4445 self.assertEqual(obj1 != obj2, value1 != value2)
4446 self.assertEqual(obj1 == list(obj2), value1 == value2)
4447 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4448 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4449 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4450 self.assertEqual(obj1 == obj2, tag1 == tag2)
4451 self.assertEqual(obj1 != obj2, tag1 != tag2)
4453 @given(lists(booleans()))
4454 def test_iter(self, values):
4455 class SeqOf(self.base_klass):
4457 obj = SeqOf([Boolean(value) for value in values])
4458 self.assertEqual(len(obj), len(values))
4459 for i, value in enumerate(obj):
4460 self.assertEqual(value, values[i])
4462 @given(data_strategy())
4463 def test_ready(self, d):
4464 ready = [Integer(v) for v in d.draw(lists(
4471 range(d.draw(integers(min_value=1, max_value=5)))
4474 class SeqOf(self.base_klass):
4476 values = d.draw(permutations(ready + non_ready))
4478 for value in values:
4480 self.assertFalse(seqof.ready)
4483 with self.assertRaises(ObjNotReady) as err:
4486 for i, value in enumerate(values):
4487 self.assertEqual(seqof[i], value)
4488 if not seqof[i].ready:
4489 seqof[i] = Integer(i)
4490 self.assertTrue(seqof.ready)
4494 def test_spec_mismatch(self):
4495 class SeqOf(self.base_klass):
4498 seqof.append(Integer(123))
4499 with self.assertRaises(ValueError):
4500 seqof.append(Boolean(False))
4501 with self.assertRaises(ValueError):
4502 seqof[0] = Boolean(False)
4504 @given(data_strategy())
4505 def test_bounds_satisfied(self, d):
4506 class SeqOf(self.base_klass):
4508 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4509 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4510 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4511 SeqOf(value=value, bounds=(bound_min, bound_max))
4513 @given(data_strategy())
4514 def test_bounds_unsatisfied(self, d):
4515 class SeqOf(self.base_klass):
4517 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4518 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4519 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4520 with self.assertRaises(BoundsError) as err:
4521 SeqOf(value=value, bounds=(bound_min, bound_max))
4523 value = [Boolean()] * d.draw(integers(
4524 min_value=bound_max + 1,
4525 max_value=bound_max + 10,
4527 with self.assertRaises(BoundsError) as err:
4528 SeqOf(value=value, bounds=(bound_min, bound_max))
4531 @given(integers(min_value=1, max_value=10))
4532 def test_out_of_bounds(self, bound_max):
4533 class SeqOf(self.base_klass):
4535 bounds = (0, bound_max)
4537 for _ in range(bound_max):
4538 seqof.append(Integer(123))
4539 with self.assertRaises(BoundsError):
4540 seqof.append(Integer(123))
4542 @given(data_strategy())
4543 def test_call(self, d):
4553 ) = d.draw(seqof_values_strategy())
4555 class SeqOf(self.base_klass):
4556 schema = schema_initial
4557 obj_initial = SeqOf(
4558 value=value_initial,
4559 bounds=bounds_initial,
4562 default=default_initial,
4563 optional=optional_initial or False,
4564 _decoded=_decoded_initial,
4575 ) = d.draw(seqof_values_strategy(
4576 schema=schema_initial,
4577 do_expl=impl_initial is None,
4579 if (default is None) and (obj_initial.default is not None):
4582 (bounds is None) and
4583 (value is not None) and
4584 (bounds_initial is not None) and
4585 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4589 (bounds is None) and
4590 (default is not None) and
4591 (bounds_initial is not None) and
4592 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4604 value_expected = default if value is None else value
4606 default_initial if value_expected is None
4609 value_expected = () if value_expected is None else value_expected
4610 self.assertEqual(obj, value_expected)
4611 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4612 self.assertEqual(obj.expl_tag, expl or expl_initial)
4615 default_initial if default is None else default,
4617 if obj.default is None:
4618 optional = optional_initial if optional is None else optional
4619 optional = False if optional is None else optional
4622 self.assertEqual(obj.optional, optional)
4624 (obj._bound_min, obj._bound_max),
4625 bounds or bounds_initial or (0, float("+inf")),
4628 @given(seqof_values_strategy())
4629 def test_copy(self, values):
4630 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4632 class SeqOf(self.base_klass):
4640 optional=optional or False,
4643 obj_copied = obj.copy()
4644 self.assert_copied_basic_fields(obj, obj_copied)
4645 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4646 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4647 self.assertEqual(obj._value, obj_copied._value)
4651 integers(min_value=1).map(tag_encode),
4653 def test_stripped(self, values, tag_impl):
4654 class SeqOf(self.base_klass):
4655 schema = OctetString()
4656 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4657 with self.assertRaises(NotEnoughData):
4658 obj.decode(obj.encode()[:-1])
4662 integers(min_value=1).map(tag_ctxc),
4664 def test_stripped_expl(self, values, tag_expl):
4665 class SeqOf(self.base_klass):
4666 schema = OctetString()
4667 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4668 with self.assertRaises(NotEnoughData):
4669 obj.decode(obj.encode()[:-1])
4672 integers(min_value=31),
4673 integers(min_value=0),
4676 def test_bad_tag(self, tag, offset, decode_path):
4677 decode_path = tuple(str(i) for i in decode_path)
4678 with self.assertRaises(DecodeError) as err:
4679 self.base_klass().decode(
4680 tag_encode(tag)[:-1],
4682 decode_path=decode_path,
4685 self.assertEqual(err.exception.offset, offset)
4686 self.assertEqual(err.exception.decode_path, decode_path)
4689 integers(min_value=128),
4690 integers(min_value=0),
4693 def test_bad_len(self, l, offset, decode_path):
4694 decode_path = tuple(str(i) for i in decode_path)
4695 with self.assertRaises(DecodeError) as err:
4696 self.base_klass().decode(
4697 self.base_klass.tag_default + len_encode(l)[:-1],
4699 decode_path=decode_path,
4702 self.assertEqual(err.exception.offset, offset)
4703 self.assertEqual(err.exception.decode_path, decode_path)
4705 @given(binary(min_size=1))
4706 def test_tag_mismatch(self, impl):
4707 assume(impl != self.base_klass.tag_default)
4708 with self.assertRaises(TagMismatch):
4709 self.base_klass(impl=impl).decode(self.base_klass().encode())
4711 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4713 seqof_values_strategy(schema=Integer()),
4714 lists(integers().map(Integer)),
4715 integers(min_value=1).map(tag_ctxc),
4716 integers(min_value=0),
4719 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4720 _, _, _, _, _, default, optional, _decoded = values
4722 class SeqOf(self.base_klass):
4732 self.assertFalse(obj.expled)
4733 obj_encoded = obj.encode()
4734 obj_expled = obj(value, expl=tag_expl)
4735 self.assertTrue(obj_expled.expled)
4738 obj_expled_encoded = obj_expled.encode()
4739 obj_decoded, tail = obj_expled.decode(
4740 obj_expled_encoded + tail_junk,
4745 self.assertEqual(tail, tail_junk)
4746 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
4747 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4748 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4749 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4751 obj_decoded.expl_llen,
4752 len(len_encode(len(obj_encoded))),
4754 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4755 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4758 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4760 self.assertEqual(obj_decoded.expl_offset, offset)
4761 for obj_inner in obj_decoded:
4762 self.assertIn(obj_inner, obj_decoded)
4763 self.assertSequenceEqual(
4766 obj_inner.offset - offset:
4767 obj_inner.offset + obj_inner.tlvlen - offset
4772 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
4773 class SeqOf(SequenceOf):
4777 def _test_symmetric_compare_objs(self, obj1, obj2):
4778 self.assertEqual(obj1, obj2)
4779 self.assertSequenceEqual(list(obj1), list(obj2))
4782 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
4787 def _test_symmetric_compare_objs(self, obj1, obj2):
4788 self.assertSetEqual(
4789 set(int(v) for v in obj1),
4790 set(int(v) for v in obj2),
4793 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4794 @given(data_strategy())
4795 def test_sorted(self, d):
4796 values = [OctetString(v) for v in d.draw(lists(binary()))]
4799 schema = OctetString()
4801 seq_encoded = seq.encode()
4802 seq_decoded, _ = seq.decode(seq_encoded)
4803 self.assertSequenceEqual(
4804 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4805 b"".join(sorted([v.encode() for v in values])),
4809 class TestGoMarshalVectors(TestCase):
4811 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
4812 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
4813 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
4814 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
4815 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
4817 class Seq(Sequence):
4819 ("erste", Integer()),
4820 ("zweite", Integer(optional=True))
4823 seq["erste"] = Integer(64)
4824 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4825 seq["erste"] = Integer(0x123456)
4826 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
4827 seq["erste"] = Integer(64)
4828 seq["zweite"] = Integer(65)
4829 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
4831 class NestedSeq(Sequence):
4835 seq["erste"] = Integer(127)
4836 seq["zweite"] = None
4837 nested = NestedSeq()
4838 nested["nest"] = seq
4839 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
4841 self.assertSequenceEqual(
4842 OctetString(b"\x01\x02\x03").encode(),
4843 hexdec("0403010203"),
4846 class Seq(Sequence):
4848 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
4851 seq["erste"] = Integer(64)
4852 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
4854 class Seq(Sequence):
4856 ("erste", Integer(expl=tag_ctxc(5))),
4859 seq["erste"] = Integer(64)
4860 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
4862 class Seq(Sequence):
4865 impl=tag_encode(0, klass=TagClassContext),
4870 seq["erste"] = Null()
4871 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
4873 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4875 self.assertSequenceEqual(
4876 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
4877 hexdec("170d3730303130313030303030305a"),
4879 self.assertSequenceEqual(
4880 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
4881 hexdec("170d3039313131353232353631365a"),
4883 self.assertSequenceEqual(
4884 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
4885 hexdec("180f32313030303430353132303130315a"),
4888 class Seq(Sequence):
4890 ("erste", GeneralizedTime()),
4893 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
4894 self.assertSequenceEqual(
4896 hexdec("3011180f32303039313131353232353631365a"),
4899 self.assertSequenceEqual(
4900 BitString((1, b"\x80")).encode(),
4903 self.assertSequenceEqual(
4904 BitString((12, b"\x81\xF0")).encode(),
4905 hexdec("03030481f0"),
4908 self.assertSequenceEqual(
4909 ObjectIdentifier("1.2.3.4").encode(),
4910 hexdec("06032a0304"),
4912 self.assertSequenceEqual(
4913 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
4914 hexdec("06092a864888932d010105"),
4916 self.assertSequenceEqual(
4917 ObjectIdentifier("2.100.3").encode(),
4918 hexdec("0603813403"),
4921 self.assertSequenceEqual(
4922 PrintableString("test").encode(),
4923 hexdec("130474657374"),
4925 self.assertSequenceEqual(
4926 PrintableString("x" * 127).encode(),
4927 hexdec("137F" + "78" * 127),
4929 self.assertSequenceEqual(
4930 PrintableString("x" * 128).encode(),
4931 hexdec("138180" + "78" * 128),
4933 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
4935 class Seq(Sequence):
4937 ("erste", IA5String()),
4940 seq["erste"] = IA5String("test")
4941 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
4943 class Seq(Sequence):
4945 ("erste", PrintableString()),
4948 seq["erste"] = PrintableString("test")
4949 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
4950 seq["erste"] = PrintableString("test*")
4951 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
4953 class Seq(Sequence):
4955 ("erste", Any(optional=True)),
4956 ("zweite", Integer()),
4959 seq["zweite"] = Integer(64)
4960 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4965 seq.append(Integer(10))
4966 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
4968 class _SeqOf(SequenceOf):
4969 schema = PrintableString()
4971 class SeqOf(SequenceOf):
4974 _seqof.append(PrintableString("1"))
4976 seqof.append(_seqof)
4977 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
4979 class Seq(Sequence):
4981 ("erste", Integer(default=1)),
4984 seq["erste"] = Integer(0)
4985 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
4986 seq["erste"] = Integer(1)
4987 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4988 seq["erste"] = Integer(2)
4989 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
4992 class TestPP(TestCase):
4993 @given(data_strategy())
4994 def test_oid_printing(self, d):
4996 str(ObjectIdentifier(k)): v * 2
4997 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
4999 chosen = d.draw(sampled_from(sorted(oids)))
5000 chosen_id = oids[chosen]
5001 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5002 self.assertNotIn(chosen_id, pp_console_row(pp))
5003 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5006 class TestAutoAddSlots(TestCase):
5008 class Inher(Integer):
5011 with self.assertRaises(AttributeError):
5013 inher.unexistent = "whatever"
5016 class TestOIDDefines(TestCase):
5017 @given(data_strategy())
5018 def runTest(self, d):
5019 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5020 value_name_chosen = d.draw(sampled_from(value_names))
5022 ObjectIdentifier(oid)
5023 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5025 oid_chosen = d.draw(sampled_from(oids))
5026 values = d.draw(lists(
5028 min_size=len(value_names),
5029 max_size=len(value_names),
5032 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5033 oid: Integer() for oid in oids[:-1]
5036 for i, value_name in enumerate(value_names):
5037 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5039 class Seq(Sequence):
5042 for value_name, value in zip(value_names, values):
5043 seq[value_name] = Any(Integer(value).encode())
5044 seq["type"] = oid_chosen
5045 seq, _ = Seq().decode(seq.encode())
5046 for value_name in value_names:
5047 if value_name == value_name_chosen:
5049 self.assertIsNone(seq[value_name].defined)
5050 if value_name_chosen in oids[:-1]:
5051 self.assertIsNotNone(seq[value_name_chosen].defined)
5052 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5053 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5056 class TestDefinesByPath(TestCase):
5057 def test_generated(self):
5058 class Seq(Sequence):
5060 ("type", ObjectIdentifier()),
5061 ("value", OctetString(expl=tag_ctxc(123))),
5064 class SeqInner(Sequence):
5066 ("typeInner", ObjectIdentifier()),
5067 ("valueInner", Any()),
5070 class PairValue(SetOf):
5073 class Pair(Sequence):
5075 ("type", ObjectIdentifier()),
5076 ("value", PairValue()),
5079 class Pairs(SequenceOf):
5086 type_octet_stringed,
5088 ObjectIdentifier(oid)
5089 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5091 seq_integered = Seq()
5092 seq_integered["type"] = type_integered
5093 seq_integered["value"] = OctetString(Integer(123).encode())
5094 seq_integered_raw = seq_integered.encode()
5098 (type_octet_stringed, OctetString(b"whatever")),
5099 (type_integered, Integer(123)),
5100 (type_octet_stringed, OctetString(b"whenever")),
5101 (type_integered, Integer(234)),
5103 for t, v in pairs_input:
5106 pair["value"] = PairValue((Any(v),))
5108 seq_inner = SeqInner()
5109 seq_inner["typeInner"] = type_innered
5110 seq_inner["valueInner"] = Any(pairs)
5111 seq_sequenced = Seq()
5112 seq_sequenced["type"] = type_sequenced
5113 seq_sequenced["value"] = OctetString(seq_inner.encode())
5114 seq_sequenced_raw = seq_sequenced.encode()
5116 defines_by_path = []
5117 seq_integered, _ = Seq().decode(seq_integered_raw)
5118 self.assertIsNone(seq_integered["value"].defined)
5119 defines_by_path.append(
5120 (("type",), ((("value",), {
5121 type_integered: Integer(),
5122 type_sequenced: SeqInner(),
5125 seq_integered, _ = Seq().decode(
5127 ctx={"defines_by_path": defines_by_path},
5129 self.assertIsNotNone(seq_integered["value"].defined)
5130 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5131 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5132 self.assertTrue(seq_integered_raw[
5133 seq_integered["value"].defined[1].offset:
5134 ].startswith(Integer(123).encode()))
5136 seq_sequenced, _ = Seq().decode(
5138 ctx={"defines_by_path": defines_by_path},
5140 self.assertIsNotNone(seq_sequenced["value"].defined)
5141 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5142 seq_inner = seq_sequenced["value"].defined[1]
5143 self.assertIsNone(seq_inner["valueInner"].defined)
5145 defines_by_path.append((
5146 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5147 ((("valueInner",), {type_innered: Pairs()}),),
5149 seq_sequenced, _ = Seq().decode(
5151 ctx={"defines_by_path": defines_by_path},
5153 self.assertIsNotNone(seq_sequenced["value"].defined)
5154 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5155 seq_inner = seq_sequenced["value"].defined[1]
5156 self.assertIsNotNone(seq_inner["valueInner"].defined)
5157 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5158 pairs = seq_inner["valueInner"].defined[1]
5160 self.assertIsNone(pair["value"][0].defined)
5162 defines_by_path.append((
5165 DecodePathDefBy(type_sequenced),
5167 DecodePathDefBy(type_innered),
5172 type_integered: Integer(),
5173 type_octet_stringed: OctetString(),
5176 seq_sequenced, _ = Seq().decode(
5178 ctx={"defines_by_path": defines_by_path},
5180 self.assertIsNotNone(seq_sequenced["value"].defined)
5181 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5182 seq_inner = seq_sequenced["value"].defined[1]
5183 self.assertIsNotNone(seq_inner["valueInner"].defined)
5184 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5185 pairs_got = seq_inner["valueInner"].defined[1]
5186 for pair_input, pair_got in zip(pairs_input, pairs_got):
5187 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5188 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5190 @given(oid_strategy(), integers())
5191 def test_simple(self, oid, tgt):
5192 class Inner(Sequence):
5194 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5195 ObjectIdentifier(oid): Integer(),
5199 class Outer(Sequence):
5202 ("tgt", OctetString()),
5206 inner["oid"] = ObjectIdentifier(oid)
5208 outer["inner"] = inner
5209 outer["tgt"] = OctetString(Integer(tgt).encode())
5210 decoded, _ = Outer().decode(outer.encode())
5211 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5214 class TestAbsDecodePath(TestCase):
5216 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5217 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5219 def test_concat(self, decode_path, rel_path):
5220 self.assertSequenceEqual(
5221 abs_decode_path(decode_path, rel_path),
5222 decode_path + rel_path,
5226 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5227 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5229 def test_abs(self, decode_path, rel_path):
5230 self.assertSequenceEqual(
5231 abs_decode_path(decode_path, ("/",) + rel_path),
5236 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5237 integers(min_value=1, max_value=3),
5238 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5240 def test_dots(self, decode_path, number_of_dots, rel_path):
5241 self.assertSequenceEqual(
5242 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5243 decode_path[:-number_of_dots] + rel_path,
5247 class TestStrictDefaultExistence(TestCase):
5248 @given(data_strategy())
5249 def runTest(self, d):
5250 count = d.draw(integers(min_value=1, max_value=10))
5251 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5253 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5254 for i in range(count)
5257 class Seq(Sequence):
5260 for i in range(count):
5261 seq["int%d" % i] = Integer(123)
5263 chosen = "int%d" % chosen
5264 seq.specs[chosen] = seq.specs[chosen](default=123)
5266 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5267 seq.decode(raw, ctx={"strict_default_existence": True})