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(min_size=1), 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)
297 @given(binary(min_size=1))
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(min_size=1), binary(min_size=1))
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)),
2243 def test_x690_vector(self):
2245 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2246 ObjectIdentifier((2, 999, 3)),
2251 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2253 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2254 values = list(draw(sets(
2256 min_size=len(schema),
2257 max_size=len(schema),
2259 schema = list(zip(schema, values))
2260 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2264 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2266 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2267 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2268 optional = draw(one_of(none(), booleans()))
2270 draw(integers(min_value=0)),
2271 draw(integers(min_value=0)),
2272 draw(integers(min_value=0)),
2274 return (schema, value, impl, expl, default, optional, _decoded)
2277 class TestEnumerated(CommonMixin, TestCase):
2278 class EWhatever(Enumerated):
2279 schema = (("whatever", 0),)
2281 base_klass = EWhatever
2283 def test_schema_required(self):
2284 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2287 def test_invalid_value_type(self):
2288 with self.assertRaises(InvalidValueType) as err:
2289 self.base_klass((1, 2))
2292 @given(sets(text_letters(), min_size=2))
2293 def test_unknown_name(self, schema_input):
2294 missing = schema_input.pop()
2296 class E(Enumerated):
2297 schema = [(n, 123) for n in schema_input]
2298 with self.assertRaises(ObjUnknown) as err:
2303 sets(text_letters(), min_size=2),
2304 sets(integers(), min_size=2),
2306 def test_unknown_value(self, schema_input, values_input):
2308 missing_value = values_input.pop()
2309 _input = list(zip(schema_input, values_input))
2311 class E(Enumerated):
2313 with self.assertRaises(DecodeError) as err:
2318 def test_optional(self, optional):
2319 obj = self.base_klass(default="whatever", optional=optional)
2320 self.assertTrue(obj.optional)
2322 def test_ready(self):
2323 obj = self.base_klass()
2324 self.assertFalse(obj.ready)
2327 with self.assertRaises(ObjNotReady) as err:
2330 obj = self.base_klass("whatever")
2331 self.assertTrue(obj.ready)
2335 @given(integers(), integers(), binary(), binary())
2336 def test_comparison(self, value1, value2, tag1, tag2):
2337 class E(Enumerated):
2339 ("whatever0", value1),
2340 ("whatever1", value2),
2343 class EInherited(E):
2345 for klass in (E, EInherited):
2346 obj1 = klass(value1)
2347 obj2 = klass(value2)
2348 self.assertEqual(obj1 == obj2, value1 == value2)
2349 self.assertEqual(obj1 != obj2, value1 != value2)
2350 self.assertEqual(obj1 == int(obj2), value1 == value2)
2351 obj1 = klass(value1, impl=tag1)
2352 obj2 = klass(value1, impl=tag2)
2353 self.assertEqual(obj1 == obj2, tag1 == tag2)
2354 self.assertEqual(obj1 != obj2, tag1 != tag2)
2356 @given(data_strategy())
2357 def test_call(self, d):
2366 ) = d.draw(enumerated_values_strategy())
2368 class E(Enumerated):
2369 schema = schema_initial
2371 value=value_initial,
2374 default=default_initial,
2375 optional=optional_initial or False,
2376 _decoded=_decoded_initial,
2386 ) = d.draw(enumerated_values_strategy(
2387 schema=schema_initial,
2388 do_expl=impl_initial is None,
2398 value_expected = default if value is None else value
2400 default_initial if value_expected is None
2405 dict(schema_initial).get(value_expected, value_expected),
2407 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2408 self.assertEqual(obj.expl_tag, expl or expl_initial)
2411 default_initial if default is None else default,
2413 if obj.default is None:
2414 optional = optional_initial if optional is None else optional
2415 optional = False if optional is None else optional
2418 self.assertEqual(obj.optional, optional)
2419 self.assertEqual(obj.specs, dict(schema_initial))
2421 @given(enumerated_values_strategy())
2422 def test_copy(self, values):
2423 schema_input, value, impl, expl, default, optional, _decoded = values
2425 class E(Enumerated):
2426 schema = schema_input
2435 obj_copied = obj.copy()
2436 self.assert_copied_basic_fields(obj, obj_copied)
2437 self.assertEqual(obj.specs, obj_copied.specs)
2439 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2440 @given(data_strategy())
2441 def test_symmetric(self, d):
2442 schema_input, _, _, _, default, optional, _decoded = d.draw(
2443 enumerated_values_strategy(),
2445 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2446 offset = d.draw(integers(min_value=0))
2447 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2448 tail_junk = d.draw(binary(max_size=5))
2450 class E(Enumerated):
2451 schema = schema_input
2460 self.assertFalse(obj.expled)
2461 obj_encoded = obj.encode()
2462 obj_expled = obj(value, expl=tag_expl)
2463 self.assertTrue(obj_expled.expled)
2466 obj_expled_encoded = obj_expled.encode()
2467 obj_decoded, tail = obj_expled.decode(
2468 obj_expled_encoded + tail_junk,
2473 self.assertEqual(tail, tail_junk)
2474 self.assertEqual(obj_decoded, obj_expled)
2475 self.assertNotEqual(obj_decoded, obj)
2476 self.assertEqual(int(obj_decoded), int(obj_expled))
2477 self.assertEqual(int(obj_decoded), int(obj))
2478 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2479 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2480 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2482 obj_decoded.expl_llen,
2483 len(len_encode(len(obj_encoded))),
2485 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2486 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2489 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2491 self.assertEqual(obj_decoded.expl_offset, offset)
2495 def string_values_strategy(draw, alphabet, do_expl=False):
2496 bound_min, bound_max = sorted(draw(sets(
2497 integers(min_value=0, max_value=1 << 7),
2501 value = draw(one_of(
2503 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2505 default = draw(one_of(
2507 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2510 if draw(booleans()):
2511 bounds = (bound_min, bound_max)
2515 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2517 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2518 optional = draw(one_of(none(), booleans()))
2520 draw(integers(min_value=0)),
2521 draw(integers(min_value=0)),
2522 draw(integers(min_value=0)),
2524 return (value, bounds, impl, expl, default, optional, _decoded)
2527 class StringMixin(object):
2528 def test_invalid_value_type(self):
2529 with self.assertRaises(InvalidValueType) as err:
2530 self.base_klass((1, 2))
2533 def text_alphabet(self):
2534 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2535 return printable + whitespace
2539 def test_optional(self, optional):
2540 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2541 self.assertTrue(obj.optional)
2543 @given(data_strategy())
2544 def test_ready(self, d):
2545 obj = self.base_klass()
2546 self.assertFalse(obj.ready)
2550 with self.assertRaises(ObjNotReady) as err:
2553 value = d.draw(text(alphabet=self.text_alphabet()))
2554 obj = self.base_klass(value)
2555 self.assertTrue(obj.ready)
2560 @given(data_strategy())
2561 def test_comparison(self, d):
2562 value1 = d.draw(text(alphabet=self.text_alphabet()))
2563 value2 = d.draw(text(alphabet=self.text_alphabet()))
2564 tag1 = d.draw(binary(min_size=1))
2565 tag2 = d.draw(binary(min_size=1))
2566 obj1 = self.base_klass(value1)
2567 obj2 = self.base_klass(value2)
2568 self.assertEqual(obj1 == obj2, value1 == value2)
2569 self.assertEqual(obj1 != obj2, value1 != value2)
2570 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2571 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2572 obj1 = self.base_klass(value1, impl=tag1)
2573 obj2 = self.base_klass(value1, impl=tag2)
2574 self.assertEqual(obj1 == obj2, tag1 == tag2)
2575 self.assertEqual(obj1 != obj2, tag1 != tag2)
2577 @given(data_strategy())
2578 def test_bounds_satisfied(self, d):
2579 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2580 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2581 value = d.draw(text(
2582 alphabet=self.text_alphabet(),
2586 self.base_klass(value=value, bounds=(bound_min, bound_max))
2588 @given(data_strategy())
2589 def test_bounds_unsatisfied(self, d):
2590 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2591 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2592 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2593 with self.assertRaises(BoundsError) as err:
2594 self.base_klass(value=value, bounds=(bound_min, bound_max))
2596 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2597 with self.assertRaises(BoundsError) as err:
2598 self.base_klass(value=value, bounds=(bound_min, bound_max))
2601 @given(data_strategy())
2602 def test_call(self, d):
2611 ) = d.draw(string_values_strategy(self.text_alphabet()))
2612 obj_initial = self.base_klass(
2618 optional_initial or False,
2629 ) = d.draw(string_values_strategy(
2630 self.text_alphabet(),
2631 do_expl=impl_initial is None,
2633 if (default is None) and (obj_initial.default is not None):
2636 (bounds is None) and
2637 (value is not None) and
2638 (bounds_initial is not None) and
2639 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2643 (bounds is None) and
2644 (default is not None) and
2645 (bounds_initial is not None) and
2646 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2649 obj = obj_initial(value, bounds, impl, expl, default, optional)
2651 value_expected = default if value is None else value
2653 default_initial if value_expected is None
2656 self.assertEqual(obj, value_expected)
2657 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2658 self.assertEqual(obj.expl_tag, expl or expl_initial)
2661 default_initial if default is None else default,
2663 if obj.default is None:
2664 optional = optional_initial if optional is None else optional
2665 optional = False if optional is None else optional
2668 self.assertEqual(obj.optional, optional)
2670 (obj._bound_min, obj._bound_max),
2671 bounds or bounds_initial or (0, float("+inf")),
2674 @given(data_strategy())
2675 def test_copy(self, d):
2676 values = d.draw(string_values_strategy(self.text_alphabet()))
2677 obj = self.base_klass(*values)
2678 obj_copied = obj.copy()
2679 self.assert_copied_basic_fields(obj, obj_copied)
2680 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2681 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2682 self.assertEqual(obj._value, obj_copied._value)
2684 @given(data_strategy())
2685 def test_stripped(self, d):
2686 value = d.draw(text(alphabet=self.text_alphabet()))
2687 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2688 obj = self.base_klass(value, impl=tag_impl)
2689 with self.assertRaises(NotEnoughData):
2690 obj.decode(obj.encode()[:-1])
2692 @given(data_strategy())
2693 def test_stripped_expl(self, d):
2694 value = d.draw(text(alphabet=self.text_alphabet()))
2695 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2696 obj = self.base_klass(value, expl=tag_expl)
2697 with self.assertRaises(NotEnoughData):
2698 obj.decode(obj.encode()[:-1])
2701 integers(min_value=31),
2702 integers(min_value=0),
2705 def test_bad_tag(self, tag, offset, decode_path):
2706 decode_path = tuple(str(i) for i in decode_path)
2707 with self.assertRaises(DecodeError) as err:
2708 self.base_klass().decode(
2709 tag_encode(tag)[:-1],
2711 decode_path=decode_path,
2714 self.assertEqual(err.exception.offset, offset)
2715 self.assertEqual(err.exception.decode_path, decode_path)
2718 integers(min_value=128),
2719 integers(min_value=0),
2722 def test_bad_len(self, l, offset, decode_path):
2723 decode_path = tuple(str(i) for i in decode_path)
2724 with self.assertRaises(DecodeError) as err:
2725 self.base_klass().decode(
2726 self.base_klass.tag_default + len_encode(l)[:-1],
2728 decode_path=decode_path,
2731 self.assertEqual(err.exception.offset, offset)
2732 self.assertEqual(err.exception.decode_path, decode_path)
2735 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2736 integers(min_value=0),
2739 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2740 decode_path = tuple(str(i) for i in decode_path)
2741 value, bound_min = list(sorted(ints))
2743 class String(self.base_klass):
2744 # Multiply this value by four, to satisfy UTF-32 bounds
2745 # (4 bytes per character) validation
2746 bounds = (bound_min * 4, bound_min * 4)
2747 with self.assertRaises(DecodeError) as err:
2749 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2751 decode_path=decode_path,
2754 self.assertEqual(err.exception.offset, offset)
2755 self.assertEqual(err.exception.decode_path, decode_path)
2757 @given(data_strategy())
2758 def test_symmetric(self, d):
2759 values = d.draw(string_values_strategy(self.text_alphabet()))
2760 value = d.draw(text(alphabet=self.text_alphabet()))
2761 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2762 offset = d.draw(integers(min_value=0))
2763 tail_junk = d.draw(binary(max_size=5))
2764 _, _, _, _, default, optional, _decoded = values
2765 obj = self.base_klass(
2773 self.assertFalse(obj.expled)
2774 obj_encoded = obj.encode()
2775 obj_expled = obj(value, expl=tag_expl)
2776 self.assertTrue(obj_expled.expled)
2779 obj_expled_encoded = obj_expled.encode()
2780 obj_decoded, tail = obj_expled.decode(
2781 obj_expled_encoded + tail_junk,
2786 self.assertEqual(tail, tail_junk)
2787 self.assertEqual(obj_decoded, obj_expled)
2788 self.assertNotEqual(obj_decoded, obj)
2789 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2790 self.assertEqual(bytes(obj_decoded), bytes(obj))
2791 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2792 self.assertEqual(text_type(obj_decoded), text_type(obj))
2793 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2794 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2795 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2797 obj_decoded.expl_llen,
2798 len(len_encode(len(obj_encoded))),
2800 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2801 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2804 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2806 self.assertEqual(obj_decoded.expl_offset, offset)
2809 class TestUTF8String(StringMixin, CommonMixin, TestCase):
2810 base_klass = UTF8String
2813 class UnicodeDecodeErrorMixin(object):
2815 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
2819 def test_unicode_decode_error(self, cyrillic_text):
2820 with self.assertRaises(DecodeError):
2821 self.base_klass(cyrillic_text)
2824 class TestNumericString(StringMixin, CommonMixin, TestCase):
2825 base_klass = NumericString
2827 def text_alphabet(self):
2830 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
2831 def test_non_numeric(self, cyrillic_text):
2832 with assertRaisesRegex(self, DecodeError, "non-numeric"):
2833 self.base_klass(cyrillic_text)
2836 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2837 integers(min_value=0),
2840 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2841 decode_path = tuple(str(i) for i in decode_path)
2842 value, bound_min = list(sorted(ints))
2844 class String(self.base_klass):
2845 bounds = (bound_min, bound_min)
2846 with self.assertRaises(DecodeError) as err:
2848 self.base_klass(b"1" * value).encode(),
2850 decode_path=decode_path,
2853 self.assertEqual(err.exception.offset, offset)
2854 self.assertEqual(err.exception.decode_path, decode_path)
2857 class TestPrintableString(
2858 UnicodeDecodeErrorMixin,
2863 base_klass = PrintableString
2866 class TestTeletexString(
2867 UnicodeDecodeErrorMixin,
2872 base_klass = TeletexString
2875 class TestVideotexString(
2876 UnicodeDecodeErrorMixin,
2881 base_klass = VideotexString
2884 class TestIA5String(
2885 UnicodeDecodeErrorMixin,
2890 base_klass = IA5String
2893 class TestGraphicString(
2894 UnicodeDecodeErrorMixin,
2899 base_klass = GraphicString
2902 class TestVisibleString(
2903 UnicodeDecodeErrorMixin,
2908 base_klass = VisibleString
2910 def test_x690_vector(self):
2912 str(VisibleString().decode(hexdec("1A054A6F6E6573"))[0]),
2916 str(VisibleString().decode(
2917 hexdec("3A0904034A6F6E04026573"),
2918 ctx={"bered": True},
2923 str(VisibleString().decode(
2924 hexdec("3A8004034A6F6E040265730000"),
2925 ctx={"bered": True},
2931 class TestGeneralString(
2932 UnicodeDecodeErrorMixin,
2937 base_klass = GeneralString
2940 class TestUniversalString(StringMixin, CommonMixin, TestCase):
2941 base_klass = UniversalString
2944 class TestBMPString(StringMixin, CommonMixin, TestCase):
2945 base_klass = BMPString
2949 def generalized_time_values_strategy(
2957 if draw(booleans()):
2958 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2960 value = value.replace(microsecond=0)
2962 if draw(booleans()):
2963 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2965 default = default.replace(microsecond=0)
2969 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2971 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2972 optional = draw(one_of(none(), booleans()))
2974 draw(integers(min_value=0)),
2975 draw(integers(min_value=0)),
2976 draw(integers(min_value=0)),
2978 return (value, impl, expl, default, optional, _decoded)
2981 class TimeMixin(object):
2982 def test_invalid_value_type(self):
2983 with self.assertRaises(InvalidValueType) as err:
2984 self.base_klass(datetime.now().timetuple())
2987 @given(data_strategy())
2988 def test_optional(self, d):
2989 default = d.draw(datetimes(
2990 min_value=self.min_datetime,
2991 max_value=self.max_datetime,
2993 optional = d.draw(booleans())
2994 obj = self.base_klass(default=default, optional=optional)
2995 self.assertTrue(obj.optional)
2997 @given(data_strategy())
2998 def test_ready(self, d):
2999 obj = self.base_klass()
3000 self.assertFalse(obj.ready)
3003 with self.assertRaises(ObjNotReady) as err:
3006 value = d.draw(datetimes(min_value=self.min_datetime))
3007 obj = self.base_klass(value)
3008 self.assertTrue(obj.ready)
3012 @given(data_strategy())
3013 def test_comparison(self, d):
3014 value1 = d.draw(datetimes(
3015 min_value=self.min_datetime,
3016 max_value=self.max_datetime,
3018 value2 = d.draw(datetimes(
3019 min_value=self.min_datetime,
3020 max_value=self.max_datetime,
3022 tag1 = d.draw(binary(min_size=1))
3023 tag2 = d.draw(binary(min_size=1))
3025 value1 = value1.replace(microsecond=0)
3026 value2 = value2.replace(microsecond=0)
3027 obj1 = self.base_klass(value1)
3028 obj2 = self.base_klass(value2)
3029 self.assertEqual(obj1 == obj2, value1 == value2)
3030 self.assertEqual(obj1 != obj2, value1 != value2)
3031 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3032 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3033 obj1 = self.base_klass(value1, impl=tag1)
3034 obj2 = self.base_klass(value1, impl=tag2)
3035 self.assertEqual(obj1 == obj2, tag1 == tag2)
3036 self.assertEqual(obj1 != obj2, tag1 != tag2)
3038 @given(data_strategy())
3039 def test_call(self, d):
3047 ) = d.draw(generalized_time_values_strategy(
3048 min_datetime=self.min_datetime,
3049 max_datetime=self.max_datetime,
3050 omit_ms=self.omit_ms,
3052 obj_initial = self.base_klass(
3053 value=value_initial,
3056 default=default_initial,
3057 optional=optional_initial or False,
3058 _decoded=_decoded_initial,
3067 ) = d.draw(generalized_time_values_strategy(
3068 min_datetime=self.min_datetime,
3069 max_datetime=self.max_datetime,
3070 omit_ms=self.omit_ms,
3071 do_expl=impl_initial is None,
3081 value_expected = default if value is None else value
3083 default_initial if value_expected is None
3086 self.assertEqual(obj, value_expected)
3087 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3088 self.assertEqual(obj.expl_tag, expl or expl_initial)
3091 default_initial if default is None else default,
3093 if obj.default is None:
3094 optional = optional_initial if optional is None else optional
3095 optional = False if optional is None else optional
3098 self.assertEqual(obj.optional, optional)
3100 @given(data_strategy())
3101 def test_copy(self, d):
3102 values = d.draw(generalized_time_values_strategy(
3103 min_datetime=self.min_datetime,
3104 max_datetime=self.max_datetime,
3106 obj = self.base_klass(*values)
3107 obj_copied = obj.copy()
3108 self.assert_copied_basic_fields(obj, obj_copied)
3109 self.assertEqual(obj._value, obj_copied._value)
3111 @given(data_strategy())
3112 def test_stripped(self, d):
3113 value = d.draw(datetimes(
3114 min_value=self.min_datetime,
3115 max_value=self.max_datetime,
3117 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3118 obj = self.base_klass(value, impl=tag_impl)
3119 with self.assertRaises(NotEnoughData):
3120 obj.decode(obj.encode()[:-1])
3122 @given(data_strategy())
3123 def test_stripped_expl(self, d):
3124 value = d.draw(datetimes(
3125 min_value=self.min_datetime,
3126 max_value=self.max_datetime,
3128 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3129 obj = self.base_klass(value, expl=tag_expl)
3130 with self.assertRaises(NotEnoughData):
3131 obj.decode(obj.encode()[:-1])
3133 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3134 @given(data_strategy())
3135 def test_symmetric(self, d):
3136 values = d.draw(generalized_time_values_strategy(
3137 min_datetime=self.min_datetime,
3138 max_datetime=self.max_datetime,
3140 value = d.draw(datetimes(
3141 min_value=self.min_datetime,
3142 max_value=self.max_datetime,
3144 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3145 offset = d.draw(integers(min_value=0))
3146 tail_junk = d.draw(binary(max_size=5))
3147 _, _, _, default, optional, _decoded = values
3148 obj = self.base_klass(
3156 self.assertFalse(obj.expled)
3157 obj_encoded = obj.encode()
3158 obj_expled = obj(value, expl=tag_expl)
3159 self.assertTrue(obj_expled.expled)
3162 obj_expled_encoded = obj_expled.encode()
3163 obj_decoded, tail = obj_expled.decode(
3164 obj_expled_encoded + tail_junk,
3169 self.assertEqual(tail, tail_junk)
3170 self.assertEqual(obj_decoded, obj_expled)
3171 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3172 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3173 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3174 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3175 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3177 obj_decoded.expl_llen,
3178 len(len_encode(len(obj_encoded))),
3180 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3181 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3184 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3186 self.assertEqual(obj_decoded.expl_offset, offset)
3189 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3190 base_klass = GeneralizedTime
3192 min_datetime = datetime(1900, 1, 1)
3193 max_datetime = datetime(9999, 12, 31)
3195 def test_go_vectors_invalid(self):
3207 b"-20100102030410Z",
3208 b"2010-0102030410Z",
3209 b"2010-0002030410Z",
3210 b"201001-02030410Z",
3211 b"20100102-030410Z",
3212 b"2010010203-0410Z",
3213 b"201001020304-10Z",
3214 # These ones are INVALID in *DER*, but accepted
3215 # by Go's encoding/asn1
3216 b"20100102030405+0607",
3217 b"20100102030405-0607",
3219 with self.assertRaises(DecodeError) as err:
3220 GeneralizedTime(data)
3223 def test_go_vectors_valid(self):
3225 GeneralizedTime(b"20100102030405Z").todatetime(),
3226 datetime(2010, 1, 2, 3, 4, 5, 0),
3230 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3231 base_klass = UTCTime
3233 min_datetime = datetime(2000, 1, 1)
3234 max_datetime = datetime(2049, 12, 31)
3236 def test_go_vectors_invalid(self):
3262 # These ones are INVALID in *DER*, but accepted
3263 # by Go's encoding/asn1
3264 b"910506164540-0700",
3265 b"910506164540+0730",
3269 with self.assertRaises(DecodeError) as err:
3273 def test_go_vectors_valid(self):
3275 UTCTime(b"910506234540Z").todatetime(),
3276 datetime(1991, 5, 6, 23, 45, 40, 0),
3279 @given(integers(min_value=0, max_value=49))
3280 def test_pre50(self, year):
3282 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3286 @given(integers(min_value=50, max_value=99))
3287 def test_post50(self, year):
3289 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3295 def any_values_strategy(draw, do_expl=False):
3296 value = draw(one_of(none(), binary()))
3299 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3300 optional = draw(one_of(none(), booleans()))
3302 draw(integers(min_value=0)),
3303 draw(integers(min_value=0)),
3304 draw(integers(min_value=0)),
3306 return (value, expl, optional, _decoded)
3309 class AnyInherited(Any):
3313 class TestAny(CommonMixin, TestCase):
3316 def test_invalid_value_type(self):
3317 with self.assertRaises(InvalidValueType) as err:
3322 def test_optional(self, optional):
3323 obj = Any(optional=optional)
3324 self.assertEqual(obj.optional, optional)
3327 def test_ready(self, value):
3329 self.assertFalse(obj.ready)
3332 with self.assertRaises(ObjNotReady) as err:
3336 self.assertTrue(obj.ready)
3341 def test_basic(self, value):
3342 integer_encoded = Integer(value).encode()
3344 Any(integer_encoded),
3345 Any(Integer(value)),
3346 Any(Any(Integer(value))),
3348 self.assertSequenceEqual(bytes(obj), integer_encoded)
3350 obj.decode(obj.encode())[0].vlen,
3351 len(integer_encoded),
3355 self.assertSequenceEqual(obj.encode(), integer_encoded)
3357 @given(binary(), binary())
3358 def test_comparison(self, value1, value2):
3359 for klass in (Any, AnyInherited):
3360 obj1 = klass(value1)
3361 obj2 = klass(value2)
3362 self.assertEqual(obj1 == obj2, value1 == value2)
3363 self.assertEqual(obj1 != obj2, value1 != value2)
3364 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3366 @given(data_strategy())
3367 def test_call(self, d):
3368 for klass in (Any, AnyInherited):
3374 ) = d.draw(any_values_strategy())
3375 obj_initial = klass(
3378 optional_initial or False,
3386 ) = d.draw(any_values_strategy(do_expl=True))
3387 obj = obj_initial(value, expl, optional)
3389 value_expected = None if value is None else value
3390 self.assertEqual(obj, value_expected)
3391 self.assertEqual(obj.expl_tag, expl or expl_initial)
3392 if obj.default is None:
3393 optional = optional_initial if optional is None else optional
3394 optional = False if optional is None else optional
3395 self.assertEqual(obj.optional, optional)
3397 def test_simultaneous_impl_expl(self):
3398 # override it, as Any does not have implicit tag
3401 def test_decoded(self):
3402 # override it, as Any does not have implicit tag
3405 @given(any_values_strategy())
3406 def test_copy(self, values):
3407 for klass in (Any, AnyInherited):
3408 obj = klass(*values)
3409 obj_copied = obj.copy()
3410 self.assert_copied_basic_fields(obj, obj_copied)
3411 self.assertEqual(obj._value, obj_copied._value)
3413 @given(binary().map(OctetString))
3414 def test_stripped(self, value):
3416 with self.assertRaises(NotEnoughData):
3417 obj.decode(obj.encode()[:-1])
3421 integers(min_value=1).map(tag_ctxc),
3423 def test_stripped_expl(self, value, tag_expl):
3424 obj = Any(value, expl=tag_expl)
3425 with self.assertRaises(NotEnoughData):
3426 obj.decode(obj.encode()[:-1])
3429 integers(min_value=31),
3430 integers(min_value=0),
3433 def test_bad_tag(self, tag, offset, decode_path):
3434 decode_path = tuple(str(i) for i in decode_path)
3435 with self.assertRaises(DecodeError) as err:
3437 tag_encode(tag)[:-1],
3439 decode_path=decode_path,
3442 self.assertEqual(err.exception.offset, offset)
3443 self.assertEqual(err.exception.decode_path, decode_path)
3446 integers(min_value=128),
3447 integers(min_value=0),
3450 def test_bad_len(self, l, offset, decode_path):
3451 decode_path = tuple(str(i) for i in decode_path)
3452 with self.assertRaises(DecodeError) as err:
3454 Any.tag_default + len_encode(l)[:-1],
3456 decode_path=decode_path,
3459 self.assertEqual(err.exception.offset, offset)
3460 self.assertEqual(err.exception.decode_path, decode_path)
3462 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3464 any_values_strategy(),
3465 integers().map(lambda x: Integer(x).encode()),
3466 integers(min_value=1).map(tag_ctxc),
3467 integers(min_value=0),
3470 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3471 for klass in (Any, AnyInherited):
3472 _, _, optional, _decoded = values
3473 obj = klass(value=value, optional=optional, _decoded=_decoded)
3476 self.assertFalse(obj.expled)
3477 obj_encoded = obj.encode()
3478 obj_expled = obj(value, expl=tag_expl)
3479 self.assertTrue(obj_expled.expled)
3482 obj_expled_encoded = obj_expled.encode()
3483 obj_decoded, tail = obj_expled.decode(
3484 obj_expled_encoded + tail_junk,
3489 self.assertEqual(tail, tail_junk)
3490 self.assertEqual(obj_decoded, obj_expled)
3491 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3492 self.assertEqual(bytes(obj_decoded), bytes(obj))
3493 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3494 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3495 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3497 obj_decoded.expl_llen,
3498 len(len_encode(len(obj_encoded))),
3500 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3501 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3504 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3506 self.assertEqual(obj_decoded.expl_offset, offset)
3507 self.assertEqual(obj_decoded.tlen, 0)
3508 self.assertEqual(obj_decoded.llen, 0)
3509 self.assertEqual(obj_decoded.vlen, len(value))
3513 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3515 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3516 tags = [tag_encode(tag) for tag in draw(sets(
3517 integers(min_value=0),
3518 min_size=len(names),
3519 max_size=len(names),
3521 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3523 if value_required or draw(booleans()):
3524 value = draw(tuples(
3525 sampled_from([name for name, _ in schema]),
3526 integers().map(Integer),
3530 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3531 default = draw(one_of(
3533 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3535 optional = draw(one_of(none(), booleans()))
3537 draw(integers(min_value=0)),
3538 draw(integers(min_value=0)),
3539 draw(integers(min_value=0)),
3541 return (schema, value, expl, default, optional, _decoded)
3544 class ChoiceInherited(Choice):
3548 class TestChoice(CommonMixin, TestCase):
3550 schema = (("whatever", Boolean()),)
3553 def test_schema_required(self):
3554 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3557 def test_impl_forbidden(self):
3558 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3559 Choice(impl=b"whatever")
3561 def test_invalid_value_type(self):
3562 with self.assertRaises(InvalidValueType) as err:
3563 self.base_klass(123)
3565 with self.assertRaises(ObjUnknown) as err:
3566 self.base_klass(("whenever", Boolean(False)))
3568 with self.assertRaises(InvalidValueType) as err:
3569 self.base_klass(("whatever", Integer(123)))
3573 def test_optional(self, optional):
3574 obj = self.base_klass(
3575 default=self.base_klass(("whatever", Boolean(False))),
3578 self.assertTrue(obj.optional)
3581 def test_ready(self, value):
3582 obj = self.base_klass()
3583 self.assertFalse(obj.ready)
3586 self.assertIsNone(obj["whatever"])
3587 with self.assertRaises(ObjNotReady) as err:
3590 obj["whatever"] = Boolean()
3591 self.assertFalse(obj.ready)
3594 obj["whatever"] = Boolean(value)
3595 self.assertTrue(obj.ready)
3599 @given(booleans(), booleans())
3600 def test_comparison(self, value1, value2):
3601 class WahlInherited(self.base_klass):
3603 for klass in (self.base_klass, WahlInherited):
3604 obj1 = klass(("whatever", Boolean(value1)))
3605 obj2 = klass(("whatever", Boolean(value2)))
3606 self.assertEqual(obj1 == obj2, value1 == value2)
3607 self.assertEqual(obj1 != obj2, value1 != value2)
3608 self.assertEqual(obj1 == obj2._value, value1 == value2)
3609 self.assertFalse(obj1 == obj2._value[1])
3611 @given(data_strategy())
3612 def test_call(self, d):
3613 for klass in (Choice, ChoiceInherited):
3621 ) = d.draw(choice_values_strategy())
3624 schema = schema_initial
3626 value=value_initial,
3628 default=default_initial,
3629 optional=optional_initial or False,
3630 _decoded=_decoded_initial,
3639 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
3640 obj = obj_initial(value, expl, default, optional)
3642 value_expected = default if value is None else value
3644 default_initial if value_expected is None
3647 self.assertEqual(obj.choice, value_expected[0])
3648 self.assertEqual(obj.value, int(value_expected[1]))
3649 self.assertEqual(obj.expl_tag, expl or expl_initial)
3650 default_expect = default_initial if default is None else default
3651 if default_expect is not None:
3652 self.assertEqual(obj.default.choice, default_expect[0])
3653 self.assertEqual(obj.default.value, int(default_expect[1]))
3654 if obj.default is None:
3655 optional = optional_initial if optional is None else optional
3656 optional = False if optional is None else optional
3659 self.assertEqual(obj.optional, optional)
3660 self.assertEqual(obj.specs, obj_initial.specs)
3662 def test_simultaneous_impl_expl(self):
3663 # override it, as Any does not have implicit tag
3666 def test_decoded(self):
3667 # override it, as Any does not have implicit tag
3670 @given(choice_values_strategy())
3671 def test_copy(self, values):
3672 _schema, value, expl, default, optional, _decoded = values
3674 class Wahl(self.base_klass):
3680 optional=optional or False,
3683 obj_copied = obj.copy()
3684 self.assertIsNone(obj.tag)
3685 self.assertIsNone(obj_copied.tag)
3686 # hack for assert_copied_basic_fields
3687 obj.tag = "whatever"
3688 obj_copied.tag = "whatever"
3689 self.assert_copied_basic_fields(obj, obj_copied)
3690 self.assertEqual(obj._value, obj_copied._value)
3691 self.assertEqual(obj.specs, obj_copied.specs)
3694 def test_stripped(self, value):
3695 obj = self.base_klass(("whatever", Boolean(value)))
3696 with self.assertRaises(NotEnoughData):
3697 obj.decode(obj.encode()[:-1])
3701 integers(min_value=1).map(tag_ctxc),
3703 def test_stripped_expl(self, value, tag_expl):
3704 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3705 with self.assertRaises(NotEnoughData):
3706 obj.decode(obj.encode()[:-1])
3708 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3709 @given(data_strategy())
3710 def test_symmetric(self, d):
3711 _schema, value, _, default, optional, _decoded = d.draw(
3712 choice_values_strategy(value_required=True)
3714 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3715 offset = d.draw(integers(min_value=0))
3716 tail_junk = d.draw(binary(max_size=5))
3718 class Wahl(self.base_klass):
3728 self.assertFalse(obj.expled)
3729 obj_encoded = obj.encode()
3730 obj_expled = obj(value, expl=tag_expl)
3731 self.assertTrue(obj_expled.expled)
3734 obj_expled_encoded = obj_expled.encode()
3735 obj_decoded, tail = obj_expled.decode(
3736 obj_expled_encoded + tail_junk,
3741 self.assertEqual(tail, tail_junk)
3742 self.assertEqual(obj_decoded, obj_expled)
3743 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3744 self.assertEqual(obj_decoded.value, obj_expled.value)
3745 self.assertEqual(obj_decoded.choice, obj.choice)
3746 self.assertEqual(obj_decoded.value, obj.value)
3747 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3748 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3749 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3751 obj_decoded.expl_llen,
3752 len(len_encode(len(obj_encoded))),
3754 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3755 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3758 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3760 self.assertEqual(obj_decoded.expl_offset, offset)
3761 self.assertSequenceEqual(
3763 obj_decoded.value.offset - offset:
3764 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3770 def test_set_get(self, value):
3773 ("erste", Boolean()),
3774 ("zweite", Integer()),
3777 with self.assertRaises(ObjUnknown) as err:
3778 obj["whatever"] = "whenever"
3779 with self.assertRaises(InvalidValueType) as err:
3780 obj["zweite"] = Boolean(False)
3781 obj["zweite"] = Integer(value)
3783 with self.assertRaises(ObjUnknown) as err:
3786 self.assertIsNone(obj["erste"])
3787 self.assertEqual(obj["zweite"], Integer(value))
3789 def test_tag_mismatch(self):
3792 ("erste", Boolean()),
3794 int_encoded = Integer(123).encode()
3795 bool_encoded = Boolean(False).encode()
3797 obj.decode(bool_encoded)
3798 with self.assertRaises(TagMismatch):
3799 obj.decode(int_encoded)
3801 def test_tag_mismatch_underlying(self):
3802 class SeqOfBoolean(SequenceOf):
3805 class SeqOfInteger(SequenceOf):
3810 ("erste", SeqOfBoolean()),
3813 int_encoded = SeqOfInteger((Integer(123),)).encode()
3814 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
3816 obj.decode(bool_encoded)
3817 with self.assertRaises(TagMismatch) as err:
3818 obj.decode(int_encoded)
3819 self.assertEqual(err.exception.decode_path, ("erste", "0"))
3823 def seq_values_strategy(draw, seq_klass, do_expl=False):
3825 if draw(booleans()):
3828 k: v for k, v in draw(dictionaries(
3831 booleans().map(Boolean),
3832 integers().map(Integer),
3837 if draw(booleans()):
3838 schema = list(draw(dictionaries(
3841 booleans().map(Boolean),
3842 integers().map(Integer),
3848 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3850 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3852 if draw(booleans()):
3853 default = seq_klass()
3855 k: v for k, v in draw(dictionaries(
3858 booleans().map(Boolean),
3859 integers().map(Integer),
3863 optional = draw(one_of(none(), booleans()))
3865 draw(integers(min_value=0)),
3866 draw(integers(min_value=0)),
3867 draw(integers(min_value=0)),
3869 return (value, schema, impl, expl, default, optional, _decoded)
3873 def sequence_strategy(draw, seq_klass):
3874 inputs = draw(lists(
3876 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
3877 tuples(just(Integer), integers(), one_of(none(), integers())),
3882 integers(min_value=1),
3883 min_size=len(inputs),
3884 max_size=len(inputs),
3887 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3888 for tag, expled in zip(tags, draw(lists(
3890 min_size=len(inputs),
3891 max_size=len(inputs),
3895 for i, optional in enumerate(draw(lists(
3896 sampled_from(("required", "optional", "empty")),
3897 min_size=len(inputs),
3898 max_size=len(inputs),
3900 if optional in ("optional", "empty"):
3901 inits[i]["optional"] = True
3902 if optional == "empty":
3904 empties = set(empties)
3905 names = list(draw(sets(
3907 min_size=len(inputs),
3908 max_size=len(inputs),
3911 for i, (klass, value, default) in enumerate(inputs):
3912 schema.append((names[i], klass(default=default, **inits[i])))
3913 seq_name = draw(text_letters())
3914 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3917 for i, (klass, value, default) in enumerate(inputs):
3924 "default_value": None if spec.default is None else default,
3928 expect["optional"] = True
3930 expect["presented"] = True
3931 expect["value"] = value
3933 expect["optional"] = True
3934 if default is not None and default == value:
3935 expect["presented"] = False
3936 seq[name] = klass(value)
3937 expects.append(expect)
3942 def sequences_strategy(draw, seq_klass):
3943 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
3945 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3946 for tag, expled in zip(tags, draw(lists(
3953 i for i, is_default in enumerate(draw(lists(
3959 names = list(draw(sets(
3964 seq_expectses = draw(lists(
3965 sequence_strategy(seq_klass=seq_klass),
3969 seqs = [seq for seq, _ in seq_expectses]
3971 for i, (name, seq) in enumerate(zip(names, seqs)):
3974 seq(default=(seq if i in defaulted else None), **inits[i]),
3976 seq_name = draw(text_letters())
3977 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3980 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
3983 "expects": expects_inner,
3986 seq_outer[name] = seq_inner
3987 if seq_outer.specs[name].default is None:
3988 expect["presented"] = True
3989 expect_outers.append(expect)
3990 return seq_outer, expect_outers
3993 class SeqMixing(object):
3994 def test_invalid_value_type(self):
3995 with self.assertRaises(InvalidValueType) as err:
3996 self.base_klass(123)
3999 def test_invalid_value_type_set(self):
4000 class Seq(self.base_klass):
4001 schema = (("whatever", Boolean()),)
4003 with self.assertRaises(InvalidValueType) as err:
4004 seq["whatever"] = Integer(123)
4008 def test_optional(self, optional):
4009 obj = self.base_klass(default=self.base_klass(), optional=optional)
4010 self.assertTrue(obj.optional)
4012 @given(data_strategy())
4013 def test_ready(self, d):
4015 str(i): v for i, v in enumerate(d.draw(lists(
4022 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4029 for name in d.draw(permutations(
4030 list(ready.keys()) + list(non_ready.keys()),
4032 schema_input.append((name, Boolean()))
4034 class Seq(self.base_klass):
4035 schema = tuple(schema_input)
4037 for name in ready.keys():
4039 seq[name] = Boolean()
4040 self.assertFalse(seq.ready)
4043 for name, value in ready.items():
4044 seq[name] = Boolean(value)
4045 self.assertFalse(seq.ready)
4048 with self.assertRaises(ObjNotReady) as err:
4051 for name, value in non_ready.items():
4052 seq[name] = Boolean(value)
4053 self.assertTrue(seq.ready)
4057 @given(data_strategy())
4058 def test_call(self, d):
4059 class SeqInherited(self.base_klass):
4061 for klass in (self.base_klass, SeqInherited):
4070 ) = d.draw(seq_values_strategy(seq_klass=klass))
4071 obj_initial = klass(
4077 optional_initial or False,
4088 ) = d.draw(seq_values_strategy(
4090 do_expl=impl_initial is None,
4092 obj = obj_initial(value, impl, expl, default, optional)
4093 value_expected = default if value is None else value
4095 default_initial if value_expected is None
4098 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4099 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4100 self.assertEqual(obj.expl_tag, expl or expl_initial)
4102 {} if obj.default is None else obj.default._value,
4103 getattr(default_initial if default is None else default, "_value", {}),
4105 if obj.default is None:
4106 optional = optional_initial if optional is None else optional
4107 optional = False if optional is None else optional
4110 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4111 self.assertEqual(obj.optional, optional)
4113 @given(data_strategy())
4114 def test_copy(self, d):
4115 class SeqInherited(self.base_klass):
4117 for klass in (self.base_klass, SeqInherited):
4118 values = d.draw(seq_values_strategy(seq_klass=klass))
4119 obj = klass(*values)
4120 obj_copied = obj.copy()
4121 self.assert_copied_basic_fields(obj, obj_copied)
4122 self.assertEqual(obj.specs, obj_copied.specs)
4123 self.assertEqual(obj._value, obj_copied._value)
4125 @given(data_strategy())
4126 def test_stripped(self, d):
4127 value = d.draw(integers())
4128 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4130 class Seq(self.base_klass):
4132 schema = (("whatever", Integer()),)
4134 seq["whatever"] = Integer(value)
4135 with self.assertRaises(NotEnoughData):
4136 seq.decode(seq.encode()[:-1])
4138 @given(data_strategy())
4139 def test_stripped_expl(self, d):
4140 value = d.draw(integers())
4141 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4143 class Seq(self.base_klass):
4145 schema = (("whatever", Integer()),)
4147 seq["whatever"] = Integer(value)
4148 with self.assertRaises(NotEnoughData):
4149 seq.decode(seq.encode()[:-1])
4151 @given(binary(min_size=2))
4152 def test_non_tag_mismatch_raised(self, junk):
4154 _, _, len_encoded = tag_strip(memoryview(junk))
4155 len_decode(len_encoded)
4161 class Seq(self.base_klass):
4163 ("whatever", Integer()),
4165 ("whenever", Integer()),
4168 seq["whatever"] = Integer(123)
4169 seq["junk"] = Any(junk)
4170 seq["whenever"] = Integer(123)
4171 with self.assertRaises(DecodeError):
4172 seq.decode(seq.encode())
4175 integers(min_value=31),
4176 integers(min_value=0),
4179 def test_bad_tag(self, tag, offset, decode_path):
4180 decode_path = tuple(str(i) for i in decode_path)
4181 with self.assertRaises(DecodeError) as err:
4182 self.base_klass().decode(
4183 tag_encode(tag)[:-1],
4185 decode_path=decode_path,
4188 self.assertEqual(err.exception.offset, offset)
4189 self.assertEqual(err.exception.decode_path, decode_path)
4192 integers(min_value=128),
4193 integers(min_value=0),
4196 def test_bad_len(self, l, offset, decode_path):
4197 decode_path = tuple(str(i) for i in decode_path)
4198 with self.assertRaises(DecodeError) as err:
4199 self.base_klass().decode(
4200 self.base_klass.tag_default + len_encode(l)[:-1],
4202 decode_path=decode_path,
4205 self.assertEqual(err.exception.offset, offset)
4206 self.assertEqual(err.exception.decode_path, decode_path)
4208 def _assert_expects(self, seq, expects):
4209 for expect in expects:
4211 seq.specs[expect["name"]].optional,
4214 if expect["default_value"] is not None:
4216 seq.specs[expect["name"]].default,
4217 expect["default_value"],
4219 if expect["presented"]:
4220 self.assertIn(expect["name"], seq)
4221 self.assertEqual(seq[expect["name"]], expect["value"])
4223 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4224 @given(data_strategy())
4225 def test_symmetric(self, d):
4226 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4227 tail_junk = d.draw(binary(max_size=5))
4228 self.assertTrue(seq.ready)
4229 self.assertFalse(seq.decoded)
4230 self._assert_expects(seq, expects)
4233 seq_encoded = seq.encode()
4234 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4235 self.assertEqual(tail, tail_junk)
4236 self.assertTrue(seq.ready)
4237 self._assert_expects(seq_decoded, expects)
4238 self.assertEqual(seq, seq_decoded)
4239 self.assertEqual(seq_decoded.encode(), seq_encoded)
4240 for expect in expects:
4241 if not expect["presented"]:
4242 self.assertNotIn(expect["name"], seq_decoded)
4244 self.assertIn(expect["name"], seq_decoded)
4245 obj = seq_decoded[expect["name"]]
4246 self.assertTrue(obj.decoded)
4247 offset = obj.expl_offset if obj.expled else obj.offset
4248 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4249 self.assertSequenceEqual(
4250 seq_encoded[offset:offset + tlvlen],
4254 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4255 @given(data_strategy())
4256 def test_symmetric_with_seq(self, d):
4257 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4258 self.assertTrue(seq.ready)
4259 seq_encoded = seq.encode()
4260 seq_decoded, tail = seq.decode(seq_encoded)
4261 self.assertEqual(tail, b"")
4262 self.assertTrue(seq.ready)
4263 self.assertEqual(seq, seq_decoded)
4264 self.assertEqual(seq_decoded.encode(), seq_encoded)
4265 for expect_outer in expect_outers:
4266 if not expect_outer["presented"]:
4267 self.assertNotIn(expect_outer["name"], seq_decoded)
4269 self.assertIn(expect_outer["name"], seq_decoded)
4270 obj = seq_decoded[expect_outer["name"]]
4271 self.assertTrue(obj.decoded)
4272 offset = obj.expl_offset if obj.expled else obj.offset
4273 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4274 self.assertSequenceEqual(
4275 seq_encoded[offset:offset + tlvlen],
4278 self._assert_expects(obj, expect_outer["expects"])
4280 @given(data_strategy())
4281 def test_default_disappears(self, d):
4282 _schema = list(d.draw(dictionaries(
4284 sets(integers(), min_size=2, max_size=2),
4288 class Seq(self.base_klass):
4290 (n, Integer(default=d))
4291 for n, (_, d) in _schema
4294 for name, (value, _) in _schema:
4295 seq[name] = Integer(value)
4296 self.assertEqual(len(seq._value), len(_schema))
4297 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4298 self.assertGreater(len(seq.encode()), len(empty_seq))
4299 for name, (_, default) in _schema:
4300 seq[name] = Integer(default)
4301 self.assertEqual(len(seq._value), 0)
4302 self.assertSequenceEqual(seq.encode(), empty_seq)
4304 @given(data_strategy())
4305 def test_encoded_default_accepted(self, d):
4306 _schema = list(d.draw(dictionaries(
4311 tags = [tag_encode(tag) for tag in d.draw(sets(
4312 integers(min_value=0),
4313 min_size=len(_schema),
4314 max_size=len(_schema),
4317 class SeqWithoutDefault(self.base_klass):
4319 (n, Integer(impl=t))
4320 for (n, _), t in zip(_schema, tags)
4322 seq_without_default = SeqWithoutDefault()
4323 for name, value in _schema:
4324 seq_without_default[name] = Integer(value)
4325 seq_encoded = seq_without_default.encode()
4327 class SeqWithDefault(self.base_klass):
4329 (n, Integer(default=v, impl=t))
4330 for (n, v), t in zip(_schema, tags)
4332 seq_with_default = SeqWithDefault()
4333 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4334 for name, value in _schema:
4335 self.assertEqual(seq_decoded[name], seq_with_default[name])
4336 self.assertEqual(seq_decoded[name], value)
4338 @given(data_strategy())
4339 def test_missing_from_spec(self, d):
4340 names = list(d.draw(sets(text_letters(), min_size=2)))
4341 tags = [tag_encode(tag) for tag in d.draw(sets(
4342 integers(min_value=0),
4343 min_size=len(names),
4344 max_size=len(names),
4346 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4348 class SeqFull(self.base_klass):
4349 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4350 seq_full = SeqFull()
4351 for i, name in enumerate(names):
4352 seq_full[name] = Integer(i)
4353 seq_encoded = seq_full.encode()
4354 altered = names_tags[:-2] + names_tags[-1:]
4356 class SeqMissing(self.base_klass):
4357 schema = [(n, Integer(impl=t)) for n, t in altered]
4358 seq_missing = SeqMissing()
4359 with self.assertRaises(TagMismatch):
4360 seq_missing.decode(seq_encoded)
4363 class TestSequence(SeqMixing, CommonMixin, TestCase):
4364 base_klass = Sequence
4370 def test_remaining(self, value, junk):
4371 class Seq(Sequence):
4373 ("whatever", Integer()),
4375 int_encoded = Integer(value).encode()
4377 Sequence.tag_default,
4378 len_encode(len(int_encoded + junk)),
4381 with assertRaisesRegex(self, DecodeError, "remaining"):
4382 Seq().decode(junked)
4384 @given(sets(text_letters(), min_size=2))
4385 def test_obj_unknown(self, names):
4386 missing = names.pop()
4388 class Seq(Sequence):
4389 schema = [(n, Boolean()) for n in names]
4391 with self.assertRaises(ObjUnknown) as err:
4394 with self.assertRaises(ObjUnknown) as err:
4395 seq[missing] = Boolean()
4398 def test_x690_vector(self):
4399 class Seq(Sequence):
4401 ("name", IA5String()),
4404 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4405 self.assertEqual(seq["name"], "Smith")
4406 self.assertEqual(seq["ok"], True)
4409 class TestSet(SeqMixing, CommonMixin, TestCase):
4412 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4413 @given(data_strategy())
4414 def test_sorted(self, d):
4416 tag_encode(tag) for tag in
4417 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4421 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4423 for name, _ in Seq.schema:
4424 seq[name] = OctetString(b"")
4425 seq_encoded = seq.encode()
4426 seq_decoded, _ = seq.decode(seq_encoded)
4427 self.assertSequenceEqual(
4428 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4429 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4434 def seqof_values_strategy(draw, schema=None, do_expl=False):
4436 schema = draw(sampled_from((Boolean(), Integer())))
4437 bound_min, bound_max = sorted(draw(sets(
4438 integers(min_value=0, max_value=10),
4442 if isinstance(schema, Boolean):
4443 values_generator = booleans().map(Boolean)
4444 elif isinstance(schema, Integer):
4445 values_generator = integers().map(Integer)
4446 values_generator = lists(
4451 values = draw(one_of(none(), values_generator))
4455 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4457 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4458 default = draw(one_of(none(), values_generator))
4459 optional = draw(one_of(none(), booleans()))
4461 draw(integers(min_value=0)),
4462 draw(integers(min_value=0)),
4463 draw(integers(min_value=0)),
4468 (bound_min, bound_max),
4477 class SeqOfMixing(object):
4478 def test_invalid_value_type(self):
4479 with self.assertRaises(InvalidValueType) as err:
4480 self.base_klass(123)
4483 def test_invalid_values_type(self):
4484 class SeqOf(self.base_klass):
4486 with self.assertRaises(InvalidValueType) as err:
4487 SeqOf([Integer(123), Boolean(False), Integer(234)])
4490 def test_schema_required(self):
4491 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4492 self.base_klass.__mro__[1]()
4494 @given(booleans(), booleans(), binary(), binary())
4495 def test_comparison(self, value1, value2, tag1, tag2):
4496 class SeqOf(self.base_klass):
4498 obj1 = SeqOf([Boolean(value1)])
4499 obj2 = SeqOf([Boolean(value2)])
4500 self.assertEqual(obj1 == obj2, value1 == value2)
4501 self.assertEqual(obj1 != obj2, value1 != value2)
4502 self.assertEqual(obj1 == list(obj2), value1 == value2)
4503 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4504 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4505 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4506 self.assertEqual(obj1 == obj2, tag1 == tag2)
4507 self.assertEqual(obj1 != obj2, tag1 != tag2)
4509 @given(lists(booleans()))
4510 def test_iter(self, values):
4511 class SeqOf(self.base_klass):
4513 obj = SeqOf([Boolean(value) for value in values])
4514 self.assertEqual(len(obj), len(values))
4515 for i, value in enumerate(obj):
4516 self.assertEqual(value, values[i])
4518 @given(data_strategy())
4519 def test_ready(self, d):
4520 ready = [Integer(v) for v in d.draw(lists(
4527 range(d.draw(integers(min_value=1, max_value=5)))
4530 class SeqOf(self.base_klass):
4532 values = d.draw(permutations(ready + non_ready))
4534 for value in values:
4536 self.assertFalse(seqof.ready)
4539 with self.assertRaises(ObjNotReady) as err:
4542 for i, value in enumerate(values):
4543 self.assertEqual(seqof[i], value)
4544 if not seqof[i].ready:
4545 seqof[i] = Integer(i)
4546 self.assertTrue(seqof.ready)
4550 def test_spec_mismatch(self):
4551 class SeqOf(self.base_klass):
4554 seqof.append(Integer(123))
4555 with self.assertRaises(ValueError):
4556 seqof.append(Boolean(False))
4557 with self.assertRaises(ValueError):
4558 seqof[0] = Boolean(False)
4560 @given(data_strategy())
4561 def test_bounds_satisfied(self, d):
4562 class SeqOf(self.base_klass):
4564 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4565 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4566 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4567 SeqOf(value=value, bounds=(bound_min, bound_max))
4569 @given(data_strategy())
4570 def test_bounds_unsatisfied(self, d):
4571 class SeqOf(self.base_klass):
4573 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4574 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4575 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4576 with self.assertRaises(BoundsError) as err:
4577 SeqOf(value=value, bounds=(bound_min, bound_max))
4579 value = [Boolean()] * d.draw(integers(
4580 min_value=bound_max + 1,
4581 max_value=bound_max + 10,
4583 with self.assertRaises(BoundsError) as err:
4584 SeqOf(value=value, bounds=(bound_min, bound_max))
4587 @given(integers(min_value=1, max_value=10))
4588 def test_out_of_bounds(self, bound_max):
4589 class SeqOf(self.base_klass):
4591 bounds = (0, bound_max)
4593 for _ in range(bound_max):
4594 seqof.append(Integer(123))
4595 with self.assertRaises(BoundsError):
4596 seqof.append(Integer(123))
4598 @given(data_strategy())
4599 def test_call(self, d):
4609 ) = d.draw(seqof_values_strategy())
4611 class SeqOf(self.base_klass):
4612 schema = schema_initial
4613 obj_initial = SeqOf(
4614 value=value_initial,
4615 bounds=bounds_initial,
4618 default=default_initial,
4619 optional=optional_initial or False,
4620 _decoded=_decoded_initial,
4631 ) = d.draw(seqof_values_strategy(
4632 schema=schema_initial,
4633 do_expl=impl_initial is None,
4635 if (default is None) and (obj_initial.default is not None):
4638 (bounds is None) and
4639 (value is not None) and
4640 (bounds_initial is not None) and
4641 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4645 (bounds is None) and
4646 (default is not None) and
4647 (bounds_initial is not None) and
4648 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4660 value_expected = default if value is None else value
4662 default_initial if value_expected is None
4665 value_expected = () if value_expected is None else value_expected
4666 self.assertEqual(obj, value_expected)
4667 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4668 self.assertEqual(obj.expl_tag, expl or expl_initial)
4671 default_initial if default is None else default,
4673 if obj.default is None:
4674 optional = optional_initial if optional is None else optional
4675 optional = False if optional is None else optional
4678 self.assertEqual(obj.optional, optional)
4680 (obj._bound_min, obj._bound_max),
4681 bounds or bounds_initial or (0, float("+inf")),
4684 @given(seqof_values_strategy())
4685 def test_copy(self, values):
4686 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4688 class SeqOf(self.base_klass):
4696 optional=optional or False,
4699 obj_copied = obj.copy()
4700 self.assert_copied_basic_fields(obj, obj_copied)
4701 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4702 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4703 self.assertEqual(obj._value, obj_copied._value)
4707 integers(min_value=1).map(tag_encode),
4709 def test_stripped(self, values, tag_impl):
4710 class SeqOf(self.base_klass):
4711 schema = OctetString()
4712 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4713 with self.assertRaises(NotEnoughData):
4714 obj.decode(obj.encode()[:-1])
4718 integers(min_value=1).map(tag_ctxc),
4720 def test_stripped_expl(self, values, tag_expl):
4721 class SeqOf(self.base_klass):
4722 schema = OctetString()
4723 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4724 with self.assertRaises(NotEnoughData):
4725 obj.decode(obj.encode()[:-1])
4728 integers(min_value=31),
4729 integers(min_value=0),
4732 def test_bad_tag(self, tag, offset, decode_path):
4733 decode_path = tuple(str(i) for i in decode_path)
4734 with self.assertRaises(DecodeError) as err:
4735 self.base_klass().decode(
4736 tag_encode(tag)[:-1],
4738 decode_path=decode_path,
4741 self.assertEqual(err.exception.offset, offset)
4742 self.assertEqual(err.exception.decode_path, decode_path)
4745 integers(min_value=128),
4746 integers(min_value=0),
4749 def test_bad_len(self, l, offset, decode_path):
4750 decode_path = tuple(str(i) for i in decode_path)
4751 with self.assertRaises(DecodeError) as err:
4752 self.base_klass().decode(
4753 self.base_klass.tag_default + len_encode(l)[:-1],
4755 decode_path=decode_path,
4758 self.assertEqual(err.exception.offset, offset)
4759 self.assertEqual(err.exception.decode_path, decode_path)
4761 @given(binary(min_size=1))
4762 def test_tag_mismatch(self, impl):
4763 assume(impl != self.base_klass.tag_default)
4764 with self.assertRaises(TagMismatch):
4765 self.base_klass(impl=impl).decode(self.base_klass().encode())
4767 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4769 seqof_values_strategy(schema=Integer()),
4770 lists(integers().map(Integer)),
4771 integers(min_value=1).map(tag_ctxc),
4772 integers(min_value=0),
4775 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4776 _, _, _, _, _, default, optional, _decoded = values
4778 class SeqOf(self.base_klass):
4788 self.assertFalse(obj.expled)
4789 obj_encoded = obj.encode()
4790 obj_expled = obj(value, expl=tag_expl)
4791 self.assertTrue(obj_expled.expled)
4794 obj_expled_encoded = obj_expled.encode()
4795 obj_decoded, tail = obj_expled.decode(
4796 obj_expled_encoded + tail_junk,
4801 self.assertEqual(tail, tail_junk)
4802 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
4803 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4804 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4805 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4807 obj_decoded.expl_llen,
4808 len(len_encode(len(obj_encoded))),
4810 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4811 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4814 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4816 self.assertEqual(obj_decoded.expl_offset, offset)
4817 for obj_inner in obj_decoded:
4818 self.assertIn(obj_inner, obj_decoded)
4819 self.assertSequenceEqual(
4822 obj_inner.offset - offset:
4823 obj_inner.offset + obj_inner.tlvlen - offset
4828 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
4829 class SeqOf(SequenceOf):
4833 def _test_symmetric_compare_objs(self, obj1, obj2):
4834 self.assertEqual(obj1, obj2)
4835 self.assertSequenceEqual(list(obj1), list(obj2))
4838 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
4843 def _test_symmetric_compare_objs(self, obj1, obj2):
4844 self.assertSetEqual(
4845 set(int(v) for v in obj1),
4846 set(int(v) for v in obj2),
4849 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4850 @given(data_strategy())
4851 def test_sorted(self, d):
4852 values = [OctetString(v) for v in d.draw(lists(binary()))]
4855 schema = OctetString()
4857 seq_encoded = seq.encode()
4858 seq_decoded, _ = seq.decode(seq_encoded)
4859 self.assertSequenceEqual(
4860 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4861 b"".join(sorted([v.encode() for v in values])),
4865 class TestGoMarshalVectors(TestCase):
4867 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
4868 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
4869 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
4870 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
4871 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
4873 class Seq(Sequence):
4875 ("erste", Integer()),
4876 ("zweite", Integer(optional=True))
4879 seq["erste"] = Integer(64)
4880 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4881 seq["erste"] = Integer(0x123456)
4882 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
4883 seq["erste"] = Integer(64)
4884 seq["zweite"] = Integer(65)
4885 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
4887 class NestedSeq(Sequence):
4891 seq["erste"] = Integer(127)
4892 seq["zweite"] = None
4893 nested = NestedSeq()
4894 nested["nest"] = seq
4895 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
4897 self.assertSequenceEqual(
4898 OctetString(b"\x01\x02\x03").encode(),
4899 hexdec("0403010203"),
4902 class Seq(Sequence):
4904 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
4907 seq["erste"] = Integer(64)
4908 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
4910 class Seq(Sequence):
4912 ("erste", Integer(expl=tag_ctxc(5))),
4915 seq["erste"] = Integer(64)
4916 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
4918 class Seq(Sequence):
4921 impl=tag_encode(0, klass=TagClassContext),
4926 seq["erste"] = Null()
4927 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
4929 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4931 self.assertSequenceEqual(
4932 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
4933 hexdec("170d3730303130313030303030305a"),
4935 self.assertSequenceEqual(
4936 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
4937 hexdec("170d3039313131353232353631365a"),
4939 self.assertSequenceEqual(
4940 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
4941 hexdec("180f32313030303430353132303130315a"),
4944 class Seq(Sequence):
4946 ("erste", GeneralizedTime()),
4949 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
4950 self.assertSequenceEqual(
4952 hexdec("3011180f32303039313131353232353631365a"),
4955 self.assertSequenceEqual(
4956 BitString((1, b"\x80")).encode(),
4959 self.assertSequenceEqual(
4960 BitString((12, b"\x81\xF0")).encode(),
4961 hexdec("03030481f0"),
4964 self.assertSequenceEqual(
4965 ObjectIdentifier("1.2.3.4").encode(),
4966 hexdec("06032a0304"),
4968 self.assertSequenceEqual(
4969 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
4970 hexdec("06092a864888932d010105"),
4972 self.assertSequenceEqual(
4973 ObjectIdentifier("2.100.3").encode(),
4974 hexdec("0603813403"),
4977 self.assertSequenceEqual(
4978 PrintableString("test").encode(),
4979 hexdec("130474657374"),
4981 self.assertSequenceEqual(
4982 PrintableString("x" * 127).encode(),
4983 hexdec("137F" + "78" * 127),
4985 self.assertSequenceEqual(
4986 PrintableString("x" * 128).encode(),
4987 hexdec("138180" + "78" * 128),
4989 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
4991 class Seq(Sequence):
4993 ("erste", IA5String()),
4996 seq["erste"] = IA5String("test")
4997 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
4999 class Seq(Sequence):
5001 ("erste", PrintableString()),
5004 seq["erste"] = PrintableString("test")
5005 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5006 seq["erste"] = PrintableString("test*")
5007 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5009 class Seq(Sequence):
5011 ("erste", Any(optional=True)),
5012 ("zweite", Integer()),
5015 seq["zweite"] = Integer(64)
5016 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5021 seq.append(Integer(10))
5022 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5024 class _SeqOf(SequenceOf):
5025 schema = PrintableString()
5027 class SeqOf(SequenceOf):
5030 _seqof.append(PrintableString("1"))
5032 seqof.append(_seqof)
5033 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5035 class Seq(Sequence):
5037 ("erste", Integer(default=1)),
5040 seq["erste"] = Integer(0)
5041 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5042 seq["erste"] = Integer(1)
5043 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5044 seq["erste"] = Integer(2)
5045 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5048 class TestPP(TestCase):
5049 @given(data_strategy())
5050 def test_oid_printing(self, d):
5052 str(ObjectIdentifier(k)): v * 2
5053 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5055 chosen = d.draw(sampled_from(sorted(oids)))
5056 chosen_id = oids[chosen]
5057 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5058 self.assertNotIn(chosen_id, pp_console_row(pp))
5059 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5062 class TestAutoAddSlots(TestCase):
5064 class Inher(Integer):
5067 with self.assertRaises(AttributeError):
5069 inher.unexistent = "whatever"
5072 class TestOIDDefines(TestCase):
5073 @given(data_strategy())
5074 def runTest(self, d):
5075 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5076 value_name_chosen = d.draw(sampled_from(value_names))
5078 ObjectIdentifier(oid)
5079 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5081 oid_chosen = d.draw(sampled_from(oids))
5082 values = d.draw(lists(
5084 min_size=len(value_names),
5085 max_size=len(value_names),
5088 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5089 oid: Integer() for oid in oids[:-1]
5092 for i, value_name in enumerate(value_names):
5093 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5095 class Seq(Sequence):
5098 for value_name, value in zip(value_names, values):
5099 seq[value_name] = Any(Integer(value).encode())
5100 seq["type"] = oid_chosen
5101 seq, _ = Seq().decode(seq.encode())
5102 for value_name in value_names:
5103 if value_name == value_name_chosen:
5105 self.assertIsNone(seq[value_name].defined)
5106 if value_name_chosen in oids[:-1]:
5107 self.assertIsNotNone(seq[value_name_chosen].defined)
5108 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5109 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5112 class TestDefinesByPath(TestCase):
5113 def test_generated(self):
5114 class Seq(Sequence):
5116 ("type", ObjectIdentifier()),
5117 ("value", OctetString(expl=tag_ctxc(123))),
5120 class SeqInner(Sequence):
5122 ("typeInner", ObjectIdentifier()),
5123 ("valueInner", Any()),
5126 class PairValue(SetOf):
5129 class Pair(Sequence):
5131 ("type", ObjectIdentifier()),
5132 ("value", PairValue()),
5135 class Pairs(SequenceOf):
5142 type_octet_stringed,
5144 ObjectIdentifier(oid)
5145 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5147 seq_integered = Seq()
5148 seq_integered["type"] = type_integered
5149 seq_integered["value"] = OctetString(Integer(123).encode())
5150 seq_integered_raw = seq_integered.encode()
5154 (type_octet_stringed, OctetString(b"whatever")),
5155 (type_integered, Integer(123)),
5156 (type_octet_stringed, OctetString(b"whenever")),
5157 (type_integered, Integer(234)),
5159 for t, v in pairs_input:
5162 pair["value"] = PairValue((Any(v),))
5164 seq_inner = SeqInner()
5165 seq_inner["typeInner"] = type_innered
5166 seq_inner["valueInner"] = Any(pairs)
5167 seq_sequenced = Seq()
5168 seq_sequenced["type"] = type_sequenced
5169 seq_sequenced["value"] = OctetString(seq_inner.encode())
5170 seq_sequenced_raw = seq_sequenced.encode()
5172 defines_by_path = []
5173 seq_integered, _ = Seq().decode(seq_integered_raw)
5174 self.assertIsNone(seq_integered["value"].defined)
5175 defines_by_path.append(
5176 (("type",), ((("value",), {
5177 type_integered: Integer(),
5178 type_sequenced: SeqInner(),
5181 seq_integered, _ = Seq().decode(
5183 ctx={"defines_by_path": defines_by_path},
5185 self.assertIsNotNone(seq_integered["value"].defined)
5186 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5187 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5188 self.assertTrue(seq_integered_raw[
5189 seq_integered["value"].defined[1].offset:
5190 ].startswith(Integer(123).encode()))
5192 seq_sequenced, _ = Seq().decode(
5194 ctx={"defines_by_path": defines_by_path},
5196 self.assertIsNotNone(seq_sequenced["value"].defined)
5197 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5198 seq_inner = seq_sequenced["value"].defined[1]
5199 self.assertIsNone(seq_inner["valueInner"].defined)
5201 defines_by_path.append((
5202 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5203 ((("valueInner",), {type_innered: Pairs()}),),
5205 seq_sequenced, _ = Seq().decode(
5207 ctx={"defines_by_path": defines_by_path},
5209 self.assertIsNotNone(seq_sequenced["value"].defined)
5210 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5211 seq_inner = seq_sequenced["value"].defined[1]
5212 self.assertIsNotNone(seq_inner["valueInner"].defined)
5213 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5214 pairs = seq_inner["valueInner"].defined[1]
5216 self.assertIsNone(pair["value"][0].defined)
5218 defines_by_path.append((
5221 DecodePathDefBy(type_sequenced),
5223 DecodePathDefBy(type_innered),
5228 type_integered: Integer(),
5229 type_octet_stringed: OctetString(),
5232 seq_sequenced, _ = Seq().decode(
5234 ctx={"defines_by_path": defines_by_path},
5236 self.assertIsNotNone(seq_sequenced["value"].defined)
5237 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5238 seq_inner = seq_sequenced["value"].defined[1]
5239 self.assertIsNotNone(seq_inner["valueInner"].defined)
5240 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5241 pairs_got = seq_inner["valueInner"].defined[1]
5242 for pair_input, pair_got in zip(pairs_input, pairs_got):
5243 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5244 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5246 @given(oid_strategy(), integers())
5247 def test_simple(self, oid, tgt):
5248 class Inner(Sequence):
5250 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5251 ObjectIdentifier(oid): Integer(),
5255 class Outer(Sequence):
5258 ("tgt", OctetString()),
5262 inner["oid"] = ObjectIdentifier(oid)
5264 outer["inner"] = inner
5265 outer["tgt"] = OctetString(Integer(tgt).encode())
5266 decoded, _ = Outer().decode(outer.encode())
5267 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5270 class TestAbsDecodePath(TestCase):
5272 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5273 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5275 def test_concat(self, decode_path, rel_path):
5276 self.assertSequenceEqual(
5277 abs_decode_path(decode_path, rel_path),
5278 decode_path + rel_path,
5282 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5283 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5285 def test_abs(self, decode_path, rel_path):
5286 self.assertSequenceEqual(
5287 abs_decode_path(decode_path, ("/",) + rel_path),
5292 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5293 integers(min_value=1, max_value=3),
5294 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5296 def test_dots(self, decode_path, number_of_dots, rel_path):
5297 self.assertSequenceEqual(
5298 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5299 decode_path[:-number_of_dots] + rel_path,
5303 class TestStrictDefaultExistence(TestCase):
5304 @given(data_strategy())
5305 def runTest(self, d):
5306 count = d.draw(integers(min_value=1, max_value=10))
5307 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5309 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5310 for i in range(count)
5313 class Seq(Sequence):
5316 for i in range(count):
5317 seq["int%d" % i] = Integer(123)
5319 chosen = "int%d" % chosen
5320 seq.specs[chosen] = seq.specs[chosen](default=123)
5322 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5323 seq.decode(raw, ctx={"strict_default_existence": True})
5326 class TestX690PrefixedType(TestCase):
5328 self.assertSequenceEqual(
5329 VisibleString("Jones").encode(),
5330 hexdec("1A054A6F6E6573"),
5332 self.assertSequenceEqual(
5335 impl=tag_encode(3, klass=TagClassApplication),
5337 hexdec("43054A6F6E6573"),
5339 self.assertSequenceEqual(
5343 impl=tag_encode(3, klass=TagClassApplication),
5347 hexdec("A20743054A6F6E6573"),
5349 self.assertSequenceEqual(
5353 impl=tag_encode(3, klass=TagClassApplication),
5355 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5357 hexdec("670743054A6F6E6573"),
5359 self.assertSequenceEqual(
5360 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5361 hexdec("82054A6F6E6573"),