2 # PyDERASN -- Python ASN.1 DER codec with abstract structures
3 # Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from datetime import datetime
20 from string import ascii_letters
21 from string import digits
22 from string import printable
23 from string import whitespace
24 from unittest import TestCase
26 from hypothesis import assume
27 from hypothesis import given
28 from hypothesis import settings
29 from hypothesis.strategies import binary
30 from hypothesis.strategies import booleans
31 from hypothesis.strategies import composite
32 from hypothesis.strategies import data as data_strategy
33 from hypothesis.strategies import datetimes
34 from hypothesis.strategies import dictionaries
35 from hypothesis.strategies import integers
36 from hypothesis.strategies import just
37 from hypothesis.strategies import lists
38 from hypothesis.strategies import none
39 from hypothesis.strategies import one_of
40 from hypothesis.strategies import permutations
41 from hypothesis.strategies import sampled_from
42 from hypothesis.strategies import sets
43 from hypothesis.strategies import text
44 from hypothesis.strategies import tuples
45 from six import assertRaisesRegex
46 from six import binary_type
47 from six import byte2int
48 from six import indexbytes
49 from six import int2byte
50 from six import iterbytes
52 from six import text_type
53 from six import unichr as six_unichr
55 from pyderasn import _pp
56 from pyderasn import abs_decode_path
57 from pyderasn import Any
58 from pyderasn import BitString
59 from pyderasn import BMPString
60 from pyderasn import Boolean
61 from pyderasn import BoundsError
62 from pyderasn import Choice
63 from pyderasn import DecodeError
64 from pyderasn import DecodePathDefBy
65 from pyderasn import Enumerated
66 from pyderasn import EOC
67 from pyderasn import GeneralizedTime
68 from pyderasn import GeneralString
69 from pyderasn import GraphicString
70 from pyderasn import hexdec
71 from pyderasn import hexenc
72 from pyderasn import IA5String
73 from pyderasn import Integer
74 from pyderasn import InvalidLength
75 from pyderasn import InvalidOID
76 from pyderasn import InvalidValueType
77 from pyderasn import len_decode
78 from pyderasn import len_encode
79 from pyderasn import NotEnoughData
80 from pyderasn import Null
81 from pyderasn import NumericString
82 from pyderasn import ObjectIdentifier
83 from pyderasn import ObjNotReady
84 from pyderasn import ObjUnknown
85 from pyderasn import OctetString
86 from pyderasn import pp_console_row
87 from pyderasn import pprint
88 from pyderasn import PrintableString
89 from pyderasn import Sequence
90 from pyderasn import SequenceOf
91 from pyderasn import Set
92 from pyderasn import SetOf
93 from pyderasn import tag_ctxc
94 from pyderasn import tag_ctxp
95 from pyderasn import tag_decode
96 from pyderasn import tag_encode
97 from pyderasn import tag_strip
98 from pyderasn import TagClassApplication
99 from pyderasn import TagClassContext
100 from pyderasn import TagClassPrivate
101 from pyderasn import TagClassUniversal
102 from pyderasn import TagFormConstructed
103 from pyderasn import TagFormPrimitive
104 from pyderasn import TagMismatch
105 from pyderasn import TeletexString
106 from pyderasn import UniversalString
107 from pyderasn import UTCTime
108 from pyderasn import UTF8String
109 from pyderasn import VideotexString
110 from pyderasn import VisibleString
113 settings.register_profile("local", settings(
115 perform_health_check=False,
117 settings.load_profile("local")
118 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
120 tag_classes = sampled_from((
126 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
129 class TestHex(TestCase):
131 def test_symmetric(self, data):
132 self.assertEqual(hexdec(hexenc(data)), data)
135 class TestTagCoder(TestCase):
136 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
140 integers(min_value=0, max_value=30),
143 def test_short(self, klass, form, num, junk):
144 raw = tag_encode(klass=klass, form=form, num=num)
145 self.assertEqual(tag_decode(raw), (klass, form, num))
146 self.assertEqual(len(raw), 1)
148 byte2int(tag_encode(klass=klass, form=form, num=0)),
149 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
151 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
152 self.assertSequenceEqual(stripped.tobytes(), raw)
153 self.assertEqual(tlen, len(raw))
154 self.assertSequenceEqual(tail, junk)
156 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
160 integers(min_value=31),
163 def test_long(self, klass, form, num, junk):
164 raw = tag_encode(klass=klass, form=form, num=num)
165 self.assertEqual(tag_decode(raw), (klass, form, num))
166 self.assertGreater(len(raw), 1)
168 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
171 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
172 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
173 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
174 self.assertSequenceEqual(stripped.tobytes(), raw)
175 self.assertEqual(tlen, len(raw))
176 self.assertSequenceEqual(tail, junk)
178 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
179 @given(integers(min_value=31))
180 def test_unfinished_tag(self, num):
181 raw = bytearray(tag_encode(num=num))
182 for i in range(1, len(raw)):
184 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
185 tag_strip(bytes(raw))
187 def test_go_vectors_valid(self):
188 for data, (eklass, etag, elen, eform) in (
189 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
190 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
191 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
192 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
193 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
194 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
195 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
196 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
197 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
198 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
200 tag, _, len_encoded = tag_strip(memoryview(data))
201 klass, form, num = tag_decode(tag)
202 _len, _, tail = len_decode(len_encoded)
203 self.assertSequenceEqual(tail, b"")
204 self.assertEqual(klass, eklass)
205 self.assertEqual(num, etag)
206 self.assertEqual(_len, elen)
207 self.assertEqual(form, eform)
209 def test_go_vectors_invalid(self):
217 with self.assertRaises(DecodeError):
218 _, _, len_encoded = tag_strip(memoryview(data))
219 len_decode(len_encoded)
222 integers(min_value=0, max_value=127),
223 integers(min_value=0, max_value=2),
225 def test_long_instead_of_short(self, l, dummy_num):
226 octets = (b"\x00" * dummy_num) + int2byte(l)
227 octets = int2byte((dummy_num + 1) | 0x80) + octets
228 with self.assertRaises(DecodeError):
232 class TestLenCoder(TestCase):
233 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
235 integers(min_value=0, max_value=127),
238 def test_short(self, l, junk):
239 raw = len_encode(l) + junk
240 decoded, llen, tail = len_decode(memoryview(raw))
241 self.assertEqual(decoded, l)
242 self.assertEqual(llen, 1)
243 self.assertEqual(len(raw), 1 + len(junk))
244 self.assertEqual(tail.tobytes(), junk)
246 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
248 integers(min_value=128),
251 def test_long(self, l, junk):
252 raw = len_encode(l) + junk
253 decoded, llen, tail = len_decode(memoryview(raw))
254 self.assertEqual(decoded, l)
255 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
256 self.assertEqual(llen, len(raw) - len(junk))
257 self.assertNotEqual(indexbytes(raw, 1), 0)
258 self.assertSequenceEqual(tail.tobytes(), junk)
260 def test_empty(self):
261 with self.assertRaises(NotEnoughData):
264 @given(integers(min_value=128))
265 def test_stripped(self, _len):
266 with self.assertRaises(NotEnoughData):
267 len_decode(len_encode(_len)[:-1])
270 text_printable = text(alphabet=printable, min_size=1)
274 def text_letters(draw):
275 result = draw(text(alphabet=ascii_letters, min_size=1))
277 result = result.encode("ascii")
281 class CommonMixin(object):
282 def test_tag_default(self):
283 obj = self.base_klass()
284 self.assertEqual(obj.tag, obj.tag_default)
286 def test_simultaneous_impl_expl(self):
287 with self.assertRaises(ValueError):
288 self.base_klass(impl=b"whatever", expl=b"whenever")
290 @given(binary(min_size=1), integers(), integers(), integers())
291 def test_decoded(self, impl, offset, llen, vlen):
292 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
293 self.assertEqual(obj.offset, offset)
294 self.assertEqual(obj.llen, llen)
295 self.assertEqual(obj.vlen, vlen)
296 self.assertEqual(obj.tlen, len(impl))
297 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
299 @given(binary(min_size=1))
300 def test_impl_inherited(self, impl_tag):
301 class Inherited(self.base_klass):
304 self.assertSequenceEqual(obj.impl, impl_tag)
305 self.assertFalse(obj.expled)
308 def test_expl_inherited(self, expl_tag):
309 class Inherited(self.base_klass):
312 self.assertSequenceEqual(obj.expl, expl_tag)
313 self.assertTrue(obj.expled)
315 def assert_copied_basic_fields(self, obj, obj_copied):
316 self.assertEqual(obj, obj_copied)
317 self.assertSequenceEqual(obj.tag, obj_copied.tag)
318 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
319 self.assertEqual(obj.default, obj_copied.default)
320 self.assertEqual(obj.optional, obj_copied.optional)
321 self.assertEqual(obj.offset, obj_copied.offset)
322 self.assertEqual(obj.llen, obj_copied.llen)
323 self.assertEqual(obj.vlen, obj_copied.vlen)
327 def boolean_values_strategy(draw, do_expl=False):
328 value = draw(one_of(none(), booleans()))
332 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
334 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
335 default = draw(one_of(none(), booleans()))
336 optional = draw(one_of(none(), booleans()))
338 draw(integers(min_value=0)),
339 draw(integers(min_value=0)),
340 draw(integers(min_value=0)),
342 return (value, impl, expl, default, optional, _decoded)
345 class BooleanInherited(Boolean):
349 class TestBoolean(CommonMixin, TestCase):
352 def test_invalid_value_type(self):
353 with self.assertRaises(InvalidValueType) as err:
358 def test_optional(self, optional):
359 obj = Boolean(default=Boolean(False), optional=optional)
360 self.assertTrue(obj.optional)
363 def test_ready(self, value):
365 self.assertFalse(obj.ready)
368 with self.assertRaises(ObjNotReady) as err:
372 self.assertTrue(obj.ready)
376 @given(booleans(), booleans(), binary(), binary())
377 def test_comparison(self, value1, value2, tag1, tag2):
378 for klass in (Boolean, BooleanInherited):
381 self.assertEqual(obj1 == obj2, value1 == value2)
382 self.assertEqual(obj1 != obj2, value1 != value2)
383 self.assertEqual(obj1 == bool(obj2), value1 == value2)
384 obj1 = klass(value1, impl=tag1)
385 obj2 = klass(value1, impl=tag2)
386 self.assertEqual(obj1 == obj2, tag1 == tag2)
387 self.assertEqual(obj1 != obj2, tag1 != tag2)
389 @given(data_strategy())
390 def test_call(self, d):
391 for klass in (Boolean, BooleanInherited):
399 ) = d.draw(boolean_values_strategy())
405 optional_initial or False,
415 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
416 obj = obj_initial(value, impl, expl, default, optional)
418 value_expected = default if value is None else value
420 default_initial if value_expected is None
423 self.assertEqual(obj, value_expected)
424 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
425 self.assertEqual(obj.expl_tag, expl or expl_initial)
428 default_initial if default is None else default,
430 if obj.default is None:
431 optional = optional_initial if optional is None else optional
432 optional = False if optional is None else optional
435 self.assertEqual(obj.optional, optional)
437 @given(boolean_values_strategy())
438 def test_copy(self, values):
439 for klass in (Boolean, BooleanInherited):
441 obj_copied = obj.copy()
442 self.assert_copied_basic_fields(obj, obj_copied)
446 integers(min_value=1).map(tag_encode),
448 def test_stripped(self, value, tag_impl):
449 obj = Boolean(value, impl=tag_impl)
450 with self.assertRaises(NotEnoughData):
451 obj.decode(obj.encode()[:-1])
455 integers(min_value=1).map(tag_ctxc),
457 def test_stripped_expl(self, value, tag_expl):
458 obj = Boolean(value, expl=tag_expl)
459 with self.assertRaises(NotEnoughData):
460 obj.decode(obj.encode()[:-1])
463 integers(min_value=31),
464 integers(min_value=0),
467 def test_bad_tag(self, tag, offset, decode_path):
468 decode_path = tuple(str(i) for i in decode_path)
469 with self.assertRaises(DecodeError) as err:
471 tag_encode(tag)[:-1],
473 decode_path=decode_path,
476 self.assertEqual(err.exception.offset, offset)
477 self.assertEqual(err.exception.decode_path, decode_path)
480 integers(min_value=31),
481 integers(min_value=0),
484 def test_bad_expl_tag(self, tag, offset, decode_path):
485 decode_path = tuple(str(i) for i in decode_path)
486 with self.assertRaises(DecodeError) as err:
487 Boolean(expl=Boolean.tag_default).decode(
488 tag_encode(tag)[:-1],
490 decode_path=decode_path,
493 self.assertEqual(err.exception.offset, offset)
494 self.assertEqual(err.exception.decode_path, decode_path)
497 integers(min_value=128),
498 integers(min_value=0),
501 def test_bad_len(self, l, offset, decode_path):
502 decode_path = tuple(str(i) for i in decode_path)
503 with self.assertRaises(DecodeError) as err:
505 Boolean.tag_default + len_encode(l)[:-1],
507 decode_path=decode_path,
510 self.assertEqual(err.exception.offset, offset)
511 self.assertEqual(err.exception.decode_path, decode_path)
514 integers(min_value=128),
515 integers(min_value=0),
518 def test_bad_expl_len(self, l, offset, decode_path):
519 decode_path = tuple(str(i) for i in decode_path)
520 with self.assertRaises(DecodeError) as err:
521 Boolean(expl=Boolean.tag_default).decode(
522 Boolean.tag_default + len_encode(l)[:-1],
524 decode_path=decode_path,
527 self.assertEqual(err.exception.offset, offset)
528 self.assertEqual(err.exception.decode_path, decode_path)
530 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
532 boolean_values_strategy(),
534 integers(min_value=1).map(tag_ctxc),
535 integers(min_value=0),
538 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
539 for klass in (Boolean, BooleanInherited):
540 _, _, _, default, optional, _decoded = values
549 self.assertFalse(obj.expled)
550 obj_encoded = obj.encode()
551 obj_expled = obj(value, expl=tag_expl)
552 self.assertTrue(obj_expled.expled)
555 obj_expled_encoded = obj_expled.encode()
556 obj_decoded, tail = obj_expled.decode(
557 obj_expled_encoded + tail_junk,
562 self.assertEqual(tail, tail_junk)
563 self.assertEqual(obj_decoded, obj_expled)
564 self.assertNotEqual(obj_decoded, obj)
565 self.assertEqual(bool(obj_decoded), bool(obj_expled))
566 self.assertEqual(bool(obj_decoded), bool(obj))
567 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
568 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
569 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
571 obj_decoded.expl_llen,
572 len(len_encode(len(obj_encoded))),
574 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
575 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
578 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
580 self.assertEqual(obj_decoded.expl_offset, offset)
582 @given(integers(min_value=2))
583 def test_invalid_len(self, l):
584 with self.assertRaises(InvalidLength):
585 Boolean().decode(b"".join((
591 @given(integers(min_value=0 + 1, max_value=255 - 1))
592 def test_ber_value(self, value):
593 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
594 Boolean().decode(b"".join((
599 obj, _ = Boolean().decode(
607 self.assertTrue(bool(obj))
608 self.assertTrue(obj.bered)
612 def integer_values_strategy(draw, do_expl=False):
613 bound_min, value, default, bound_max = sorted(draw(sets(
622 _specs = draw(sets(text_letters()))
625 min_size=len(_specs),
626 max_size=len(_specs),
628 _specs = list(zip(_specs, values))
631 bounds = (bound_min, bound_max)
635 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
637 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
640 optional = draw(one_of(none(), booleans()))
642 draw(integers(min_value=0)),
643 draw(integers(min_value=0)),
644 draw(integers(min_value=0)),
646 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
649 class IntegerInherited(Integer):
653 class TestInteger(CommonMixin, TestCase):
656 def test_invalid_value_type(self):
657 with self.assertRaises(InvalidValueType) as err:
661 @given(sets(text_letters(), min_size=2))
662 def test_unknown_name(self, names_input):
663 missing = names_input.pop()
666 schema = [(n, 123) for n in names_input]
667 with self.assertRaises(ObjUnknown) as err:
671 @given(sets(text_letters(), min_size=2))
672 def test_known_name(self, names_input):
674 schema = [(n, 123) for n in names_input]
675 Int(names_input.pop())
678 def test_optional(self, optional):
679 obj = Integer(default=Integer(0), optional=optional)
680 self.assertTrue(obj.optional)
683 def test_ready(self, value):
685 self.assertFalse(obj.ready)
688 with self.assertRaises(ObjNotReady) as err:
692 self.assertTrue(obj.ready)
697 @given(integers(), integers(), binary(), binary())
698 def test_comparison(self, value1, value2, tag1, tag2):
699 for klass in (Integer, IntegerInherited):
702 self.assertEqual(obj1 == obj2, value1 == value2)
703 self.assertEqual(obj1 != obj2, value1 != value2)
704 self.assertEqual(obj1 == int(obj2), value1 == value2)
705 obj1 = klass(value1, impl=tag1)
706 obj2 = klass(value1, impl=tag2)
707 self.assertEqual(obj1 == obj2, tag1 == tag2)
708 self.assertEqual(obj1 != obj2, tag1 != tag2)
710 @given(lists(integers()))
711 def test_sorted_works(self, values):
712 self.assertSequenceEqual(
713 [int(v) for v in sorted(Integer(v) for v in values)],
717 @given(data_strategy())
718 def test_named(self, d):
719 names_input = list(d.draw(sets(text_letters(), min_size=1)))
720 values_input = list(d.draw(sets(
722 min_size=len(names_input),
723 max_size=len(names_input),
725 chosen_name = d.draw(sampled_from(names_input))
726 names_input = dict(zip(names_input, values_input))
730 _int = Int(chosen_name)
731 self.assertEqual(_int.named, chosen_name)
732 self.assertEqual(int(_int), names_input[chosen_name])
734 @given(integers(), integers(min_value=0), integers(min_value=0))
735 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
736 value = bound_min + value_delta
737 bound_max = value + bound_delta
738 Integer(value=value, bounds=(bound_min, bound_max))
740 @given(sets(integers(), min_size=3, max_size=3))
741 def test_bounds_unsatisfied(self, values):
742 values = sorted(values)
743 with self.assertRaises(BoundsError) as err:
744 Integer(value=values[0], bounds=(values[1], values[2]))
746 with self.assertRaises(BoundsError) as err:
747 Integer(value=values[2], bounds=(values[0], values[1]))
750 @given(data_strategy())
751 def test_call(self, d):
752 for klass in (Integer, IntegerInherited):
762 ) = d.draw(integer_values_strategy())
769 optional_initial or False,
782 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
783 if (default is None) and (obj_initial.default is not None):
787 (value is not None) and
788 (bounds_initial is not None) and
789 not (bounds_initial[0] <= value <= bounds_initial[1])
794 (default is not None) and
795 (bounds_initial is not None) and
796 not (bounds_initial[0] <= default <= bounds_initial[1])
799 obj = obj_initial(value, bounds, impl, expl, default, optional)
801 value_expected = default if value is None else value
803 default_initial if value_expected is None
806 self.assertEqual(obj, value_expected)
807 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
808 self.assertEqual(obj.expl_tag, expl or expl_initial)
811 default_initial if default is None else default,
813 if obj.default is None:
814 optional = optional_initial if optional is None else optional
815 optional = False if optional is None else optional
818 self.assertEqual(obj.optional, optional)
820 (obj._bound_min, obj._bound_max),
821 bounds or bounds_initial or (float("-inf"), float("+inf")),
825 {} if _specs_initial is None else dict(_specs_initial),
828 @given(integer_values_strategy())
829 def test_copy(self, values):
830 for klass in (Integer, IntegerInherited):
832 obj_copied = obj.copy()
833 self.assert_copied_basic_fields(obj, obj_copied)
834 self.assertEqual(obj.specs, obj_copied.specs)
835 self.assertEqual(obj._bound_min, obj_copied._bound_min)
836 self.assertEqual(obj._bound_max, obj_copied._bound_max)
837 self.assertEqual(obj._value, obj_copied._value)
841 integers(min_value=1).map(tag_encode),
843 def test_stripped(self, value, tag_impl):
844 obj = Integer(value, impl=tag_impl)
845 with self.assertRaises(NotEnoughData):
846 obj.decode(obj.encode()[:-1])
850 integers(min_value=1).map(tag_ctxc),
852 def test_stripped_expl(self, value, tag_expl):
853 obj = Integer(value, expl=tag_expl)
854 with self.assertRaises(NotEnoughData):
855 obj.decode(obj.encode()[:-1])
857 def test_zero_len(self):
858 with self.assertRaises(NotEnoughData):
859 Integer().decode(b"".join((
865 integers(min_value=31),
866 integers(min_value=0),
869 def test_bad_tag(self, tag, offset, decode_path):
870 decode_path = tuple(str(i) for i in decode_path)
871 with self.assertRaises(DecodeError) as err:
873 tag_encode(tag)[:-1],
875 decode_path=decode_path,
878 self.assertEqual(err.exception.offset, offset)
879 self.assertEqual(err.exception.decode_path, decode_path)
882 integers(min_value=128),
883 integers(min_value=0),
886 def test_bad_len(self, l, offset, decode_path):
887 decode_path = tuple(str(i) for i in decode_path)
888 with self.assertRaises(DecodeError) as err:
890 Integer.tag_default + len_encode(l)[:-1],
892 decode_path=decode_path,
895 self.assertEqual(err.exception.offset, offset)
896 self.assertEqual(err.exception.decode_path, decode_path)
899 sets(integers(), min_size=2, max_size=2),
900 integers(min_value=0),
903 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
904 decode_path = tuple(str(i) for i in decode_path)
905 value, bound_min = list(sorted(ints))
908 bounds = (bound_min, bound_min)
909 with self.assertRaises(DecodeError) as err:
911 Integer(value).encode(),
913 decode_path=decode_path,
916 self.assertEqual(err.exception.offset, offset)
917 self.assertEqual(err.exception.decode_path, decode_path)
919 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
921 integer_values_strategy(),
923 integers(min_value=1).map(tag_ctxc),
924 integers(min_value=0),
927 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
928 for klass in (Integer, IntegerInherited):
929 _, _, _, _, default, optional, _, _decoded = values
938 self.assertFalse(obj.expled)
939 obj_encoded = obj.encode()
940 obj_expled = obj(value, expl=tag_expl)
941 self.assertTrue(obj_expled.expled)
944 obj_expled_encoded = obj_expled.encode()
945 obj_decoded, tail = obj_expled.decode(
946 obj_expled_encoded + tail_junk,
951 self.assertEqual(tail, tail_junk)
952 self.assertEqual(obj_decoded, obj_expled)
953 self.assertNotEqual(obj_decoded, obj)
954 self.assertEqual(int(obj_decoded), int(obj_expled))
955 self.assertEqual(int(obj_decoded), int(obj))
956 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
957 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
958 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
960 obj_decoded.expl_llen,
961 len(len_encode(len(obj_encoded))),
963 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
964 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
967 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
969 self.assertEqual(obj_decoded.expl_offset, offset)
971 def test_go_vectors_valid(self):
972 for data, expect in ((
984 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
985 (b"\x80\x00\x00\x00", -2147483648),
988 Integer().decode(b"".join((
990 len_encode(len(data)),
996 def test_go_vectors_invalid(self):
1001 with self.assertRaises(DecodeError):
1002 Integer().decode(b"".join((
1003 Integer.tag_default,
1004 len_encode(len(data)),
1010 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1013 if draw(booleans()):
1014 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1016 integers(min_value=0, max_value=255),
1017 min_size=len(schema),
1018 max_size=len(schema),
1020 schema = list(zip(schema, bits))
1022 def _value(value_required):
1023 if not value_required and draw(booleans()):
1025 generation_choice = 0
1027 generation_choice = draw(sampled_from((1, 2, 3)))
1028 if generation_choice == 1 or draw(booleans()):
1029 return "'%s'B" % "".join(draw(lists(
1030 sampled_from(("0", "1")),
1031 max_size=len(schema),
1033 elif generation_choice == 2 or draw(booleans()):
1034 return draw(binary(max_size=len(schema) // 8))
1035 elif generation_choice == 3 or draw(booleans()):
1036 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1038 value = _value(value_required)
1039 default = _value(value_required=False)
1043 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1045 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1046 optional = draw(one_of(none(), booleans()))
1048 draw(integers(min_value=0)),
1049 draw(integers(min_value=0)),
1050 draw(integers(min_value=0)),
1052 return (schema, value, impl, expl, default, optional, _decoded)
1055 class BitStringInherited(BitString):
1059 class TestBitString(CommonMixin, TestCase):
1060 base_klass = BitString
1062 @given(lists(booleans()))
1063 def test_b_encoding(self, bits):
1064 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1065 self.assertEqual(obj.bit_len, len(bits))
1066 self.assertSequenceEqual(list(obj), bits)
1067 for i, bit in enumerate(bits):
1068 self.assertEqual(obj[i], bit)
1070 @given(lists(booleans()))
1071 def test_out_of_bounds_bits(self, bits):
1072 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1073 for i in range(len(bits), len(bits) * 2):
1074 self.assertFalse(obj[i])
1076 def test_bad_b_encoding(self):
1077 with self.assertRaises(ValueError):
1078 BitString("'010120101'B")
1081 integers(min_value=1, max_value=255),
1082 integers(min_value=1, max_value=255),
1084 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1085 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1086 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1087 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1089 class BS(BitString):
1090 schema = (("whatever", 0),)
1091 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1092 self.assertEqual(obj.bit_len, leading_zeros + 1)
1093 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1095 def test_zero_len(self):
1096 with self.assertRaises(NotEnoughData):
1097 BitString().decode(b"".join((
1098 BitString.tag_default,
1102 def test_invalid_value_type(self):
1103 with self.assertRaises(InvalidValueType) as err:
1106 with self.assertRaises(InvalidValueType) as err:
1110 def test_obj_unknown(self):
1111 with self.assertRaises(ObjUnknown) as err:
1112 BitString(b"whatever")["whenever"]
1115 def test_get_invalid_type(self):
1116 with self.assertRaises(InvalidValueType) as err:
1117 BitString(b"whatever")[(1, 2, 3)]
1120 @given(data_strategy())
1121 def test_unknown_name(self, d):
1122 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1123 missing = _schema.pop()
1125 class BS(BitString):
1126 schema = [(n, i) for i, n in enumerate(_schema)]
1127 with self.assertRaises(ObjUnknown) as err:
1132 def test_optional(self, optional):
1133 obj = BitString(default=BitString(b""), optional=optional)
1134 self.assertTrue(obj.optional)
1137 def test_ready(self, value):
1139 self.assertFalse(obj.ready)
1142 with self.assertRaises(ObjNotReady) as err:
1145 obj = BitString(value)
1146 self.assertTrue(obj.ready)
1151 tuples(integers(min_value=0), binary()),
1152 tuples(integers(min_value=0), binary()),
1156 def test_comparison(self, value1, value2, tag1, tag2):
1157 for klass in (BitString, BitStringInherited):
1158 obj1 = klass(value1)
1159 obj2 = klass(value2)
1160 self.assertEqual(obj1 == obj2, value1 == value2)
1161 self.assertEqual(obj1 != obj2, value1 != value2)
1162 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1163 obj1 = klass(value1, impl=tag1)
1164 obj2 = klass(value1, impl=tag2)
1165 self.assertEqual(obj1 == obj2, tag1 == tag2)
1166 self.assertEqual(obj1 != obj2, tag1 != tag2)
1168 @given(data_strategy())
1169 def test_call(self, d):
1170 for klass in (BitString, BitStringInherited):
1179 ) = d.draw(bit_string_values_strategy())
1182 schema = schema_initial
1184 value=value_initial,
1187 default=default_initial,
1188 optional=optional_initial or False,
1189 _decoded=_decoded_initial,
1199 ) = d.draw(bit_string_values_strategy(
1200 schema=schema_initial,
1201 do_expl=impl_initial is None,
1210 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1211 self.assertEqual(obj.expl_tag, expl or expl_initial)
1212 if obj.default is None:
1213 optional = optional_initial if optional is None else optional
1214 optional = False if optional is None else optional
1217 self.assertEqual(obj.optional, optional)
1218 self.assertEqual(obj.specs, obj_initial.specs)
1220 @given(bit_string_values_strategy())
1221 def test_copy(self, values):
1222 for klass in (BitString, BitStringInherited):
1223 _schema, value, impl, expl, default, optional, _decoded = values
1232 optional=optional or False,
1235 obj_copied = obj.copy()
1236 self.assert_copied_basic_fields(obj, obj_copied)
1237 self.assertEqual(obj.specs, obj_copied.specs)
1238 self.assertEqual(obj._value, obj_copied._value)
1242 integers(min_value=1).map(tag_encode),
1244 def test_stripped(self, value, tag_impl):
1245 obj = BitString(value, impl=tag_impl)
1246 with self.assertRaises(NotEnoughData):
1247 obj.decode(obj.encode()[:-1])
1251 integers(min_value=1).map(tag_ctxc),
1253 def test_stripped_expl(self, value, tag_expl):
1254 obj = BitString(value, expl=tag_expl)
1255 with self.assertRaises(NotEnoughData):
1256 obj.decode(obj.encode()[:-1])
1259 integers(min_value=31),
1260 integers(min_value=0),
1263 def test_bad_tag(self, tag, offset, decode_path):
1264 decode_path = tuple(str(i) for i in decode_path)
1265 with self.assertRaises(DecodeError) as err:
1267 tag_encode(tag)[:-1],
1269 decode_path=decode_path,
1272 self.assertEqual(err.exception.offset, offset)
1273 self.assertEqual(err.exception.decode_path, decode_path)
1276 integers(min_value=128),
1277 integers(min_value=0),
1280 def test_bad_len(self, l, offset, decode_path):
1281 decode_path = tuple(str(i) for i in decode_path)
1282 with self.assertRaises(DecodeError) as err:
1284 BitString.tag_default + len_encode(l)[:-1],
1286 decode_path=decode_path,
1289 self.assertEqual(err.exception.offset, offset)
1290 self.assertEqual(err.exception.decode_path, decode_path)
1292 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1293 @given(data_strategy())
1294 def test_symmetric(self, d):
1303 ) = d.draw(bit_string_values_strategy(value_required=True))
1304 tail_junk = d.draw(binary(max_size=5))
1305 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1306 offset = d.draw(integers(min_value=0))
1307 for klass in (BitString, BitStringInherited):
1318 self.assertFalse(obj.expled)
1319 obj_encoded = obj.encode()
1320 obj_expled = obj(value, expl=tag_expl)
1321 self.assertTrue(obj_expled.expled)
1324 obj_expled_encoded = obj_expled.encode()
1325 obj_decoded, tail = obj_expled.decode(
1326 obj_expled_encoded + tail_junk,
1331 self.assertEqual(tail, tail_junk)
1332 self.assertEqual(obj_decoded, obj_expled)
1333 self.assertNotEqual(obj_decoded, obj)
1334 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1335 self.assertEqual(bytes(obj_decoded), bytes(obj))
1336 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1337 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1338 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1340 obj_decoded.expl_llen,
1341 len(len_encode(len(obj_encoded))),
1343 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1344 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1347 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1349 self.assertEqual(obj_decoded.expl_offset, offset)
1350 if isinstance(value, tuple):
1351 self.assertSetEqual(set(value), set(obj_decoded.named))
1355 @given(integers(min_value=1, max_value=255))
1356 def test_bad_zero_value(self, pad_size):
1357 with self.assertRaises(DecodeError):
1358 BitString().decode(b"".join((
1359 BitString.tag_default,
1364 def test_go_vectors_invalid(self):
1370 with self.assertRaises(DecodeError):
1371 BitString().decode(b"".join((
1372 BitString.tag_default,
1377 def test_go_vectors_valid(self):
1378 obj, _ = BitString().decode(b"".join((
1379 BitString.tag_default,
1383 self.assertEqual(bytes(obj), b"")
1384 self.assertEqual(obj.bit_len, 0)
1386 obj, _ = BitString().decode(b"".join((
1387 BitString.tag_default,
1391 self.assertEqual(bytes(obj), b"\x00")
1392 self.assertEqual(obj.bit_len, 1)
1394 obj = BitString((16, b"\x82\x40"))
1395 self.assertTrue(obj[0])
1396 self.assertFalse(obj[1])
1397 self.assertTrue(obj[6])
1398 self.assertTrue(obj[9])
1399 self.assertFalse(obj[17])
1402 integers(min_value=1, max_value=30),
1405 binary(min_size=1, max_size=5),
1407 binary(min_size=1, max_size=5),
1415 lists(booleans(), min_size=1),
1417 def test_constructed(self, impl, chunk_inputs, chunk_last_bits):
1418 def chunk_constructed(contents):
1420 tag_encode(form=TagFormConstructed, num=3) +
1422 b"".join(BitString(content).encode() for content in contents) +
1426 payload_expected = b""
1427 bit_len_expected = 0
1428 for chunk_input in chunk_inputs:
1429 if isinstance(chunk_input, binary_type):
1430 chunks.append(BitString(chunk_input).encode())
1431 payload_expected += chunk_input
1432 bit_len_expected += len(chunk_input) * 8
1434 chunks.append(chunk_constructed(chunk_input))
1435 payload = b"".join(chunk_input)
1436 payload_expected += payload
1437 bit_len_expected += len(payload) * 8
1438 chunk_last = BitString("'%s'B" % "".join(
1439 "1" if bit else "0" for bit in chunk_last_bits
1441 payload_expected += bytes(chunk_last)
1442 bit_len_expected += chunk_last.bit_len
1443 encoded_indefinite = (
1444 tag_encode(form=TagFormConstructed, num=impl) +
1447 chunk_last.encode() +
1450 encoded_definite = (
1451 tag_encode(form=TagFormConstructed, num=impl) +
1452 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1456 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1457 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1458 for encoded in (encoded_indefinite, encoded_definite):
1459 obj, tail = BitString(impl=tag_encode(impl)).decode(
1460 encoded, ctx={"bered": True}
1462 self.assertSequenceEqual(tail, b"")
1463 self.assertEqual(obj.bit_len, bit_len_expected)
1464 self.assertSequenceEqual(bytes(obj), payload_expected)
1465 self.assertTrue(obj.bered)
1466 self.assertEqual(len(encoded), obj.tlvlen)
1468 def test_x690_vector(self):
1469 vector_payload = hexdec("0A3B5F291CD0")
1470 vector = BitString((len(vector_payload) * 8 - 4, vector_payload))
1471 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1472 self.assertSequenceEqual(tail, b"")
1473 self.assertEqual(obj, vector)
1474 obj, tail = BitString().decode(
1475 hexdec("23800303000A3B0305045F291CD00000"),
1476 ctx={"bered": True},
1478 self.assertSequenceEqual(tail, b"")
1479 self.assertEqual(obj, vector)
1483 def octet_string_values_strategy(draw, do_expl=False):
1484 bound_min, bound_max = sorted(draw(sets(
1485 integers(min_value=0, max_value=1 << 7),
1489 value = draw(one_of(
1491 binary(min_size=bound_min, max_size=bound_max),
1493 default = draw(one_of(
1495 binary(min_size=bound_min, max_size=bound_max),
1498 if draw(booleans()):
1499 bounds = (bound_min, bound_max)
1503 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1505 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1506 optional = draw(one_of(none(), booleans()))
1508 draw(integers(min_value=0)),
1509 draw(integers(min_value=0)),
1510 draw(integers(min_value=0)),
1512 return (value, bounds, impl, expl, default, optional, _decoded)
1515 class OctetStringInherited(OctetString):
1519 class TestOctetString(CommonMixin, TestCase):
1520 base_klass = OctetString
1522 def test_invalid_value_type(self):
1523 with self.assertRaises(InvalidValueType) as err:
1524 OctetString(text_type(123))
1528 def test_optional(self, optional):
1529 obj = OctetString(default=OctetString(b""), optional=optional)
1530 self.assertTrue(obj.optional)
1533 def test_ready(self, value):
1535 self.assertFalse(obj.ready)
1538 with self.assertRaises(ObjNotReady) as err:
1541 obj = OctetString(value)
1542 self.assertTrue(obj.ready)
1546 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1547 def test_comparison(self, value1, value2, tag1, tag2):
1548 for klass in (OctetString, OctetStringInherited):
1549 obj1 = klass(value1)
1550 obj2 = klass(value2)
1551 self.assertEqual(obj1 == obj2, value1 == value2)
1552 self.assertEqual(obj1 != obj2, value1 != value2)
1553 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1554 obj1 = klass(value1, impl=tag1)
1555 obj2 = klass(value1, impl=tag2)
1556 self.assertEqual(obj1 == obj2, tag1 == tag2)
1557 self.assertEqual(obj1 != obj2, tag1 != tag2)
1559 @given(lists(binary()))
1560 def test_sorted_works(self, values):
1561 self.assertSequenceEqual(
1562 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1566 @given(data_strategy())
1567 def test_bounds_satisfied(self, d):
1568 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1569 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1570 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1571 OctetString(value=value, bounds=(bound_min, bound_max))
1573 @given(data_strategy())
1574 def test_bounds_unsatisfied(self, d):
1575 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1576 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1577 value = d.draw(binary(max_size=bound_min - 1))
1578 with self.assertRaises(BoundsError) as err:
1579 OctetString(value=value, bounds=(bound_min, bound_max))
1581 value = d.draw(binary(min_size=bound_max + 1))
1582 with self.assertRaises(BoundsError) as err:
1583 OctetString(value=value, bounds=(bound_min, bound_max))
1586 @given(data_strategy())
1587 def test_call(self, d):
1588 for klass in (OctetString, OctetStringInherited):
1597 ) = d.draw(octet_string_values_strategy())
1598 obj_initial = klass(
1604 optional_initial or False,
1615 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1616 if (default is None) and (obj_initial.default is not None):
1619 (bounds is None) and
1620 (value is not None) and
1621 (bounds_initial is not None) and
1622 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1626 (bounds is None) and
1627 (default is not None) and
1628 (bounds_initial is not None) and
1629 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1632 obj = obj_initial(value, bounds, impl, expl, default, optional)
1634 value_expected = default if value is None else value
1636 default_initial if value_expected is None
1639 self.assertEqual(obj, value_expected)
1640 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1641 self.assertEqual(obj.expl_tag, expl or expl_initial)
1644 default_initial if default is None else default,
1646 if obj.default is None:
1647 optional = optional_initial if optional is None else optional
1648 optional = False if optional is None else optional
1651 self.assertEqual(obj.optional, optional)
1653 (obj._bound_min, obj._bound_max),
1654 bounds or bounds_initial or (0, float("+inf")),
1657 @given(octet_string_values_strategy())
1658 def test_copy(self, values):
1659 for klass in (OctetString, OctetStringInherited):
1660 obj = klass(*values)
1661 obj_copied = obj.copy()
1662 self.assert_copied_basic_fields(obj, obj_copied)
1663 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1664 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1665 self.assertEqual(obj._value, obj_copied._value)
1669 integers(min_value=1).map(tag_encode),
1671 def test_stripped(self, value, tag_impl):
1672 obj = OctetString(value, impl=tag_impl)
1673 with self.assertRaises(NotEnoughData):
1674 obj.decode(obj.encode()[:-1])
1678 integers(min_value=1).map(tag_ctxc),
1680 def test_stripped_expl(self, value, tag_expl):
1681 obj = OctetString(value, expl=tag_expl)
1682 with self.assertRaises(NotEnoughData):
1683 obj.decode(obj.encode()[:-1])
1686 integers(min_value=31),
1687 integers(min_value=0),
1690 def test_bad_tag(self, tag, offset, decode_path):
1691 decode_path = tuple(str(i) for i in decode_path)
1692 with self.assertRaises(DecodeError) as err:
1693 OctetString().decode(
1694 tag_encode(tag)[:-1],
1696 decode_path=decode_path,
1699 self.assertEqual(err.exception.offset, offset)
1700 self.assertEqual(err.exception.decode_path, decode_path)
1703 integers(min_value=128),
1704 integers(min_value=0),
1707 def test_bad_len(self, l, offset, decode_path):
1708 decode_path = tuple(str(i) for i in decode_path)
1709 with self.assertRaises(DecodeError) as err:
1710 OctetString().decode(
1711 OctetString.tag_default + len_encode(l)[:-1],
1713 decode_path=decode_path,
1716 self.assertEqual(err.exception.offset, offset)
1717 self.assertEqual(err.exception.decode_path, decode_path)
1720 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1721 integers(min_value=0),
1724 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1725 decode_path = tuple(str(i) for i in decode_path)
1726 value, bound_min = list(sorted(ints))
1728 class String(OctetString):
1729 bounds = (bound_min, bound_min)
1730 with self.assertRaises(DecodeError) as err:
1732 OctetString(b"\x00" * value).encode(),
1734 decode_path=decode_path,
1737 self.assertEqual(err.exception.offset, offset)
1738 self.assertEqual(err.exception.decode_path, decode_path)
1740 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1742 octet_string_values_strategy(),
1744 integers(min_value=1).map(tag_ctxc),
1745 integers(min_value=0),
1748 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1749 for klass in (OctetString, OctetStringInherited):
1750 _, _, _, _, default, optional, _decoded = values
1759 self.assertFalse(obj.expled)
1760 obj_encoded = obj.encode()
1761 obj_expled = obj(value, expl=tag_expl)
1762 self.assertTrue(obj_expled.expled)
1765 obj_expled_encoded = obj_expled.encode()
1766 obj_decoded, tail = obj_expled.decode(
1767 obj_expled_encoded + tail_junk,
1772 self.assertEqual(tail, tail_junk)
1773 self.assertEqual(obj_decoded, obj_expled)
1774 self.assertNotEqual(obj_decoded, obj)
1775 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1776 self.assertEqual(bytes(obj_decoded), bytes(obj))
1777 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1778 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1779 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1781 obj_decoded.expl_llen,
1782 len(len_encode(len(obj_encoded))),
1784 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1785 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1788 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1790 self.assertEqual(obj_decoded.expl_offset, offset)
1793 integers(min_value=1, max_value=30),
1796 binary(min_size=1, max_size=5),
1798 binary(min_size=1, max_size=5),
1807 def test_constructed(self, impl, chunk_inputs):
1808 def chunk_constructed(contents):
1810 tag_encode(form=TagFormConstructed, num=4) +
1812 b"".join(OctetString(content).encode() for content in contents) +
1816 payload_expected = b""
1817 for chunk_input in chunk_inputs:
1818 if isinstance(chunk_input, binary_type):
1819 chunks.append(OctetString(chunk_input).encode())
1820 payload_expected += chunk_input
1822 chunks.append(chunk_constructed(chunk_input))
1823 payload = b"".join(chunk_input)
1824 payload_expected += payload
1825 encoded_indefinite = (
1826 tag_encode(form=TagFormConstructed, num=impl) +
1831 encoded_definite = (
1832 tag_encode(form=TagFormConstructed, num=impl) +
1833 len_encode(len(b"".join(chunks))) +
1836 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1837 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
1838 for encoded in (encoded_indefinite, encoded_definite):
1839 obj, tail = OctetString(impl=tag_encode(impl)).decode(
1840 encoded, ctx={"bered": True}
1842 self.assertSequenceEqual(tail, b"")
1843 self.assertSequenceEqual(bytes(obj), payload_expected)
1844 self.assertTrue(obj.bered)
1845 self.assertEqual(len(encoded), obj.tlvlen)
1849 def null_values_strategy(draw, do_expl=False):
1853 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1855 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1856 optional = draw(one_of(none(), booleans()))
1858 draw(integers(min_value=0)),
1859 draw(integers(min_value=0)),
1860 draw(integers(min_value=0)),
1862 return (impl, expl, optional, _decoded)
1865 class NullInherited(Null):
1869 class TestNull(CommonMixin, TestCase):
1872 def test_ready(self):
1874 self.assertTrue(obj.ready)
1878 @given(binary(), binary())
1879 def test_comparison(self, tag1, tag2):
1880 for klass in (Null, NullInherited):
1881 obj1 = klass(impl=tag1)
1882 obj2 = klass(impl=tag2)
1883 self.assertEqual(obj1 == obj2, tag1 == tag2)
1884 self.assertEqual(obj1 != obj2, tag1 != tag2)
1885 self.assertNotEqual(obj1, tag2)
1887 @given(data_strategy())
1888 def test_call(self, d):
1889 for klass in (Null, NullInherited):
1895 ) = d.draw(null_values_strategy())
1896 obj_initial = klass(
1899 optional=optional_initial or False,
1900 _decoded=_decoded_initial,
1907 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
1908 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1909 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1910 self.assertEqual(obj.expl_tag, expl or expl_initial)
1911 optional = optional_initial if optional is None else optional
1912 optional = False if optional is None else optional
1913 self.assertEqual(obj.optional, optional)
1915 @given(null_values_strategy())
1916 def test_copy(self, values):
1917 for klass in (Null, NullInherited):
1918 impl, expl, optional, _decoded = values
1922 optional=optional or False,
1925 obj_copied = obj.copy()
1926 self.assert_copied_basic_fields(obj, obj_copied)
1928 @given(integers(min_value=1).map(tag_encode))
1929 def test_stripped(self, tag_impl):
1930 obj = Null(impl=tag_impl)
1931 with self.assertRaises(NotEnoughData):
1932 obj.decode(obj.encode()[:-1])
1934 @given(integers(min_value=1).map(tag_ctxc))
1935 def test_stripped_expl(self, tag_expl):
1936 obj = Null(expl=tag_expl)
1937 with self.assertRaises(NotEnoughData):
1938 obj.decode(obj.encode()[:-1])
1941 integers(min_value=31),
1942 integers(min_value=0),
1945 def test_bad_tag(self, tag, offset, decode_path):
1946 decode_path = tuple(str(i) for i in decode_path)
1947 with self.assertRaises(DecodeError) as err:
1949 tag_encode(tag)[:-1],
1951 decode_path=decode_path,
1954 self.assertEqual(err.exception.offset, offset)
1955 self.assertEqual(err.exception.decode_path, decode_path)
1958 integers(min_value=128),
1959 integers(min_value=0),
1962 def test_bad_len(self, l, offset, decode_path):
1963 decode_path = tuple(str(i) for i in decode_path)
1964 with self.assertRaises(DecodeError) as err:
1966 Null.tag_default + len_encode(l)[:-1],
1968 decode_path=decode_path,
1971 self.assertEqual(err.exception.offset, offset)
1972 self.assertEqual(err.exception.decode_path, decode_path)
1974 @given(binary(min_size=1))
1975 def test_tag_mismatch(self, impl):
1976 assume(impl != Null.tag_default)
1977 with self.assertRaises(TagMismatch):
1978 Null(impl=impl).decode(Null().encode())
1981 null_values_strategy(),
1982 integers(min_value=1).map(tag_ctxc),
1983 integers(min_value=0),
1986 def test_symmetric(self, values, tag_expl, offset, tail_junk):
1987 for klass in (Null, NullInherited):
1988 _, _, optional, _decoded = values
1989 obj = klass(optional=optional, _decoded=_decoded)
1992 self.assertFalse(obj.expled)
1993 obj_encoded = obj.encode()
1994 obj_expled = obj(expl=tag_expl)
1995 self.assertTrue(obj_expled.expled)
1998 obj_expled_encoded = obj_expled.encode()
1999 obj_decoded, tail = obj_expled.decode(
2000 obj_expled_encoded + tail_junk,
2005 self.assertEqual(tail, tail_junk)
2006 self.assertEqual(obj_decoded, obj_expled)
2007 self.assertNotEqual(obj_decoded, obj)
2008 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2009 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2010 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2012 obj_decoded.expl_llen,
2013 len(len_encode(len(obj_encoded))),
2015 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2016 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2019 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2021 self.assertEqual(obj_decoded.expl_offset, offset)
2023 @given(integers(min_value=1))
2024 def test_invalid_len(self, l):
2025 with self.assertRaises(InvalidLength):
2026 Null().decode(b"".join((
2033 def oid_strategy(draw):
2034 first_arc = draw(integers(min_value=0, max_value=2))
2036 if first_arc in (0, 1):
2037 second_arc = draw(integers(min_value=0, max_value=39))
2039 second_arc = draw(integers(min_value=0))
2040 other_arcs = draw(lists(integers(min_value=0)))
2041 return tuple([first_arc, second_arc] + other_arcs)
2045 def oid_values_strategy(draw, do_expl=False):
2046 value = draw(one_of(none(), oid_strategy()))
2050 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2052 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2053 default = draw(one_of(none(), oid_strategy()))
2054 optional = draw(one_of(none(), booleans()))
2056 draw(integers(min_value=0)),
2057 draw(integers(min_value=0)),
2058 draw(integers(min_value=0)),
2060 return (value, impl, expl, default, optional, _decoded)
2063 class ObjectIdentifierInherited(ObjectIdentifier):
2067 class TestObjectIdentifier(CommonMixin, TestCase):
2068 base_klass = ObjectIdentifier
2070 def test_invalid_value_type(self):
2071 with self.assertRaises(InvalidValueType) as err:
2072 ObjectIdentifier(123)
2076 def test_optional(self, optional):
2077 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2078 self.assertTrue(obj.optional)
2080 @given(oid_strategy())
2081 def test_ready(self, value):
2082 obj = ObjectIdentifier()
2083 self.assertFalse(obj.ready)
2086 with self.assertRaises(ObjNotReady) as err:
2089 obj = ObjectIdentifier(value)
2090 self.assertTrue(obj.ready)
2095 @given(oid_strategy(), oid_strategy(), binary(), binary())
2096 def test_comparison(self, value1, value2, tag1, tag2):
2097 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2098 obj1 = klass(value1)
2099 obj2 = klass(value2)
2100 self.assertEqual(obj1 == obj2, value1 == value2)
2101 self.assertEqual(obj1 != obj2, value1 != value2)
2102 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2103 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2104 obj1 = klass(value1, impl=tag1)
2105 obj2 = klass(value1, impl=tag2)
2106 self.assertEqual(obj1 == obj2, tag1 == tag2)
2107 self.assertEqual(obj1 != obj2, tag1 != tag2)
2109 @given(lists(oid_strategy()))
2110 def test_sorted_works(self, values):
2111 self.assertSequenceEqual(
2112 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2116 @given(data_strategy())
2117 def test_call(self, d):
2118 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2126 ) = d.draw(oid_values_strategy())
2127 obj_initial = klass(
2128 value=value_initial,
2131 default=default_initial,
2132 optional=optional_initial or False,
2133 _decoded=_decoded_initial,
2142 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2151 value_expected = default if value is None else value
2153 default_initial if value_expected is None
2156 self.assertEqual(obj, value_expected)
2157 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2158 self.assertEqual(obj.expl_tag, expl or expl_initial)
2161 default_initial if default is None else default,
2163 if obj.default is None:
2164 optional = optional_initial if optional is None else optional
2165 optional = False if optional is None else optional
2168 self.assertEqual(obj.optional, optional)
2170 @given(oid_values_strategy())
2171 def test_copy(self, values):
2172 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2189 obj_copied = obj.copy()
2190 self.assert_copied_basic_fields(obj, obj_copied)
2191 self.assertEqual(obj._value, obj_copied._value)
2193 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2196 integers(min_value=1).map(tag_encode),
2198 def test_stripped(self, value, tag_impl):
2199 obj = ObjectIdentifier(value, impl=tag_impl)
2200 with self.assertRaises(NotEnoughData):
2201 obj.decode(obj.encode()[:-1])
2205 integers(min_value=1).map(tag_ctxc),
2207 def test_stripped_expl(self, value, tag_expl):
2208 obj = ObjectIdentifier(value, expl=tag_expl)
2209 with self.assertRaises(NotEnoughData):
2210 obj.decode(obj.encode()[:-1])
2213 integers(min_value=31),
2214 integers(min_value=0),
2217 def test_bad_tag(self, tag, offset, decode_path):
2218 decode_path = tuple(str(i) for i in decode_path)
2219 with self.assertRaises(DecodeError) as err:
2220 ObjectIdentifier().decode(
2221 tag_encode(tag)[:-1],
2223 decode_path=decode_path,
2226 self.assertEqual(err.exception.offset, offset)
2227 self.assertEqual(err.exception.decode_path, decode_path)
2230 integers(min_value=128),
2231 integers(min_value=0),
2234 def test_bad_len(self, l, offset, decode_path):
2235 decode_path = tuple(str(i) for i in decode_path)
2236 with self.assertRaises(DecodeError) as err:
2237 ObjectIdentifier().decode(
2238 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2240 decode_path=decode_path,
2243 self.assertEqual(err.exception.offset, offset)
2244 self.assertEqual(err.exception.decode_path, decode_path)
2246 def test_zero_oid(self):
2247 with self.assertRaises(NotEnoughData):
2248 ObjectIdentifier().decode(
2249 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2252 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2253 @given(oid_strategy())
2254 def test_unfinished_oid(self, value):
2255 assume(list(value)[-1] > 255)
2256 obj_encoded = ObjectIdentifier(value).encode()
2257 obj, _ = ObjectIdentifier().decode(obj_encoded)
2258 data = obj_encoded[obj.tlen + obj.llen:-1]
2260 ObjectIdentifier.tag_default,
2261 len_encode(len(data)),
2264 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2267 @given(integers(min_value=0))
2268 def test_invalid_short(self, value):
2269 with self.assertRaises(InvalidOID):
2270 ObjectIdentifier((value,))
2271 with self.assertRaises(InvalidOID):
2272 ObjectIdentifier("%d" % value)
2274 @given(integers(min_value=3), integers(min_value=0))
2275 def test_invalid_first_arc(self, first_arc, second_arc):
2276 with self.assertRaises(InvalidOID):
2277 ObjectIdentifier((first_arc, second_arc))
2278 with self.assertRaises(InvalidOID):
2279 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2281 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2282 def test_invalid_second_arc(self, first_arc, second_arc):
2283 with self.assertRaises(InvalidOID):
2284 ObjectIdentifier((first_arc, second_arc))
2285 with self.assertRaises(InvalidOID):
2286 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2288 @given(text(alphabet=ascii_letters + ".", min_size=1))
2289 def test_junk(self, oid):
2290 with self.assertRaises(InvalidOID):
2291 ObjectIdentifier(oid)
2293 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2294 @given(oid_strategy())
2295 def test_validness(self, oid):
2296 obj = ObjectIdentifier(oid)
2297 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2302 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2304 oid_values_strategy(),
2306 integers(min_value=1).map(tag_ctxc),
2307 integers(min_value=0),
2310 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2311 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2312 _, _, _, default, optional, _decoded = values
2321 self.assertFalse(obj.expled)
2322 obj_encoded = obj.encode()
2323 obj_expled = obj(value, expl=tag_expl)
2324 self.assertTrue(obj_expled.expled)
2327 obj_expled_encoded = obj_expled.encode()
2328 obj_decoded, tail = obj_expled.decode(
2329 obj_expled_encoded + tail_junk,
2334 self.assertEqual(tail, tail_junk)
2335 self.assertEqual(obj_decoded, obj_expled)
2336 self.assertNotEqual(obj_decoded, obj)
2337 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2338 self.assertEqual(tuple(obj_decoded), tuple(obj))
2339 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2340 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2341 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2343 obj_decoded.expl_llen,
2344 len(len_encode(len(obj_encoded))),
2346 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2347 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2350 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2352 self.assertEqual(obj_decoded.expl_offset, offset)
2355 oid_strategy().map(ObjectIdentifier),
2356 oid_strategy().map(ObjectIdentifier),
2358 def test_add(self, oid1, oid2):
2359 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2360 for oid_to_add in (oid2, tuple(oid2)):
2361 self.assertEqual(oid1 + oid_to_add, oid_expect)
2362 with self.assertRaises(InvalidValueType):
2365 def test_go_vectors_valid(self):
2366 for data, expect in (
2368 (b"\x55\x02", (2, 5, 2)),
2369 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2370 (b"\x81\x34\x03", (2, 100, 3)),
2373 ObjectIdentifier().decode(b"".join((
2374 ObjectIdentifier.tag_default,
2375 len_encode(len(data)),
2381 def test_go_vectors_invalid(self):
2382 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2383 with self.assertRaises(DecodeError):
2384 ObjectIdentifier().decode(b"".join((
2385 Integer.tag_default,
2386 len_encode(len(data)),
2390 def test_x690_vector(self):
2392 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2393 ObjectIdentifier((2, 999, 3)),
2398 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2400 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2401 values = list(draw(sets(
2403 min_size=len(schema),
2404 max_size=len(schema),
2406 schema = list(zip(schema, values))
2407 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2411 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2413 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2414 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2415 optional = draw(one_of(none(), booleans()))
2417 draw(integers(min_value=0)),
2418 draw(integers(min_value=0)),
2419 draw(integers(min_value=0)),
2421 return (schema, value, impl, expl, default, optional, _decoded)
2424 class TestEnumerated(CommonMixin, TestCase):
2425 class EWhatever(Enumerated):
2426 schema = (("whatever", 0),)
2428 base_klass = EWhatever
2430 def test_schema_required(self):
2431 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2434 def test_invalid_value_type(self):
2435 with self.assertRaises(InvalidValueType) as err:
2436 self.base_klass((1, 2))
2439 @given(sets(text_letters(), min_size=2))
2440 def test_unknown_name(self, schema_input):
2441 missing = schema_input.pop()
2443 class E(Enumerated):
2444 schema = [(n, 123) for n in schema_input]
2445 with self.assertRaises(ObjUnknown) as err:
2450 sets(text_letters(), min_size=2),
2451 sets(integers(), min_size=2),
2453 def test_unknown_value(self, schema_input, values_input):
2455 missing_value = values_input.pop()
2456 _input = list(zip(schema_input, values_input))
2458 class E(Enumerated):
2460 with self.assertRaises(DecodeError) as err:
2465 def test_optional(self, optional):
2466 obj = self.base_klass(default="whatever", optional=optional)
2467 self.assertTrue(obj.optional)
2469 def test_ready(self):
2470 obj = self.base_klass()
2471 self.assertFalse(obj.ready)
2474 with self.assertRaises(ObjNotReady) as err:
2477 obj = self.base_klass("whatever")
2478 self.assertTrue(obj.ready)
2482 @given(integers(), integers(), binary(), binary())
2483 def test_comparison(self, value1, value2, tag1, tag2):
2484 class E(Enumerated):
2486 ("whatever0", value1),
2487 ("whatever1", value2),
2490 class EInherited(E):
2492 for klass in (E, EInherited):
2493 obj1 = klass(value1)
2494 obj2 = klass(value2)
2495 self.assertEqual(obj1 == obj2, value1 == value2)
2496 self.assertEqual(obj1 != obj2, value1 != value2)
2497 self.assertEqual(obj1 == int(obj2), value1 == value2)
2498 obj1 = klass(value1, impl=tag1)
2499 obj2 = klass(value1, impl=tag2)
2500 self.assertEqual(obj1 == obj2, tag1 == tag2)
2501 self.assertEqual(obj1 != obj2, tag1 != tag2)
2503 @given(data_strategy())
2504 def test_call(self, d):
2513 ) = d.draw(enumerated_values_strategy())
2515 class E(Enumerated):
2516 schema = schema_initial
2518 value=value_initial,
2521 default=default_initial,
2522 optional=optional_initial or False,
2523 _decoded=_decoded_initial,
2533 ) = d.draw(enumerated_values_strategy(
2534 schema=schema_initial,
2535 do_expl=impl_initial is None,
2545 value_expected = default if value is None else value
2547 default_initial if value_expected is None
2552 dict(schema_initial).get(value_expected, value_expected),
2554 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2555 self.assertEqual(obj.expl_tag, expl or expl_initial)
2558 default_initial if default is None else default,
2560 if obj.default is None:
2561 optional = optional_initial if optional is None else optional
2562 optional = False if optional is None else optional
2565 self.assertEqual(obj.optional, optional)
2566 self.assertEqual(obj.specs, dict(schema_initial))
2568 @given(enumerated_values_strategy())
2569 def test_copy(self, values):
2570 schema_input, value, impl, expl, default, optional, _decoded = values
2572 class E(Enumerated):
2573 schema = schema_input
2582 obj_copied = obj.copy()
2583 self.assert_copied_basic_fields(obj, obj_copied)
2584 self.assertEqual(obj.specs, obj_copied.specs)
2586 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2587 @given(data_strategy())
2588 def test_symmetric(self, d):
2589 schema_input, _, _, _, default, optional, _decoded = d.draw(
2590 enumerated_values_strategy(),
2592 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2593 offset = d.draw(integers(min_value=0))
2594 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2595 tail_junk = d.draw(binary(max_size=5))
2597 class E(Enumerated):
2598 schema = schema_input
2607 self.assertFalse(obj.expled)
2608 obj_encoded = obj.encode()
2609 obj_expled = obj(value, expl=tag_expl)
2610 self.assertTrue(obj_expled.expled)
2613 obj_expled_encoded = obj_expled.encode()
2614 obj_decoded, tail = obj_expled.decode(
2615 obj_expled_encoded + tail_junk,
2620 self.assertEqual(tail, tail_junk)
2621 self.assertEqual(obj_decoded, obj_expled)
2622 self.assertNotEqual(obj_decoded, obj)
2623 self.assertEqual(int(obj_decoded), int(obj_expled))
2624 self.assertEqual(int(obj_decoded), int(obj))
2625 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2626 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2627 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2629 obj_decoded.expl_llen,
2630 len(len_encode(len(obj_encoded))),
2632 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2633 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2636 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2638 self.assertEqual(obj_decoded.expl_offset, offset)
2642 def string_values_strategy(draw, alphabet, do_expl=False):
2643 bound_min, bound_max = sorted(draw(sets(
2644 integers(min_value=0, max_value=1 << 7),
2648 value = draw(one_of(
2650 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2652 default = draw(one_of(
2654 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2657 if draw(booleans()):
2658 bounds = (bound_min, bound_max)
2662 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2664 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2665 optional = draw(one_of(none(), booleans()))
2667 draw(integers(min_value=0)),
2668 draw(integers(min_value=0)),
2669 draw(integers(min_value=0)),
2671 return (value, bounds, impl, expl, default, optional, _decoded)
2674 class StringMixin(object):
2675 def test_invalid_value_type(self):
2676 with self.assertRaises(InvalidValueType) as err:
2677 self.base_klass((1, 2))
2680 def text_alphabet(self):
2681 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2682 return printable + whitespace
2686 def test_optional(self, optional):
2687 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2688 self.assertTrue(obj.optional)
2690 @given(data_strategy())
2691 def test_ready(self, d):
2692 obj = self.base_klass()
2693 self.assertFalse(obj.ready)
2697 with self.assertRaises(ObjNotReady) as err:
2700 value = d.draw(text(alphabet=self.text_alphabet()))
2701 obj = self.base_klass(value)
2702 self.assertTrue(obj.ready)
2707 @given(data_strategy())
2708 def test_comparison(self, d):
2709 value1 = d.draw(text(alphabet=self.text_alphabet()))
2710 value2 = d.draw(text(alphabet=self.text_alphabet()))
2711 tag1 = d.draw(binary(min_size=1))
2712 tag2 = d.draw(binary(min_size=1))
2713 obj1 = self.base_klass(value1)
2714 obj2 = self.base_klass(value2)
2715 self.assertEqual(obj1 == obj2, value1 == value2)
2716 self.assertEqual(obj1 != obj2, value1 != value2)
2717 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2718 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2719 obj1 = self.base_klass(value1, impl=tag1)
2720 obj2 = self.base_klass(value1, impl=tag2)
2721 self.assertEqual(obj1 == obj2, tag1 == tag2)
2722 self.assertEqual(obj1 != obj2, tag1 != tag2)
2724 @given(data_strategy())
2725 def test_bounds_satisfied(self, d):
2726 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2727 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2728 value = d.draw(text(
2729 alphabet=self.text_alphabet(),
2733 self.base_klass(value=value, bounds=(bound_min, bound_max))
2735 @given(data_strategy())
2736 def test_bounds_unsatisfied(self, d):
2737 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2738 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2739 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2740 with self.assertRaises(BoundsError) as err:
2741 self.base_klass(value=value, bounds=(bound_min, bound_max))
2743 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2744 with self.assertRaises(BoundsError) as err:
2745 self.base_klass(value=value, bounds=(bound_min, bound_max))
2748 @given(data_strategy())
2749 def test_call(self, d):
2758 ) = d.draw(string_values_strategy(self.text_alphabet()))
2759 obj_initial = self.base_klass(
2765 optional_initial or False,
2776 ) = d.draw(string_values_strategy(
2777 self.text_alphabet(),
2778 do_expl=impl_initial is None,
2780 if (default is None) and (obj_initial.default is not None):
2783 (bounds is None) and
2784 (value is not None) and
2785 (bounds_initial is not None) and
2786 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2790 (bounds is None) and
2791 (default is not None) and
2792 (bounds_initial is not None) and
2793 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2796 obj = obj_initial(value, bounds, impl, expl, default, optional)
2798 value_expected = default if value is None else value
2800 default_initial if value_expected is None
2803 self.assertEqual(obj, value_expected)
2804 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2805 self.assertEqual(obj.expl_tag, expl or expl_initial)
2808 default_initial if default is None else default,
2810 if obj.default is None:
2811 optional = optional_initial if optional is None else optional
2812 optional = False if optional is None else optional
2815 self.assertEqual(obj.optional, optional)
2817 (obj._bound_min, obj._bound_max),
2818 bounds or bounds_initial or (0, float("+inf")),
2821 @given(data_strategy())
2822 def test_copy(self, d):
2823 values = d.draw(string_values_strategy(self.text_alphabet()))
2824 obj = self.base_klass(*values)
2825 obj_copied = obj.copy()
2826 self.assert_copied_basic_fields(obj, obj_copied)
2827 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2828 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2829 self.assertEqual(obj._value, obj_copied._value)
2831 @given(data_strategy())
2832 def test_stripped(self, d):
2833 value = d.draw(text(alphabet=self.text_alphabet()))
2834 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2835 obj = self.base_klass(value, impl=tag_impl)
2836 with self.assertRaises(NotEnoughData):
2837 obj.decode(obj.encode()[:-1])
2839 @given(data_strategy())
2840 def test_stripped_expl(self, d):
2841 value = d.draw(text(alphabet=self.text_alphabet()))
2842 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2843 obj = self.base_klass(value, expl=tag_expl)
2844 with self.assertRaises(NotEnoughData):
2845 obj.decode(obj.encode()[:-1])
2848 integers(min_value=31),
2849 integers(min_value=0),
2852 def test_bad_tag(self, tag, offset, decode_path):
2853 decode_path = tuple(str(i) for i in decode_path)
2854 with self.assertRaises(DecodeError) as err:
2855 self.base_klass().decode(
2856 tag_encode(tag)[:-1],
2858 decode_path=decode_path,
2861 self.assertEqual(err.exception.offset, offset)
2862 self.assertEqual(err.exception.decode_path, decode_path)
2865 integers(min_value=128),
2866 integers(min_value=0),
2869 def test_bad_len(self, l, offset, decode_path):
2870 decode_path = tuple(str(i) for i in decode_path)
2871 with self.assertRaises(DecodeError) as err:
2872 self.base_klass().decode(
2873 self.base_klass.tag_default + len_encode(l)[:-1],
2875 decode_path=decode_path,
2878 self.assertEqual(err.exception.offset, offset)
2879 self.assertEqual(err.exception.decode_path, decode_path)
2882 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2883 integers(min_value=0),
2886 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2887 decode_path = tuple(str(i) for i in decode_path)
2888 value, bound_min = list(sorted(ints))
2890 class String(self.base_klass):
2891 # Multiply this value by four, to satisfy UTF-32 bounds
2892 # (4 bytes per character) validation
2893 bounds = (bound_min * 4, bound_min * 4)
2894 with self.assertRaises(DecodeError) as err:
2896 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2898 decode_path=decode_path,
2901 self.assertEqual(err.exception.offset, offset)
2902 self.assertEqual(err.exception.decode_path, decode_path)
2904 @given(data_strategy())
2905 def test_symmetric(self, d):
2906 values = d.draw(string_values_strategy(self.text_alphabet()))
2907 value = d.draw(text(alphabet=self.text_alphabet()))
2908 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2909 offset = d.draw(integers(min_value=0))
2910 tail_junk = d.draw(binary(max_size=5))
2911 _, _, _, _, default, optional, _decoded = values
2912 obj = self.base_klass(
2920 self.assertFalse(obj.expled)
2921 obj_encoded = obj.encode()
2922 obj_expled = obj(value, expl=tag_expl)
2923 self.assertTrue(obj_expled.expled)
2926 obj_expled_encoded = obj_expled.encode()
2927 obj_decoded, tail = obj_expled.decode(
2928 obj_expled_encoded + tail_junk,
2933 self.assertEqual(tail, tail_junk)
2934 self.assertEqual(obj_decoded, obj_expled)
2935 self.assertNotEqual(obj_decoded, obj)
2936 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2937 self.assertEqual(bytes(obj_decoded), bytes(obj))
2938 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2939 self.assertEqual(text_type(obj_decoded), text_type(obj))
2940 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2941 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2942 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2944 obj_decoded.expl_llen,
2945 len(len_encode(len(obj_encoded))),
2947 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2948 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2951 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2953 self.assertEqual(obj_decoded.expl_offset, offset)
2956 class TestUTF8String(StringMixin, CommonMixin, TestCase):
2957 base_klass = UTF8String
2960 class UnicodeDecodeErrorMixin(object):
2962 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
2966 def test_unicode_decode_error(self, cyrillic_text):
2967 with self.assertRaises(DecodeError):
2968 self.base_klass(cyrillic_text)
2971 class TestNumericString(StringMixin, CommonMixin, TestCase):
2972 base_klass = NumericString
2974 def text_alphabet(self):
2977 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
2978 def test_non_numeric(self, cyrillic_text):
2979 with assertRaisesRegex(self, DecodeError, "non-numeric"):
2980 self.base_klass(cyrillic_text)
2983 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2984 integers(min_value=0),
2987 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2988 decode_path = tuple(str(i) for i in decode_path)
2989 value, bound_min = list(sorted(ints))
2991 class String(self.base_klass):
2992 bounds = (bound_min, bound_min)
2993 with self.assertRaises(DecodeError) as err:
2995 self.base_klass(b"1" * value).encode(),
2997 decode_path=decode_path,
3000 self.assertEqual(err.exception.offset, offset)
3001 self.assertEqual(err.exception.decode_path, decode_path)
3004 class TestPrintableString(
3005 UnicodeDecodeErrorMixin,
3010 base_klass = PrintableString
3013 class TestTeletexString(
3014 UnicodeDecodeErrorMixin,
3019 base_klass = TeletexString
3022 class TestVideotexString(
3023 UnicodeDecodeErrorMixin,
3028 base_klass = VideotexString
3031 class TestIA5String(
3032 UnicodeDecodeErrorMixin,
3037 base_klass = IA5String
3040 class TestGraphicString(
3041 UnicodeDecodeErrorMixin,
3046 base_klass = GraphicString
3049 class TestVisibleString(
3050 UnicodeDecodeErrorMixin,
3055 base_klass = VisibleString
3057 def test_x690_vector(self):
3059 str(VisibleString().decode(hexdec("1A054A6F6E6573"))[0]),
3063 str(VisibleString().decode(
3064 hexdec("3A0904034A6F6E04026573"),
3065 ctx={"bered": True},
3070 str(VisibleString().decode(
3071 hexdec("3A8004034A6F6E040265730000"),
3072 ctx={"bered": True},
3078 class TestGeneralString(
3079 UnicodeDecodeErrorMixin,
3084 base_klass = GeneralString
3087 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3088 base_klass = UniversalString
3091 class TestBMPString(StringMixin, CommonMixin, TestCase):
3092 base_klass = BMPString
3096 def generalized_time_values_strategy(
3104 if draw(booleans()):
3105 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3107 value = value.replace(microsecond=0)
3109 if draw(booleans()):
3110 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3112 default = default.replace(microsecond=0)
3116 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3118 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3119 optional = draw(one_of(none(), booleans()))
3121 draw(integers(min_value=0)),
3122 draw(integers(min_value=0)),
3123 draw(integers(min_value=0)),
3125 return (value, impl, expl, default, optional, _decoded)
3128 class TimeMixin(object):
3129 def test_invalid_value_type(self):
3130 with self.assertRaises(InvalidValueType) as err:
3131 self.base_klass(datetime.now().timetuple())
3134 @given(data_strategy())
3135 def test_optional(self, d):
3136 default = d.draw(datetimes(
3137 min_value=self.min_datetime,
3138 max_value=self.max_datetime,
3140 optional = d.draw(booleans())
3141 obj = self.base_klass(default=default, optional=optional)
3142 self.assertTrue(obj.optional)
3144 @given(data_strategy())
3145 def test_ready(self, d):
3146 obj = self.base_klass()
3147 self.assertFalse(obj.ready)
3150 with self.assertRaises(ObjNotReady) as err:
3153 value = d.draw(datetimes(min_value=self.min_datetime))
3154 obj = self.base_klass(value)
3155 self.assertTrue(obj.ready)
3159 @given(data_strategy())
3160 def test_comparison(self, d):
3161 value1 = d.draw(datetimes(
3162 min_value=self.min_datetime,
3163 max_value=self.max_datetime,
3165 value2 = d.draw(datetimes(
3166 min_value=self.min_datetime,
3167 max_value=self.max_datetime,
3169 tag1 = d.draw(binary(min_size=1))
3170 tag2 = d.draw(binary(min_size=1))
3172 value1 = value1.replace(microsecond=0)
3173 value2 = value2.replace(microsecond=0)
3174 obj1 = self.base_klass(value1)
3175 obj2 = self.base_klass(value2)
3176 self.assertEqual(obj1 == obj2, value1 == value2)
3177 self.assertEqual(obj1 != obj2, value1 != value2)
3178 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3179 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3180 obj1 = self.base_klass(value1, impl=tag1)
3181 obj2 = self.base_klass(value1, impl=tag2)
3182 self.assertEqual(obj1 == obj2, tag1 == tag2)
3183 self.assertEqual(obj1 != obj2, tag1 != tag2)
3185 @given(data_strategy())
3186 def test_call(self, d):
3194 ) = d.draw(generalized_time_values_strategy(
3195 min_datetime=self.min_datetime,
3196 max_datetime=self.max_datetime,
3197 omit_ms=self.omit_ms,
3199 obj_initial = self.base_klass(
3200 value=value_initial,
3203 default=default_initial,
3204 optional=optional_initial or False,
3205 _decoded=_decoded_initial,
3214 ) = d.draw(generalized_time_values_strategy(
3215 min_datetime=self.min_datetime,
3216 max_datetime=self.max_datetime,
3217 omit_ms=self.omit_ms,
3218 do_expl=impl_initial is None,
3228 value_expected = default if value is None else value
3230 default_initial if value_expected is None
3233 self.assertEqual(obj, value_expected)
3234 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3235 self.assertEqual(obj.expl_tag, expl or expl_initial)
3238 default_initial if default is None else default,
3240 if obj.default is None:
3241 optional = optional_initial if optional is None else optional
3242 optional = False if optional is None else optional
3245 self.assertEqual(obj.optional, optional)
3247 @given(data_strategy())
3248 def test_copy(self, d):
3249 values = d.draw(generalized_time_values_strategy(
3250 min_datetime=self.min_datetime,
3251 max_datetime=self.max_datetime,
3253 obj = self.base_klass(*values)
3254 obj_copied = obj.copy()
3255 self.assert_copied_basic_fields(obj, obj_copied)
3256 self.assertEqual(obj._value, obj_copied._value)
3258 @given(data_strategy())
3259 def test_stripped(self, d):
3260 value = d.draw(datetimes(
3261 min_value=self.min_datetime,
3262 max_value=self.max_datetime,
3264 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3265 obj = self.base_klass(value, impl=tag_impl)
3266 with self.assertRaises(NotEnoughData):
3267 obj.decode(obj.encode()[:-1])
3269 @given(data_strategy())
3270 def test_stripped_expl(self, d):
3271 value = d.draw(datetimes(
3272 min_value=self.min_datetime,
3273 max_value=self.max_datetime,
3275 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3276 obj = self.base_klass(value, expl=tag_expl)
3277 with self.assertRaises(NotEnoughData):
3278 obj.decode(obj.encode()[:-1])
3280 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3281 @given(data_strategy())
3282 def test_symmetric(self, d):
3283 values = d.draw(generalized_time_values_strategy(
3284 min_datetime=self.min_datetime,
3285 max_datetime=self.max_datetime,
3287 value = d.draw(datetimes(
3288 min_value=self.min_datetime,
3289 max_value=self.max_datetime,
3291 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3292 offset = d.draw(integers(min_value=0))
3293 tail_junk = d.draw(binary(max_size=5))
3294 _, _, _, default, optional, _decoded = values
3295 obj = self.base_klass(
3303 self.assertFalse(obj.expled)
3304 obj_encoded = obj.encode()
3305 obj_expled = obj(value, expl=tag_expl)
3306 self.assertTrue(obj_expled.expled)
3309 obj_expled_encoded = obj_expled.encode()
3310 obj_decoded, tail = obj_expled.decode(
3311 obj_expled_encoded + tail_junk,
3316 self.assertEqual(tail, tail_junk)
3317 self.assertEqual(obj_decoded, obj_expled)
3318 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3319 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3320 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3321 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3322 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3324 obj_decoded.expl_llen,
3325 len(len_encode(len(obj_encoded))),
3327 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3328 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3331 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3333 self.assertEqual(obj_decoded.expl_offset, offset)
3336 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3337 base_klass = GeneralizedTime
3339 min_datetime = datetime(1900, 1, 1)
3340 max_datetime = datetime(9999, 12, 31)
3342 def test_go_vectors_invalid(self):
3354 b"-20100102030410Z",
3355 b"2010-0102030410Z",
3356 b"2010-0002030410Z",
3357 b"201001-02030410Z",
3358 b"20100102-030410Z",
3359 b"2010010203-0410Z",
3360 b"201001020304-10Z",
3361 # These ones are INVALID in *DER*, but accepted
3362 # by Go's encoding/asn1
3363 b"20100102030405+0607",
3364 b"20100102030405-0607",
3366 with self.assertRaises(DecodeError) as err:
3367 GeneralizedTime(data)
3370 def test_go_vectors_valid(self):
3372 GeneralizedTime(b"20100102030405Z").todatetime(),
3373 datetime(2010, 1, 2, 3, 4, 5, 0),
3377 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3378 base_klass = UTCTime
3380 min_datetime = datetime(2000, 1, 1)
3381 max_datetime = datetime(2049, 12, 31)
3383 def test_go_vectors_invalid(self):
3409 # These ones are INVALID in *DER*, but accepted
3410 # by Go's encoding/asn1
3411 b"910506164540-0700",
3412 b"910506164540+0730",
3416 with self.assertRaises(DecodeError) as err:
3420 def test_go_vectors_valid(self):
3422 UTCTime(b"910506234540Z").todatetime(),
3423 datetime(1991, 5, 6, 23, 45, 40, 0),
3426 @given(integers(min_value=0, max_value=49))
3427 def test_pre50(self, year):
3429 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3433 @given(integers(min_value=50, max_value=99))
3434 def test_post50(self, year):
3436 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3442 def any_values_strategy(draw, do_expl=False):
3443 value = draw(one_of(none(), binary()))
3446 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3447 optional = draw(one_of(none(), booleans()))
3449 draw(integers(min_value=0)),
3450 draw(integers(min_value=0)),
3451 draw(integers(min_value=0)),
3453 return (value, expl, optional, _decoded)
3456 class AnyInherited(Any):
3460 class TestAny(CommonMixin, TestCase):
3463 def test_invalid_value_type(self):
3464 with self.assertRaises(InvalidValueType) as err:
3469 def test_optional(self, optional):
3470 obj = Any(optional=optional)
3471 self.assertEqual(obj.optional, optional)
3474 def test_ready(self, value):
3476 self.assertFalse(obj.ready)
3479 with self.assertRaises(ObjNotReady) as err:
3483 self.assertTrue(obj.ready)
3488 def test_basic(self, value):
3489 integer_encoded = Integer(value).encode()
3491 Any(integer_encoded),
3492 Any(Integer(value)),
3493 Any(Any(Integer(value))),
3495 self.assertSequenceEqual(bytes(obj), integer_encoded)
3497 obj.decode(obj.encode())[0].vlen,
3498 len(integer_encoded),
3502 self.assertSequenceEqual(obj.encode(), integer_encoded)
3504 @given(binary(), binary())
3505 def test_comparison(self, value1, value2):
3506 for klass in (Any, AnyInherited):
3507 obj1 = klass(value1)
3508 obj2 = klass(value2)
3509 self.assertEqual(obj1 == obj2, value1 == value2)
3510 self.assertEqual(obj1 != obj2, value1 != value2)
3511 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3513 @given(data_strategy())
3514 def test_call(self, d):
3515 for klass in (Any, AnyInherited):
3521 ) = d.draw(any_values_strategy())
3522 obj_initial = klass(
3525 optional_initial or False,
3533 ) = d.draw(any_values_strategy(do_expl=True))
3534 obj = obj_initial(value, expl, optional)
3536 value_expected = None if value is None else value
3537 self.assertEqual(obj, value_expected)
3538 self.assertEqual(obj.expl_tag, expl or expl_initial)
3539 if obj.default is None:
3540 optional = optional_initial if optional is None else optional
3541 optional = False if optional is None else optional
3542 self.assertEqual(obj.optional, optional)
3544 def test_simultaneous_impl_expl(self):
3545 # override it, as Any does not have implicit tag
3548 def test_decoded(self):
3549 # override it, as Any does not have implicit tag
3552 @given(any_values_strategy())
3553 def test_copy(self, values):
3554 for klass in (Any, AnyInherited):
3555 obj = klass(*values)
3556 obj_copied = obj.copy()
3557 self.assert_copied_basic_fields(obj, obj_copied)
3558 self.assertEqual(obj._value, obj_copied._value)
3560 @given(binary().map(OctetString))
3561 def test_stripped(self, value):
3563 with self.assertRaises(NotEnoughData):
3564 obj.decode(obj.encode()[:-1])
3568 integers(min_value=1).map(tag_ctxc),
3570 def test_stripped_expl(self, value, tag_expl):
3571 obj = Any(value, expl=tag_expl)
3572 with self.assertRaises(NotEnoughData):
3573 obj.decode(obj.encode()[:-1])
3576 integers(min_value=31),
3577 integers(min_value=0),
3580 def test_bad_tag(self, tag, offset, decode_path):
3581 decode_path = tuple(str(i) for i in decode_path)
3582 with self.assertRaises(DecodeError) as err:
3584 tag_encode(tag)[:-1],
3586 decode_path=decode_path,
3589 self.assertEqual(err.exception.offset, offset)
3590 self.assertEqual(err.exception.decode_path, decode_path)
3593 integers(min_value=128),
3594 integers(min_value=0),
3597 def test_bad_len(self, l, offset, decode_path):
3598 decode_path = tuple(str(i) for i in decode_path)
3599 with self.assertRaises(DecodeError) as err:
3601 Any.tag_default + len_encode(l)[:-1],
3603 decode_path=decode_path,
3606 self.assertEqual(err.exception.offset, offset)
3607 self.assertEqual(err.exception.decode_path, decode_path)
3609 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3611 any_values_strategy(),
3612 integers().map(lambda x: Integer(x).encode()),
3613 integers(min_value=1).map(tag_ctxc),
3614 integers(min_value=0),
3617 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3618 for klass in (Any, AnyInherited):
3619 _, _, optional, _decoded = values
3620 obj = klass(value=value, optional=optional, _decoded=_decoded)
3623 self.assertFalse(obj.expled)
3624 obj_encoded = obj.encode()
3625 obj_expled = obj(value, expl=tag_expl)
3626 self.assertTrue(obj_expled.expled)
3629 obj_expled_encoded = obj_expled.encode()
3630 obj_decoded, tail = obj_expled.decode(
3631 obj_expled_encoded + tail_junk,
3636 self.assertEqual(tail, tail_junk)
3637 self.assertEqual(obj_decoded, obj_expled)
3638 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3639 self.assertEqual(bytes(obj_decoded), bytes(obj))
3640 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3641 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3642 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3644 obj_decoded.expl_llen,
3645 len(len_encode(len(obj_encoded))),
3647 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3648 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3651 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3653 self.assertEqual(obj_decoded.expl_offset, offset)
3654 self.assertEqual(obj_decoded.tlen, 0)
3655 self.assertEqual(obj_decoded.llen, 0)
3656 self.assertEqual(obj_decoded.vlen, len(value))
3660 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3662 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3663 tags = [tag_encode(tag) for tag in draw(sets(
3664 integers(min_value=0),
3665 min_size=len(names),
3666 max_size=len(names),
3668 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3670 if value_required or draw(booleans()):
3671 value = draw(tuples(
3672 sampled_from([name for name, _ in schema]),
3673 integers().map(Integer),
3677 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3678 default = draw(one_of(
3680 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3682 optional = draw(one_of(none(), booleans()))
3684 draw(integers(min_value=0)),
3685 draw(integers(min_value=0)),
3686 draw(integers(min_value=0)),
3688 return (schema, value, expl, default, optional, _decoded)
3691 class ChoiceInherited(Choice):
3695 class TestChoice(CommonMixin, TestCase):
3697 schema = (("whatever", Boolean()),)
3700 def test_schema_required(self):
3701 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3704 def test_impl_forbidden(self):
3705 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3706 Choice(impl=b"whatever")
3708 def test_invalid_value_type(self):
3709 with self.assertRaises(InvalidValueType) as err:
3710 self.base_klass(123)
3712 with self.assertRaises(ObjUnknown) as err:
3713 self.base_klass(("whenever", Boolean(False)))
3715 with self.assertRaises(InvalidValueType) as err:
3716 self.base_klass(("whatever", Integer(123)))
3720 def test_optional(self, optional):
3721 obj = self.base_klass(
3722 default=self.base_klass(("whatever", Boolean(False))),
3725 self.assertTrue(obj.optional)
3728 def test_ready(self, value):
3729 obj = self.base_klass()
3730 self.assertFalse(obj.ready)
3733 self.assertIsNone(obj["whatever"])
3734 with self.assertRaises(ObjNotReady) as err:
3737 obj["whatever"] = Boolean()
3738 self.assertFalse(obj.ready)
3741 obj["whatever"] = Boolean(value)
3742 self.assertTrue(obj.ready)
3746 @given(booleans(), booleans())
3747 def test_comparison(self, value1, value2):
3748 class WahlInherited(self.base_klass):
3750 for klass in (self.base_klass, WahlInherited):
3751 obj1 = klass(("whatever", Boolean(value1)))
3752 obj2 = klass(("whatever", Boolean(value2)))
3753 self.assertEqual(obj1 == obj2, value1 == value2)
3754 self.assertEqual(obj1 != obj2, value1 != value2)
3755 self.assertEqual(obj1 == obj2._value, value1 == value2)
3756 self.assertFalse(obj1 == obj2._value[1])
3758 @given(data_strategy())
3759 def test_call(self, d):
3760 for klass in (Choice, ChoiceInherited):
3768 ) = d.draw(choice_values_strategy())
3771 schema = schema_initial
3773 value=value_initial,
3775 default=default_initial,
3776 optional=optional_initial or False,
3777 _decoded=_decoded_initial,
3786 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
3787 obj = obj_initial(value, expl, default, optional)
3789 value_expected = default if value is None else value
3791 default_initial if value_expected is None
3794 self.assertEqual(obj.choice, value_expected[0])
3795 self.assertEqual(obj.value, int(value_expected[1]))
3796 self.assertEqual(obj.expl_tag, expl or expl_initial)
3797 default_expect = default_initial if default is None else default
3798 if default_expect is not None:
3799 self.assertEqual(obj.default.choice, default_expect[0])
3800 self.assertEqual(obj.default.value, int(default_expect[1]))
3801 if obj.default is None:
3802 optional = optional_initial if optional is None else optional
3803 optional = False if optional is None else optional
3806 self.assertEqual(obj.optional, optional)
3807 self.assertEqual(obj.specs, obj_initial.specs)
3809 def test_simultaneous_impl_expl(self):
3810 # override it, as Any does not have implicit tag
3813 def test_decoded(self):
3814 # override it, as Any does not have implicit tag
3817 @given(choice_values_strategy())
3818 def test_copy(self, values):
3819 _schema, value, expl, default, optional, _decoded = values
3821 class Wahl(self.base_klass):
3827 optional=optional or False,
3830 obj_copied = obj.copy()
3831 self.assertIsNone(obj.tag)
3832 self.assertIsNone(obj_copied.tag)
3833 # hack for assert_copied_basic_fields
3834 obj.tag = "whatever"
3835 obj_copied.tag = "whatever"
3836 self.assert_copied_basic_fields(obj, obj_copied)
3837 self.assertEqual(obj._value, obj_copied._value)
3838 self.assertEqual(obj.specs, obj_copied.specs)
3841 def test_stripped(self, value):
3842 obj = self.base_klass(("whatever", Boolean(value)))
3843 with self.assertRaises(NotEnoughData):
3844 obj.decode(obj.encode()[:-1])
3848 integers(min_value=1).map(tag_ctxc),
3850 def test_stripped_expl(self, value, tag_expl):
3851 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3852 with self.assertRaises(NotEnoughData):
3853 obj.decode(obj.encode()[:-1])
3855 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3856 @given(data_strategy())
3857 def test_symmetric(self, d):
3858 _schema, value, _, default, optional, _decoded = d.draw(
3859 choice_values_strategy(value_required=True)
3861 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3862 offset = d.draw(integers(min_value=0))
3863 tail_junk = d.draw(binary(max_size=5))
3865 class Wahl(self.base_klass):
3875 self.assertFalse(obj.expled)
3876 obj_encoded = obj.encode()
3877 obj_expled = obj(value, expl=tag_expl)
3878 self.assertTrue(obj_expled.expled)
3881 obj_expled_encoded = obj_expled.encode()
3882 obj_decoded, tail = obj_expled.decode(
3883 obj_expled_encoded + tail_junk,
3888 self.assertEqual(tail, tail_junk)
3889 self.assertEqual(obj_decoded, obj_expled)
3890 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3891 self.assertEqual(obj_decoded.value, obj_expled.value)
3892 self.assertEqual(obj_decoded.choice, obj.choice)
3893 self.assertEqual(obj_decoded.value, obj.value)
3894 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3895 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3896 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3898 obj_decoded.expl_llen,
3899 len(len_encode(len(obj_encoded))),
3901 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3902 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3905 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3907 self.assertEqual(obj_decoded.expl_offset, offset)
3908 self.assertSequenceEqual(
3910 obj_decoded.value.offset - offset:
3911 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3917 def test_set_get(self, value):
3920 ("erste", Boolean()),
3921 ("zweite", Integer()),
3924 with self.assertRaises(ObjUnknown) as err:
3925 obj["whatever"] = "whenever"
3926 with self.assertRaises(InvalidValueType) as err:
3927 obj["zweite"] = Boolean(False)
3928 obj["zweite"] = Integer(value)
3930 with self.assertRaises(ObjUnknown) as err:
3933 self.assertIsNone(obj["erste"])
3934 self.assertEqual(obj["zweite"], Integer(value))
3936 def test_tag_mismatch(self):
3939 ("erste", Boolean()),
3941 int_encoded = Integer(123).encode()
3942 bool_encoded = Boolean(False).encode()
3944 obj.decode(bool_encoded)
3945 with self.assertRaises(TagMismatch):
3946 obj.decode(int_encoded)
3948 def test_tag_mismatch_underlying(self):
3949 class SeqOfBoolean(SequenceOf):
3952 class SeqOfInteger(SequenceOf):
3957 ("erste", SeqOfBoolean()),
3960 int_encoded = SeqOfInteger((Integer(123),)).encode()
3961 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
3963 obj.decode(bool_encoded)
3964 with self.assertRaises(TagMismatch) as err:
3965 obj.decode(int_encoded)
3966 self.assertEqual(err.exception.decode_path, ("erste", "0"))
3970 def seq_values_strategy(draw, seq_klass, do_expl=False):
3972 if draw(booleans()):
3975 k: v for k, v in draw(dictionaries(
3978 booleans().map(Boolean),
3979 integers().map(Integer),
3984 if draw(booleans()):
3985 schema = list(draw(dictionaries(
3988 booleans().map(Boolean),
3989 integers().map(Integer),
3995 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3997 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3999 if draw(booleans()):
4000 default = seq_klass()
4002 k: v for k, v in draw(dictionaries(
4005 booleans().map(Boolean),
4006 integers().map(Integer),
4010 optional = draw(one_of(none(), booleans()))
4012 draw(integers(min_value=0)),
4013 draw(integers(min_value=0)),
4014 draw(integers(min_value=0)),
4016 return (value, schema, impl, expl, default, optional, _decoded)
4020 def sequence_strategy(draw, seq_klass):
4021 inputs = draw(lists(
4023 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4024 tuples(just(Integer), integers(), one_of(none(), integers())),
4029 integers(min_value=1),
4030 min_size=len(inputs),
4031 max_size=len(inputs),
4034 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4035 for tag, expled in zip(tags, draw(lists(
4037 min_size=len(inputs),
4038 max_size=len(inputs),
4042 for i, optional in enumerate(draw(lists(
4043 sampled_from(("required", "optional", "empty")),
4044 min_size=len(inputs),
4045 max_size=len(inputs),
4047 if optional in ("optional", "empty"):
4048 inits[i]["optional"] = True
4049 if optional == "empty":
4051 empties = set(empties)
4052 names = list(draw(sets(
4054 min_size=len(inputs),
4055 max_size=len(inputs),
4058 for i, (klass, value, default) in enumerate(inputs):
4059 schema.append((names[i], klass(default=default, **inits[i])))
4060 seq_name = draw(text_letters())
4061 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4064 for i, (klass, value, default) in enumerate(inputs):
4071 "default_value": None if spec.default is None else default,
4075 expect["optional"] = True
4077 expect["presented"] = True
4078 expect["value"] = value
4080 expect["optional"] = True
4081 if default is not None and default == value:
4082 expect["presented"] = False
4083 seq[name] = klass(value)
4084 expects.append(expect)
4089 def sequences_strategy(draw, seq_klass):
4090 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4092 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4093 for tag, expled in zip(tags, draw(lists(
4100 i for i, is_default in enumerate(draw(lists(
4106 names = list(draw(sets(
4111 seq_expectses = draw(lists(
4112 sequence_strategy(seq_klass=seq_klass),
4116 seqs = [seq for seq, _ in seq_expectses]
4118 for i, (name, seq) in enumerate(zip(names, seqs)):
4121 seq(default=(seq if i in defaulted else None), **inits[i]),
4123 seq_name = draw(text_letters())
4124 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4127 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4130 "expects": expects_inner,
4133 seq_outer[name] = seq_inner
4134 if seq_outer.specs[name].default is None:
4135 expect["presented"] = True
4136 expect_outers.append(expect)
4137 return seq_outer, expect_outers
4140 class SeqMixing(object):
4141 def test_invalid_value_type(self):
4142 with self.assertRaises(InvalidValueType) as err:
4143 self.base_klass(123)
4146 def test_invalid_value_type_set(self):
4147 class Seq(self.base_klass):
4148 schema = (("whatever", Boolean()),)
4150 with self.assertRaises(InvalidValueType) as err:
4151 seq["whatever"] = Integer(123)
4155 def test_optional(self, optional):
4156 obj = self.base_klass(default=self.base_klass(), optional=optional)
4157 self.assertTrue(obj.optional)
4159 @given(data_strategy())
4160 def test_ready(self, d):
4162 str(i): v for i, v in enumerate(d.draw(lists(
4169 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4176 for name in d.draw(permutations(
4177 list(ready.keys()) + list(non_ready.keys()),
4179 schema_input.append((name, Boolean()))
4181 class Seq(self.base_klass):
4182 schema = tuple(schema_input)
4184 for name in ready.keys():
4186 seq[name] = Boolean()
4187 self.assertFalse(seq.ready)
4190 for name, value in ready.items():
4191 seq[name] = Boolean(value)
4192 self.assertFalse(seq.ready)
4195 with self.assertRaises(ObjNotReady) as err:
4198 for name, value in non_ready.items():
4199 seq[name] = Boolean(value)
4200 self.assertTrue(seq.ready)
4204 @given(data_strategy())
4205 def test_call(self, d):
4206 class SeqInherited(self.base_klass):
4208 for klass in (self.base_klass, SeqInherited):
4217 ) = d.draw(seq_values_strategy(seq_klass=klass))
4218 obj_initial = klass(
4224 optional_initial or False,
4235 ) = d.draw(seq_values_strategy(
4237 do_expl=impl_initial is None,
4239 obj = obj_initial(value, impl, expl, default, optional)
4240 value_expected = default if value is None else value
4242 default_initial if value_expected is None
4245 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4246 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4247 self.assertEqual(obj.expl_tag, expl or expl_initial)
4249 {} if obj.default is None else obj.default._value,
4250 getattr(default_initial if default is None else default, "_value", {}),
4252 if obj.default is None:
4253 optional = optional_initial if optional is None else optional
4254 optional = False if optional is None else optional
4257 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4258 self.assertEqual(obj.optional, optional)
4260 @given(data_strategy())
4261 def test_copy(self, d):
4262 class SeqInherited(self.base_klass):
4264 for klass in (self.base_klass, SeqInherited):
4265 values = d.draw(seq_values_strategy(seq_klass=klass))
4266 obj = klass(*values)
4267 obj_copied = obj.copy()
4268 self.assert_copied_basic_fields(obj, obj_copied)
4269 self.assertEqual(obj.specs, obj_copied.specs)
4270 self.assertEqual(obj._value, obj_copied._value)
4272 @given(data_strategy())
4273 def test_stripped(self, d):
4274 value = d.draw(integers())
4275 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4277 class Seq(self.base_klass):
4279 schema = (("whatever", Integer()),)
4281 seq["whatever"] = Integer(value)
4282 with self.assertRaises(NotEnoughData):
4283 seq.decode(seq.encode()[:-1])
4285 @given(data_strategy())
4286 def test_stripped_expl(self, d):
4287 value = d.draw(integers())
4288 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4290 class Seq(self.base_klass):
4292 schema = (("whatever", Integer()),)
4294 seq["whatever"] = Integer(value)
4295 with self.assertRaises(NotEnoughData):
4296 seq.decode(seq.encode()[:-1])
4298 @given(binary(min_size=2))
4299 def test_non_tag_mismatch_raised(self, junk):
4301 _, _, len_encoded = tag_strip(memoryview(junk))
4302 len_decode(len_encoded)
4308 class Seq(self.base_klass):
4310 ("whatever", Integer()),
4312 ("whenever", Integer()),
4315 seq["whatever"] = Integer(123)
4316 seq["junk"] = Any(junk)
4317 seq["whenever"] = Integer(123)
4318 with self.assertRaises(DecodeError):
4319 seq.decode(seq.encode())
4322 integers(min_value=31),
4323 integers(min_value=0),
4326 def test_bad_tag(self, tag, offset, decode_path):
4327 decode_path = tuple(str(i) for i in decode_path)
4328 with self.assertRaises(DecodeError) as err:
4329 self.base_klass().decode(
4330 tag_encode(tag)[:-1],
4332 decode_path=decode_path,
4335 self.assertEqual(err.exception.offset, offset)
4336 self.assertEqual(err.exception.decode_path, decode_path)
4339 integers(min_value=128),
4340 integers(min_value=0),
4343 def test_bad_len(self, l, offset, decode_path):
4344 decode_path = tuple(str(i) for i in decode_path)
4345 with self.assertRaises(DecodeError) as err:
4346 self.base_klass().decode(
4347 self.base_klass.tag_default + len_encode(l)[:-1],
4349 decode_path=decode_path,
4352 self.assertEqual(err.exception.offset, offset)
4353 self.assertEqual(err.exception.decode_path, decode_path)
4355 def _assert_expects(self, seq, expects):
4356 for expect in expects:
4358 seq.specs[expect["name"]].optional,
4361 if expect["default_value"] is not None:
4363 seq.specs[expect["name"]].default,
4364 expect["default_value"],
4366 if expect["presented"]:
4367 self.assertIn(expect["name"], seq)
4368 self.assertEqual(seq[expect["name"]], expect["value"])
4370 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4371 @given(data_strategy())
4372 def test_symmetric(self, d):
4373 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4374 tail_junk = d.draw(binary(max_size=5))
4375 self.assertTrue(seq.ready)
4376 self.assertFalse(seq.decoded)
4377 self._assert_expects(seq, expects)
4380 seq_encoded = seq.encode()
4381 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4382 self.assertEqual(tail, tail_junk)
4383 self.assertTrue(seq.ready)
4384 self._assert_expects(seq_decoded, expects)
4385 self.assertEqual(seq, seq_decoded)
4386 self.assertEqual(seq_decoded.encode(), seq_encoded)
4387 for expect in expects:
4388 if not expect["presented"]:
4389 self.assertNotIn(expect["name"], seq_decoded)
4391 self.assertIn(expect["name"], seq_decoded)
4392 obj = seq_decoded[expect["name"]]
4393 self.assertTrue(obj.decoded)
4394 offset = obj.expl_offset if obj.expled else obj.offset
4395 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4396 self.assertSequenceEqual(
4397 seq_encoded[offset:offset + tlvlen],
4401 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4402 @given(data_strategy())
4403 def test_symmetric_with_seq(self, d):
4404 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4405 self.assertTrue(seq.ready)
4406 seq_encoded = seq.encode()
4407 seq_decoded, tail = seq.decode(seq_encoded)
4408 self.assertEqual(tail, b"")
4409 self.assertTrue(seq.ready)
4410 self.assertEqual(seq, seq_decoded)
4411 self.assertEqual(seq_decoded.encode(), seq_encoded)
4412 for expect_outer in expect_outers:
4413 if not expect_outer["presented"]:
4414 self.assertNotIn(expect_outer["name"], seq_decoded)
4416 self.assertIn(expect_outer["name"], seq_decoded)
4417 obj = seq_decoded[expect_outer["name"]]
4418 self.assertTrue(obj.decoded)
4419 offset = obj.expl_offset if obj.expled else obj.offset
4420 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4421 self.assertSequenceEqual(
4422 seq_encoded[offset:offset + tlvlen],
4425 self._assert_expects(obj, expect_outer["expects"])
4427 @given(data_strategy())
4428 def test_default_disappears(self, d):
4429 _schema = list(d.draw(dictionaries(
4431 sets(integers(), min_size=2, max_size=2),
4435 class Seq(self.base_klass):
4437 (n, Integer(default=d))
4438 for n, (_, d) in _schema
4441 for name, (value, _) in _schema:
4442 seq[name] = Integer(value)
4443 self.assertEqual(len(seq._value), len(_schema))
4444 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4445 self.assertGreater(len(seq.encode()), len(empty_seq))
4446 for name, (_, default) in _schema:
4447 seq[name] = Integer(default)
4448 self.assertEqual(len(seq._value), 0)
4449 self.assertSequenceEqual(seq.encode(), empty_seq)
4451 @given(data_strategy())
4452 def test_encoded_default_accepted(self, d):
4453 _schema = list(d.draw(dictionaries(
4458 tags = [tag_encode(tag) for tag in d.draw(sets(
4459 integers(min_value=0),
4460 min_size=len(_schema),
4461 max_size=len(_schema),
4464 class SeqWithoutDefault(self.base_klass):
4466 (n, Integer(impl=t))
4467 for (n, _), t in zip(_schema, tags)
4469 seq_without_default = SeqWithoutDefault()
4470 for name, value in _schema:
4471 seq_without_default[name] = Integer(value)
4472 seq_encoded = seq_without_default.encode()
4474 class SeqWithDefault(self.base_klass):
4476 (n, Integer(default=v, impl=t))
4477 for (n, v), t in zip(_schema, tags)
4479 seq_with_default = SeqWithDefault()
4480 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4481 for name, value in _schema:
4482 self.assertEqual(seq_decoded[name], seq_with_default[name])
4483 self.assertEqual(seq_decoded[name], value)
4485 @given(data_strategy())
4486 def test_missing_from_spec(self, d):
4487 names = list(d.draw(sets(text_letters(), min_size=2)))
4488 tags = [tag_encode(tag) for tag in d.draw(sets(
4489 integers(min_value=0),
4490 min_size=len(names),
4491 max_size=len(names),
4493 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4495 class SeqFull(self.base_klass):
4496 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4497 seq_full = SeqFull()
4498 for i, name in enumerate(names):
4499 seq_full[name] = Integer(i)
4500 seq_encoded = seq_full.encode()
4501 altered = names_tags[:-2] + names_tags[-1:]
4503 class SeqMissing(self.base_klass):
4504 schema = [(n, Integer(impl=t)) for n, t in altered]
4505 seq_missing = SeqMissing()
4506 with self.assertRaises(TagMismatch):
4507 seq_missing.decode(seq_encoded)
4510 class TestSequence(SeqMixing, CommonMixin, TestCase):
4511 base_klass = Sequence
4517 def test_remaining(self, value, junk):
4518 class Seq(Sequence):
4520 ("whatever", Integer()),
4522 int_encoded = Integer(value).encode()
4524 Sequence.tag_default,
4525 len_encode(len(int_encoded + junk)),
4528 with assertRaisesRegex(self, DecodeError, "remaining"):
4529 Seq().decode(junked)
4531 @given(sets(text_letters(), min_size=2))
4532 def test_obj_unknown(self, names):
4533 missing = names.pop()
4535 class Seq(Sequence):
4536 schema = [(n, Boolean()) for n in names]
4538 with self.assertRaises(ObjUnknown) as err:
4541 with self.assertRaises(ObjUnknown) as err:
4542 seq[missing] = Boolean()
4545 def test_x690_vector(self):
4546 class Seq(Sequence):
4548 ("name", IA5String()),
4551 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4552 self.assertEqual(seq["name"], "Smith")
4553 self.assertEqual(seq["ok"], True)
4556 class TestSet(SeqMixing, CommonMixin, TestCase):
4559 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4560 @given(data_strategy())
4561 def test_sorted(self, d):
4563 tag_encode(tag) for tag in
4564 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4568 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4570 for name, _ in Seq.schema:
4571 seq[name] = OctetString(b"")
4572 seq_encoded = seq.encode()
4573 seq_decoded, _ = seq.decode(seq_encoded)
4574 self.assertSequenceEqual(
4575 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4576 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4581 def seqof_values_strategy(draw, schema=None, do_expl=False):
4583 schema = draw(sampled_from((Boolean(), Integer())))
4584 bound_min, bound_max = sorted(draw(sets(
4585 integers(min_value=0, max_value=10),
4589 if isinstance(schema, Boolean):
4590 values_generator = booleans().map(Boolean)
4591 elif isinstance(schema, Integer):
4592 values_generator = integers().map(Integer)
4593 values_generator = lists(
4598 values = draw(one_of(none(), values_generator))
4602 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4604 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4605 default = draw(one_of(none(), values_generator))
4606 optional = draw(one_of(none(), booleans()))
4608 draw(integers(min_value=0)),
4609 draw(integers(min_value=0)),
4610 draw(integers(min_value=0)),
4615 (bound_min, bound_max),
4624 class SeqOfMixing(object):
4625 def test_invalid_value_type(self):
4626 with self.assertRaises(InvalidValueType) as err:
4627 self.base_klass(123)
4630 def test_invalid_values_type(self):
4631 class SeqOf(self.base_klass):
4633 with self.assertRaises(InvalidValueType) as err:
4634 SeqOf([Integer(123), Boolean(False), Integer(234)])
4637 def test_schema_required(self):
4638 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4639 self.base_klass.__mro__[1]()
4641 @given(booleans(), booleans(), binary(), binary())
4642 def test_comparison(self, value1, value2, tag1, tag2):
4643 class SeqOf(self.base_klass):
4645 obj1 = SeqOf([Boolean(value1)])
4646 obj2 = SeqOf([Boolean(value2)])
4647 self.assertEqual(obj1 == obj2, value1 == value2)
4648 self.assertEqual(obj1 != obj2, value1 != value2)
4649 self.assertEqual(obj1 == list(obj2), value1 == value2)
4650 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4651 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4652 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4653 self.assertEqual(obj1 == obj2, tag1 == tag2)
4654 self.assertEqual(obj1 != obj2, tag1 != tag2)
4656 @given(lists(booleans()))
4657 def test_iter(self, values):
4658 class SeqOf(self.base_klass):
4660 obj = SeqOf([Boolean(value) for value in values])
4661 self.assertEqual(len(obj), len(values))
4662 for i, value in enumerate(obj):
4663 self.assertEqual(value, values[i])
4665 @given(data_strategy())
4666 def test_ready(self, d):
4667 ready = [Integer(v) for v in d.draw(lists(
4674 range(d.draw(integers(min_value=1, max_value=5)))
4677 class SeqOf(self.base_klass):
4679 values = d.draw(permutations(ready + non_ready))
4681 for value in values:
4683 self.assertFalse(seqof.ready)
4686 with self.assertRaises(ObjNotReady) as err:
4689 for i, value in enumerate(values):
4690 self.assertEqual(seqof[i], value)
4691 if not seqof[i].ready:
4692 seqof[i] = Integer(i)
4693 self.assertTrue(seqof.ready)
4697 def test_spec_mismatch(self):
4698 class SeqOf(self.base_klass):
4701 seqof.append(Integer(123))
4702 with self.assertRaises(ValueError):
4703 seqof.append(Boolean(False))
4704 with self.assertRaises(ValueError):
4705 seqof[0] = Boolean(False)
4707 @given(data_strategy())
4708 def test_bounds_satisfied(self, d):
4709 class SeqOf(self.base_klass):
4711 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4712 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4713 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4714 SeqOf(value=value, bounds=(bound_min, bound_max))
4716 @given(data_strategy())
4717 def test_bounds_unsatisfied(self, d):
4718 class SeqOf(self.base_klass):
4720 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4721 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4722 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4723 with self.assertRaises(BoundsError) as err:
4724 SeqOf(value=value, bounds=(bound_min, bound_max))
4726 value = [Boolean()] * d.draw(integers(
4727 min_value=bound_max + 1,
4728 max_value=bound_max + 10,
4730 with self.assertRaises(BoundsError) as err:
4731 SeqOf(value=value, bounds=(bound_min, bound_max))
4734 @given(integers(min_value=1, max_value=10))
4735 def test_out_of_bounds(self, bound_max):
4736 class SeqOf(self.base_klass):
4738 bounds = (0, bound_max)
4740 for _ in range(bound_max):
4741 seqof.append(Integer(123))
4742 with self.assertRaises(BoundsError):
4743 seqof.append(Integer(123))
4745 @given(data_strategy())
4746 def test_call(self, d):
4756 ) = d.draw(seqof_values_strategy())
4758 class SeqOf(self.base_klass):
4759 schema = schema_initial
4760 obj_initial = SeqOf(
4761 value=value_initial,
4762 bounds=bounds_initial,
4765 default=default_initial,
4766 optional=optional_initial or False,
4767 _decoded=_decoded_initial,
4778 ) = d.draw(seqof_values_strategy(
4779 schema=schema_initial,
4780 do_expl=impl_initial is None,
4782 if (default is None) and (obj_initial.default is not None):
4785 (bounds is None) and
4786 (value is not None) and
4787 (bounds_initial is not None) and
4788 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4792 (bounds is None) and
4793 (default is not None) and
4794 (bounds_initial is not None) and
4795 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4807 value_expected = default if value is None else value
4809 default_initial if value_expected is None
4812 value_expected = () if value_expected is None else value_expected
4813 self.assertEqual(obj, value_expected)
4814 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4815 self.assertEqual(obj.expl_tag, expl or expl_initial)
4818 default_initial if default is None else default,
4820 if obj.default is None:
4821 optional = optional_initial if optional is None else optional
4822 optional = False if optional is None else optional
4825 self.assertEqual(obj.optional, optional)
4827 (obj._bound_min, obj._bound_max),
4828 bounds or bounds_initial or (0, float("+inf")),
4831 @given(seqof_values_strategy())
4832 def test_copy(self, values):
4833 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4835 class SeqOf(self.base_klass):
4843 optional=optional or False,
4846 obj_copied = obj.copy()
4847 self.assert_copied_basic_fields(obj, obj_copied)
4848 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4849 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4850 self.assertEqual(obj._value, obj_copied._value)
4854 integers(min_value=1).map(tag_encode),
4856 def test_stripped(self, values, tag_impl):
4857 class SeqOf(self.base_klass):
4858 schema = OctetString()
4859 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4860 with self.assertRaises(NotEnoughData):
4861 obj.decode(obj.encode()[:-1])
4865 integers(min_value=1).map(tag_ctxc),
4867 def test_stripped_expl(self, values, tag_expl):
4868 class SeqOf(self.base_klass):
4869 schema = OctetString()
4870 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4871 with self.assertRaises(NotEnoughData):
4872 obj.decode(obj.encode()[:-1])
4875 integers(min_value=31),
4876 integers(min_value=0),
4879 def test_bad_tag(self, tag, offset, decode_path):
4880 decode_path = tuple(str(i) for i in decode_path)
4881 with self.assertRaises(DecodeError) as err:
4882 self.base_klass().decode(
4883 tag_encode(tag)[:-1],
4885 decode_path=decode_path,
4888 self.assertEqual(err.exception.offset, offset)
4889 self.assertEqual(err.exception.decode_path, decode_path)
4892 integers(min_value=128),
4893 integers(min_value=0),
4896 def test_bad_len(self, l, offset, decode_path):
4897 decode_path = tuple(str(i) for i in decode_path)
4898 with self.assertRaises(DecodeError) as err:
4899 self.base_klass().decode(
4900 self.base_klass.tag_default + len_encode(l)[:-1],
4902 decode_path=decode_path,
4905 self.assertEqual(err.exception.offset, offset)
4906 self.assertEqual(err.exception.decode_path, decode_path)
4908 @given(binary(min_size=1))
4909 def test_tag_mismatch(self, impl):
4910 assume(impl != self.base_klass.tag_default)
4911 with self.assertRaises(TagMismatch):
4912 self.base_klass(impl=impl).decode(self.base_klass().encode())
4914 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4916 seqof_values_strategy(schema=Integer()),
4917 lists(integers().map(Integer)),
4918 integers(min_value=1).map(tag_ctxc),
4919 integers(min_value=0),
4922 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4923 _, _, _, _, _, default, optional, _decoded = values
4925 class SeqOf(self.base_klass):
4935 self.assertFalse(obj.expled)
4936 obj_encoded = obj.encode()
4937 obj_expled = obj(value, expl=tag_expl)
4938 self.assertTrue(obj_expled.expled)
4941 obj_expled_encoded = obj_expled.encode()
4942 obj_decoded, tail = obj_expled.decode(
4943 obj_expled_encoded + tail_junk,
4948 self.assertEqual(tail, tail_junk)
4949 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
4950 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4951 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4952 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4954 obj_decoded.expl_llen,
4955 len(len_encode(len(obj_encoded))),
4957 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4958 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4961 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4963 self.assertEqual(obj_decoded.expl_offset, offset)
4964 for obj_inner in obj_decoded:
4965 self.assertIn(obj_inner, obj_decoded)
4966 self.assertSequenceEqual(
4969 obj_inner.offset - offset:
4970 obj_inner.offset + obj_inner.tlvlen - offset
4975 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
4976 class SeqOf(SequenceOf):
4980 def _test_symmetric_compare_objs(self, obj1, obj2):
4981 self.assertEqual(obj1, obj2)
4982 self.assertSequenceEqual(list(obj1), list(obj2))
4985 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
4990 def _test_symmetric_compare_objs(self, obj1, obj2):
4991 self.assertSetEqual(
4992 set(int(v) for v in obj1),
4993 set(int(v) for v in obj2),
4996 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4997 @given(data_strategy())
4998 def test_sorted(self, d):
4999 values = [OctetString(v) for v in d.draw(lists(binary()))]
5002 schema = OctetString()
5004 seq_encoded = seq.encode()
5005 seq_decoded, _ = seq.decode(seq_encoded)
5006 self.assertSequenceEqual(
5007 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5008 b"".join(sorted([v.encode() for v in values])),
5012 class TestGoMarshalVectors(TestCase):
5014 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5015 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5016 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5017 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5018 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5020 class Seq(Sequence):
5022 ("erste", Integer()),
5023 ("zweite", Integer(optional=True))
5026 seq["erste"] = Integer(64)
5027 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5028 seq["erste"] = Integer(0x123456)
5029 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5030 seq["erste"] = Integer(64)
5031 seq["zweite"] = Integer(65)
5032 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5034 class NestedSeq(Sequence):
5038 seq["erste"] = Integer(127)
5039 seq["zweite"] = None
5040 nested = NestedSeq()
5041 nested["nest"] = seq
5042 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5044 self.assertSequenceEqual(
5045 OctetString(b"\x01\x02\x03").encode(),
5046 hexdec("0403010203"),
5049 class Seq(Sequence):
5051 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5054 seq["erste"] = Integer(64)
5055 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5057 class Seq(Sequence):
5059 ("erste", Integer(expl=tag_ctxc(5))),
5062 seq["erste"] = Integer(64)
5063 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5065 class Seq(Sequence):
5068 impl=tag_encode(0, klass=TagClassContext),
5073 seq["erste"] = Null()
5074 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5076 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5078 self.assertSequenceEqual(
5079 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5080 hexdec("170d3730303130313030303030305a"),
5082 self.assertSequenceEqual(
5083 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5084 hexdec("170d3039313131353232353631365a"),
5086 self.assertSequenceEqual(
5087 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5088 hexdec("180f32313030303430353132303130315a"),
5091 class Seq(Sequence):
5093 ("erste", GeneralizedTime()),
5096 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5097 self.assertSequenceEqual(
5099 hexdec("3011180f32303039313131353232353631365a"),
5102 self.assertSequenceEqual(
5103 BitString((1, b"\x80")).encode(),
5106 self.assertSequenceEqual(
5107 BitString((12, b"\x81\xF0")).encode(),
5108 hexdec("03030481f0"),
5111 self.assertSequenceEqual(
5112 ObjectIdentifier("1.2.3.4").encode(),
5113 hexdec("06032a0304"),
5115 self.assertSequenceEqual(
5116 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5117 hexdec("06092a864888932d010105"),
5119 self.assertSequenceEqual(
5120 ObjectIdentifier("2.100.3").encode(),
5121 hexdec("0603813403"),
5124 self.assertSequenceEqual(
5125 PrintableString("test").encode(),
5126 hexdec("130474657374"),
5128 self.assertSequenceEqual(
5129 PrintableString("x" * 127).encode(),
5130 hexdec("137F" + "78" * 127),
5132 self.assertSequenceEqual(
5133 PrintableString("x" * 128).encode(),
5134 hexdec("138180" + "78" * 128),
5136 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5138 class Seq(Sequence):
5140 ("erste", IA5String()),
5143 seq["erste"] = IA5String("test")
5144 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5146 class Seq(Sequence):
5148 ("erste", PrintableString()),
5151 seq["erste"] = PrintableString("test")
5152 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5153 seq["erste"] = PrintableString("test*")
5154 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5156 class Seq(Sequence):
5158 ("erste", Any(optional=True)),
5159 ("zweite", Integer()),
5162 seq["zweite"] = Integer(64)
5163 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5168 seq.append(Integer(10))
5169 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5171 class _SeqOf(SequenceOf):
5172 schema = PrintableString()
5174 class SeqOf(SequenceOf):
5177 _seqof.append(PrintableString("1"))
5179 seqof.append(_seqof)
5180 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5182 class Seq(Sequence):
5184 ("erste", Integer(default=1)),
5187 seq["erste"] = Integer(0)
5188 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5189 seq["erste"] = Integer(1)
5190 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5191 seq["erste"] = Integer(2)
5192 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5195 class TestPP(TestCase):
5196 @given(data_strategy())
5197 def test_oid_printing(self, d):
5199 str(ObjectIdentifier(k)): v * 2
5200 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5202 chosen = d.draw(sampled_from(sorted(oids)))
5203 chosen_id = oids[chosen]
5204 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5205 self.assertNotIn(chosen_id, pp_console_row(pp))
5206 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5209 class TestAutoAddSlots(TestCase):
5211 class Inher(Integer):
5214 with self.assertRaises(AttributeError):
5216 inher.unexistent = "whatever"
5219 class TestOIDDefines(TestCase):
5220 @given(data_strategy())
5221 def runTest(self, d):
5222 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5223 value_name_chosen = d.draw(sampled_from(value_names))
5225 ObjectIdentifier(oid)
5226 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5228 oid_chosen = d.draw(sampled_from(oids))
5229 values = d.draw(lists(
5231 min_size=len(value_names),
5232 max_size=len(value_names),
5235 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5236 oid: Integer() for oid in oids[:-1]
5239 for i, value_name in enumerate(value_names):
5240 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5242 class Seq(Sequence):
5245 for value_name, value in zip(value_names, values):
5246 seq[value_name] = Any(Integer(value).encode())
5247 seq["type"] = oid_chosen
5248 seq, _ = Seq().decode(seq.encode())
5249 for value_name in value_names:
5250 if value_name == value_name_chosen:
5252 self.assertIsNone(seq[value_name].defined)
5253 if value_name_chosen in oids[:-1]:
5254 self.assertIsNotNone(seq[value_name_chosen].defined)
5255 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5256 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5259 class TestDefinesByPath(TestCase):
5260 def test_generated(self):
5261 class Seq(Sequence):
5263 ("type", ObjectIdentifier()),
5264 ("value", OctetString(expl=tag_ctxc(123))),
5267 class SeqInner(Sequence):
5269 ("typeInner", ObjectIdentifier()),
5270 ("valueInner", Any()),
5273 class PairValue(SetOf):
5276 class Pair(Sequence):
5278 ("type", ObjectIdentifier()),
5279 ("value", PairValue()),
5282 class Pairs(SequenceOf):
5289 type_octet_stringed,
5291 ObjectIdentifier(oid)
5292 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5294 seq_integered = Seq()
5295 seq_integered["type"] = type_integered
5296 seq_integered["value"] = OctetString(Integer(123).encode())
5297 seq_integered_raw = seq_integered.encode()
5301 (type_octet_stringed, OctetString(b"whatever")),
5302 (type_integered, Integer(123)),
5303 (type_octet_stringed, OctetString(b"whenever")),
5304 (type_integered, Integer(234)),
5306 for t, v in pairs_input:
5309 pair["value"] = PairValue((Any(v),))
5311 seq_inner = SeqInner()
5312 seq_inner["typeInner"] = type_innered
5313 seq_inner["valueInner"] = Any(pairs)
5314 seq_sequenced = Seq()
5315 seq_sequenced["type"] = type_sequenced
5316 seq_sequenced["value"] = OctetString(seq_inner.encode())
5317 seq_sequenced_raw = seq_sequenced.encode()
5319 defines_by_path = []
5320 seq_integered, _ = Seq().decode(seq_integered_raw)
5321 self.assertIsNone(seq_integered["value"].defined)
5322 defines_by_path.append(
5323 (("type",), ((("value",), {
5324 type_integered: Integer(),
5325 type_sequenced: SeqInner(),
5328 seq_integered, _ = Seq().decode(
5330 ctx={"defines_by_path": defines_by_path},
5332 self.assertIsNotNone(seq_integered["value"].defined)
5333 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5334 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5335 self.assertTrue(seq_integered_raw[
5336 seq_integered["value"].defined[1].offset:
5337 ].startswith(Integer(123).encode()))
5339 seq_sequenced, _ = Seq().decode(
5341 ctx={"defines_by_path": defines_by_path},
5343 self.assertIsNotNone(seq_sequenced["value"].defined)
5344 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5345 seq_inner = seq_sequenced["value"].defined[1]
5346 self.assertIsNone(seq_inner["valueInner"].defined)
5348 defines_by_path.append((
5349 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5350 ((("valueInner",), {type_innered: Pairs()}),),
5352 seq_sequenced, _ = Seq().decode(
5354 ctx={"defines_by_path": defines_by_path},
5356 self.assertIsNotNone(seq_sequenced["value"].defined)
5357 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5358 seq_inner = seq_sequenced["value"].defined[1]
5359 self.assertIsNotNone(seq_inner["valueInner"].defined)
5360 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5361 pairs = seq_inner["valueInner"].defined[1]
5363 self.assertIsNone(pair["value"][0].defined)
5365 defines_by_path.append((
5368 DecodePathDefBy(type_sequenced),
5370 DecodePathDefBy(type_innered),
5375 type_integered: Integer(),
5376 type_octet_stringed: OctetString(),
5379 seq_sequenced, _ = Seq().decode(
5381 ctx={"defines_by_path": defines_by_path},
5383 self.assertIsNotNone(seq_sequenced["value"].defined)
5384 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5385 seq_inner = seq_sequenced["value"].defined[1]
5386 self.assertIsNotNone(seq_inner["valueInner"].defined)
5387 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5388 pairs_got = seq_inner["valueInner"].defined[1]
5389 for pair_input, pair_got in zip(pairs_input, pairs_got):
5390 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5391 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5393 @given(oid_strategy(), integers())
5394 def test_simple(self, oid, tgt):
5395 class Inner(Sequence):
5397 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5398 ObjectIdentifier(oid): Integer(),
5402 class Outer(Sequence):
5405 ("tgt", OctetString()),
5409 inner["oid"] = ObjectIdentifier(oid)
5411 outer["inner"] = inner
5412 outer["tgt"] = OctetString(Integer(tgt).encode())
5413 decoded, _ = Outer().decode(outer.encode())
5414 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5417 class TestAbsDecodePath(TestCase):
5419 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5420 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5422 def test_concat(self, decode_path, rel_path):
5423 self.assertSequenceEqual(
5424 abs_decode_path(decode_path, rel_path),
5425 decode_path + rel_path,
5429 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5430 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5432 def test_abs(self, decode_path, rel_path):
5433 self.assertSequenceEqual(
5434 abs_decode_path(decode_path, ("/",) + rel_path),
5439 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5440 integers(min_value=1, max_value=3),
5441 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5443 def test_dots(self, decode_path, number_of_dots, rel_path):
5444 self.assertSequenceEqual(
5445 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5446 decode_path[:-number_of_dots] + rel_path,
5450 class TestStrictDefaultExistence(TestCase):
5451 @given(data_strategy())
5452 def runTest(self, d):
5453 count = d.draw(integers(min_value=1, max_value=10))
5454 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5456 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5457 for i in range(count)
5460 class Seq(Sequence):
5463 for i in range(count):
5464 seq["int%d" % i] = Integer(123)
5466 chosen = "int%d" % chosen
5467 seq.specs[chosen] = seq.specs[chosen](default=123)
5469 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5470 seq.decode(raw, ctx={"strict_default_existence": True})
5473 class TestX690PrefixedType(TestCase):
5475 self.assertSequenceEqual(
5476 VisibleString("Jones").encode(),
5477 hexdec("1A054A6F6E6573"),
5479 self.assertSequenceEqual(
5482 impl=tag_encode(3, klass=TagClassApplication),
5484 hexdec("43054A6F6E6573"),
5486 self.assertSequenceEqual(
5490 impl=tag_encode(3, klass=TagClassApplication),
5494 hexdec("A20743054A6F6E6573"),
5496 self.assertSequenceEqual(
5500 impl=tag_encode(3, klass=TagClassApplication),
5502 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5504 hexdec("670743054A6F6E6573"),
5506 self.assertSequenceEqual(
5507 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5508 hexdec("82054A6F6E6573"),