2 # PyDERASN -- Python ASN.1 DER codec with abstract structures
3 # Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from datetime import datetime
20 from string import ascii_letters
21 from string import digits
22 from string import printable
23 from string import whitespace
24 from unittest import TestCase
26 from hypothesis import assume
27 from hypothesis import given
28 from hypothesis import settings
29 from hypothesis.strategies import binary
30 from hypothesis.strategies import booleans
31 from hypothesis.strategies import composite
32 from hypothesis.strategies import data as data_strategy
33 from hypothesis.strategies import datetimes
34 from hypothesis.strategies import dictionaries
35 from hypothesis.strategies import integers
36 from hypothesis.strategies import just
37 from hypothesis.strategies import lists
38 from hypothesis.strategies import none
39 from hypothesis.strategies import one_of
40 from hypothesis.strategies import permutations
41 from hypothesis.strategies import sampled_from
42 from hypothesis.strategies import sets
43 from hypothesis.strategies import text
44 from hypothesis.strategies import tuples
45 from six import assertRaisesRegex
46 from six import binary_type
47 from six import byte2int
48 from six import indexbytes
49 from six import int2byte
50 from six import iterbytes
52 from six import text_type
53 from six import unichr as six_unichr
55 from pyderasn import _pp
56 from pyderasn import abs_decode_path
57 from pyderasn import Any
58 from pyderasn import BitString
59 from pyderasn import BMPString
60 from pyderasn import Boolean
61 from pyderasn import BoundsError
62 from pyderasn import Choice
63 from pyderasn import DecodeError
64 from pyderasn import DecodePathDefBy
65 from pyderasn import Enumerated
66 from pyderasn import EOC
67 from pyderasn import EOC_LEN
68 from pyderasn import GeneralizedTime
69 from pyderasn import GeneralString
70 from pyderasn import GraphicString
71 from pyderasn import hexdec
72 from pyderasn import hexenc
73 from pyderasn import IA5String
74 from pyderasn import Integer
75 from pyderasn import InvalidLength
76 from pyderasn import InvalidOID
77 from pyderasn import InvalidValueType
78 from pyderasn import len_decode
79 from pyderasn import len_encode
80 from pyderasn import NotEnoughData
81 from pyderasn import Null
82 from pyderasn import NumericString
83 from pyderasn import ObjectIdentifier
84 from pyderasn import ObjNotReady
85 from pyderasn import ObjUnknown
86 from pyderasn import OctetString
87 from pyderasn import pp_console_row
88 from pyderasn import pprint
89 from pyderasn import PrintableString
90 from pyderasn import Sequence
91 from pyderasn import SequenceOf
92 from pyderasn import Set
93 from pyderasn import SetOf
94 from pyderasn import tag_ctxc
95 from pyderasn import tag_ctxp
96 from pyderasn import tag_decode
97 from pyderasn import tag_encode
98 from pyderasn import tag_strip
99 from pyderasn import TagClassApplication
100 from pyderasn import TagClassContext
101 from pyderasn import TagClassPrivate
102 from pyderasn import TagClassUniversal
103 from pyderasn import TagFormConstructed
104 from pyderasn import TagFormPrimitive
105 from pyderasn import TagMismatch
106 from pyderasn import TeletexString
107 from pyderasn import UniversalString
108 from pyderasn import UTCTime
109 from pyderasn import UTF8String
110 from pyderasn import VideotexString
111 from pyderasn import VisibleString
114 settings.register_profile("local", settings(
116 perform_health_check=False,
118 settings.load_profile("local")
119 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
121 tag_classes = sampled_from((
127 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
130 class TestHex(TestCase):
132 def test_symmetric(self, data):
133 self.assertEqual(hexdec(hexenc(data)), data)
136 class TestTagCoder(TestCase):
137 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
141 integers(min_value=0, max_value=30),
144 def test_short(self, klass, form, num, junk):
145 raw = tag_encode(klass=klass, form=form, num=num)
146 self.assertEqual(tag_decode(raw), (klass, form, num))
147 self.assertEqual(len(raw), 1)
149 byte2int(tag_encode(klass=klass, form=form, num=0)),
150 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
152 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
153 self.assertSequenceEqual(stripped.tobytes(), raw)
154 self.assertEqual(tlen, len(raw))
155 self.assertSequenceEqual(tail, junk)
157 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
161 integers(min_value=31),
164 def test_long(self, klass, form, num, junk):
165 raw = tag_encode(klass=klass, form=form, num=num)
166 self.assertEqual(tag_decode(raw), (klass, form, num))
167 self.assertGreater(len(raw), 1)
169 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
172 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
173 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
174 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
175 self.assertSequenceEqual(stripped.tobytes(), raw)
176 self.assertEqual(tlen, len(raw))
177 self.assertSequenceEqual(tail, junk)
179 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
180 @given(integers(min_value=31))
181 def test_unfinished_tag(self, num):
182 raw = bytearray(tag_encode(num=num))
183 for i in range(1, len(raw)):
185 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
186 tag_strip(bytes(raw))
188 def test_go_vectors_valid(self):
189 for data, (eklass, etag, elen, eform) in (
190 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
191 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
192 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
193 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
194 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
195 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
196 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
197 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
198 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
199 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
201 tag, _, len_encoded = tag_strip(memoryview(data))
202 klass, form, num = tag_decode(tag)
203 _len, _, tail = len_decode(len_encoded)
204 self.assertSequenceEqual(tail, b"")
205 self.assertEqual(klass, eklass)
206 self.assertEqual(num, etag)
207 self.assertEqual(_len, elen)
208 self.assertEqual(form, eform)
210 def test_go_vectors_invalid(self):
218 with self.assertRaises(DecodeError):
219 _, _, len_encoded = tag_strip(memoryview(data))
220 len_decode(len_encoded)
223 integers(min_value=0, max_value=127),
224 integers(min_value=0, max_value=2),
226 def test_long_instead_of_short(self, l, dummy_num):
227 octets = (b"\x00" * dummy_num) + int2byte(l)
228 octets = int2byte((dummy_num + 1) | 0x80) + octets
229 with self.assertRaises(DecodeError):
233 class TestLenCoder(TestCase):
234 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
236 integers(min_value=0, max_value=127),
239 def test_short(self, l, junk):
240 raw = len_encode(l) + junk
241 decoded, llen, tail = len_decode(memoryview(raw))
242 self.assertEqual(decoded, l)
243 self.assertEqual(llen, 1)
244 self.assertEqual(len(raw), 1 + len(junk))
245 self.assertEqual(tail.tobytes(), junk)
247 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
249 integers(min_value=128),
252 def test_long(self, l, junk):
253 raw = len_encode(l) + junk
254 decoded, llen, tail = len_decode(memoryview(raw))
255 self.assertEqual(decoded, l)
256 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
257 self.assertEqual(llen, len(raw) - len(junk))
258 self.assertNotEqual(indexbytes(raw, 1), 0)
259 self.assertSequenceEqual(tail.tobytes(), junk)
261 def test_empty(self):
262 with self.assertRaises(NotEnoughData):
265 @given(integers(min_value=128))
266 def test_stripped(self, _len):
267 with self.assertRaises(NotEnoughData):
268 len_decode(len_encode(_len)[:-1])
271 text_printable = text(alphabet=printable, min_size=1)
275 def text_letters(draw):
276 result = draw(text(alphabet=ascii_letters, min_size=1))
278 result = result.encode("ascii")
282 class CommonMixin(object):
283 def test_tag_default(self):
284 obj = self.base_klass()
285 self.assertEqual(obj.tag, obj.tag_default)
287 def test_simultaneous_impl_expl(self):
288 with self.assertRaises(ValueError):
289 self.base_klass(impl=b"whatever", expl=b"whenever")
291 @given(binary(min_size=1), integers(), integers(), integers())
292 def test_decoded(self, impl, offset, llen, vlen):
293 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
294 self.assertEqual(obj.offset, offset)
295 self.assertEqual(obj.llen, llen)
296 self.assertEqual(obj.vlen, vlen)
297 self.assertEqual(obj.tlen, len(impl))
298 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
300 @given(binary(min_size=1))
301 def test_impl_inherited(self, impl_tag):
302 class Inherited(self.base_klass):
305 self.assertSequenceEqual(obj.impl, impl_tag)
306 self.assertFalse(obj.expled)
309 def test_expl_inherited(self, expl_tag):
310 class Inherited(self.base_klass):
313 self.assertSequenceEqual(obj.expl, expl_tag)
314 self.assertTrue(obj.expled)
316 def assert_copied_basic_fields(self, obj, obj_copied):
317 self.assertEqual(obj, obj_copied)
318 self.assertSequenceEqual(obj.tag, obj_copied.tag)
319 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
320 self.assertEqual(obj.default, obj_copied.default)
321 self.assertEqual(obj.optional, obj_copied.optional)
322 self.assertEqual(obj.offset, obj_copied.offset)
323 self.assertEqual(obj.llen, obj_copied.llen)
324 self.assertEqual(obj.vlen, obj_copied.vlen)
328 def boolean_values_strategy(draw, do_expl=False):
329 value = draw(one_of(none(), booleans()))
333 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
335 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
336 default = draw(one_of(none(), booleans()))
337 optional = draw(one_of(none(), booleans()))
339 draw(integers(min_value=0)),
340 draw(integers(min_value=0)),
341 draw(integers(min_value=0)),
343 return (value, impl, expl, default, optional, _decoded)
346 class BooleanInherited(Boolean):
350 class TestBoolean(CommonMixin, TestCase):
353 def test_invalid_value_type(self):
354 with self.assertRaises(InvalidValueType) as err:
359 def test_optional(self, optional):
360 obj = Boolean(default=Boolean(False), optional=optional)
361 self.assertTrue(obj.optional)
364 def test_ready(self, value):
366 self.assertFalse(obj.ready)
369 with self.assertRaises(ObjNotReady) as err:
373 self.assertTrue(obj.ready)
377 @given(booleans(), booleans(), binary(), binary())
378 def test_comparison(self, value1, value2, tag1, tag2):
379 for klass in (Boolean, BooleanInherited):
382 self.assertEqual(obj1 == obj2, value1 == value2)
383 self.assertEqual(obj1 != obj2, value1 != value2)
384 self.assertEqual(obj1 == bool(obj2), value1 == value2)
385 obj1 = klass(value1, impl=tag1)
386 obj2 = klass(value1, impl=tag2)
387 self.assertEqual(obj1 == obj2, tag1 == tag2)
388 self.assertEqual(obj1 != obj2, tag1 != tag2)
390 @given(data_strategy())
391 def test_call(self, d):
392 for klass in (Boolean, BooleanInherited):
400 ) = d.draw(boolean_values_strategy())
406 optional_initial or False,
416 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
417 obj = obj_initial(value, impl, expl, default, optional)
419 value_expected = default if value is None else value
421 default_initial if value_expected is None
424 self.assertEqual(obj, value_expected)
425 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
426 self.assertEqual(obj.expl_tag, expl or expl_initial)
429 default_initial if default is None else default,
431 if obj.default is None:
432 optional = optional_initial if optional is None else optional
433 optional = False if optional is None else optional
436 self.assertEqual(obj.optional, optional)
438 @given(boolean_values_strategy())
439 def test_copy(self, values):
440 for klass in (Boolean, BooleanInherited):
442 obj_copied = obj.copy()
443 self.assert_copied_basic_fields(obj, obj_copied)
447 integers(min_value=1).map(tag_encode),
449 def test_stripped(self, value, tag_impl):
450 obj = Boolean(value, impl=tag_impl)
451 with self.assertRaises(NotEnoughData):
452 obj.decode(obj.encode()[:-1])
456 integers(min_value=1).map(tag_ctxc),
458 def test_stripped_expl(self, value, tag_expl):
459 obj = Boolean(value, expl=tag_expl)
460 with self.assertRaises(NotEnoughData):
461 obj.decode(obj.encode()[:-1])
464 integers(min_value=31),
465 integers(min_value=0),
468 def test_bad_tag(self, tag, offset, decode_path):
469 decode_path = tuple(str(i) for i in decode_path)
470 with self.assertRaises(DecodeError) as err:
472 tag_encode(tag)[:-1],
474 decode_path=decode_path,
477 self.assertEqual(err.exception.offset, offset)
478 self.assertEqual(err.exception.decode_path, decode_path)
481 integers(min_value=31),
482 integers(min_value=0),
485 def test_bad_expl_tag(self, tag, offset, decode_path):
486 decode_path = tuple(str(i) for i in decode_path)
487 with self.assertRaises(DecodeError) as err:
488 Boolean(expl=Boolean.tag_default).decode(
489 tag_encode(tag)[:-1],
491 decode_path=decode_path,
494 self.assertEqual(err.exception.offset, offset)
495 self.assertEqual(err.exception.decode_path, decode_path)
498 integers(min_value=128),
499 integers(min_value=0),
502 def test_bad_len(self, l, offset, decode_path):
503 decode_path = tuple(str(i) for i in decode_path)
504 with self.assertRaises(DecodeError) as err:
506 Boolean.tag_default + len_encode(l)[:-1],
508 decode_path=decode_path,
511 self.assertEqual(err.exception.offset, offset)
512 self.assertEqual(err.exception.decode_path, decode_path)
515 integers(min_value=128),
516 integers(min_value=0),
519 def test_bad_expl_len(self, l, offset, decode_path):
520 decode_path = tuple(str(i) for i in decode_path)
521 with self.assertRaises(DecodeError) as err:
522 Boolean(expl=Boolean.tag_default).decode(
523 Boolean.tag_default + len_encode(l)[:-1],
525 decode_path=decode_path,
528 self.assertEqual(err.exception.offset, offset)
529 self.assertEqual(err.exception.decode_path, decode_path)
531 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
533 boolean_values_strategy(),
535 integers(min_value=1).map(tag_ctxc),
536 integers(min_value=0),
539 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
540 for klass in (Boolean, BooleanInherited):
541 _, _, _, default, optional, _decoded = values
550 self.assertFalse(obj.expled)
551 obj_encoded = obj.encode()
552 obj_expled = obj(value, expl=tag_expl)
553 self.assertTrue(obj_expled.expled)
556 obj_expled_encoded = obj_expled.encode()
557 obj_decoded, tail = obj_expled.decode(
558 obj_expled_encoded + tail_junk,
563 self.assertEqual(tail, tail_junk)
564 self.assertEqual(obj_decoded, obj_expled)
565 self.assertNotEqual(obj_decoded, obj)
566 self.assertEqual(bool(obj_decoded), bool(obj_expled))
567 self.assertEqual(bool(obj_decoded), bool(obj))
568 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
569 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
570 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
572 obj_decoded.expl_llen,
573 len(len_encode(len(obj_encoded))),
575 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
576 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
579 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
581 self.assertEqual(obj_decoded.expl_offset, offset)
583 @given(integers(min_value=2))
584 def test_invalid_len(self, l):
585 with self.assertRaises(InvalidLength):
586 Boolean().decode(b"".join((
592 @given(integers(min_value=0 + 1, max_value=255 - 1))
593 def test_ber_value(self, value):
594 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
595 Boolean().decode(b"".join((
600 obj, _ = Boolean().decode(
608 self.assertTrue(bool(obj))
609 self.assertTrue(obj.bered)
612 integers(min_value=1).map(tag_ctxc),
619 def test_ber_expl(self, expl, values):
625 Boolean(value).encode() +
628 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
630 class SeqOf(SequenceOf):
631 schema = Boolean(expl=expl)
632 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
633 self.assertSequenceEqual(tail, b"")
634 self.assertSequenceEqual([bool(v) for v in seqof], values)
636 set((v.tlvlen, v.expl_tlvlen, v.expl_tlen, v.expl_llen) for v in seqof),
637 set(((3 + EOC_LEN, len(expl) + 1 + 3 + EOC_LEN, len(expl), 1),)),
642 def integer_values_strategy(draw, do_expl=False):
643 bound_min, value, default, bound_max = sorted(draw(sets(
652 _specs = draw(sets(text_letters()))
655 min_size=len(_specs),
656 max_size=len(_specs),
658 _specs = list(zip(_specs, values))
661 bounds = (bound_min, bound_max)
665 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
667 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
670 optional = draw(one_of(none(), booleans()))
672 draw(integers(min_value=0)),
673 draw(integers(min_value=0)),
674 draw(integers(min_value=0)),
676 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
679 class IntegerInherited(Integer):
683 class TestInteger(CommonMixin, TestCase):
686 def test_invalid_value_type(self):
687 with self.assertRaises(InvalidValueType) as err:
691 @given(sets(text_letters(), min_size=2))
692 def test_unknown_name(self, names_input):
693 missing = names_input.pop()
696 schema = [(n, 123) for n in names_input]
697 with self.assertRaises(ObjUnknown) as err:
701 @given(sets(text_letters(), min_size=2))
702 def test_known_name(self, names_input):
704 schema = [(n, 123) for n in names_input]
705 Int(names_input.pop())
708 def test_optional(self, optional):
709 obj = Integer(default=Integer(0), optional=optional)
710 self.assertTrue(obj.optional)
713 def test_ready(self, value):
715 self.assertFalse(obj.ready)
718 with self.assertRaises(ObjNotReady) as err:
722 self.assertTrue(obj.ready)
727 @given(integers(), integers(), binary(), binary())
728 def test_comparison(self, value1, value2, tag1, tag2):
729 for klass in (Integer, IntegerInherited):
732 self.assertEqual(obj1 == obj2, value1 == value2)
733 self.assertEqual(obj1 != obj2, value1 != value2)
734 self.assertEqual(obj1 == int(obj2), value1 == value2)
735 obj1 = klass(value1, impl=tag1)
736 obj2 = klass(value1, impl=tag2)
737 self.assertEqual(obj1 == obj2, tag1 == tag2)
738 self.assertEqual(obj1 != obj2, tag1 != tag2)
740 @given(lists(integers()))
741 def test_sorted_works(self, values):
742 self.assertSequenceEqual(
743 [int(v) for v in sorted(Integer(v) for v in values)],
747 @given(data_strategy())
748 def test_named(self, d):
749 names_input = list(d.draw(sets(text_letters(), min_size=1)))
750 values_input = list(d.draw(sets(
752 min_size=len(names_input),
753 max_size=len(names_input),
755 chosen_name = d.draw(sampled_from(names_input))
756 names_input = dict(zip(names_input, values_input))
760 _int = Int(chosen_name)
761 self.assertEqual(_int.named, chosen_name)
762 self.assertEqual(int(_int), names_input[chosen_name])
764 @given(integers(), integers(min_value=0), integers(min_value=0))
765 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
766 value = bound_min + value_delta
767 bound_max = value + bound_delta
768 Integer(value=value, bounds=(bound_min, bound_max))
770 @given(sets(integers(), min_size=3, max_size=3))
771 def test_bounds_unsatisfied(self, values):
772 values = sorted(values)
773 with self.assertRaises(BoundsError) as err:
774 Integer(value=values[0], bounds=(values[1], values[2]))
776 with self.assertRaises(BoundsError) as err:
777 Integer(value=values[2], bounds=(values[0], values[1]))
780 @given(data_strategy())
781 def test_call(self, d):
782 for klass in (Integer, IntegerInherited):
792 ) = d.draw(integer_values_strategy())
799 optional_initial or False,
812 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
813 if (default is None) and (obj_initial.default is not None):
817 (value is not None) and
818 (bounds_initial is not None) and
819 not (bounds_initial[0] <= value <= bounds_initial[1])
824 (default is not None) and
825 (bounds_initial is not None) and
826 not (bounds_initial[0] <= default <= bounds_initial[1])
829 obj = obj_initial(value, bounds, impl, expl, default, optional)
831 value_expected = default if value is None else value
833 default_initial if value_expected is None
836 self.assertEqual(obj, value_expected)
837 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
838 self.assertEqual(obj.expl_tag, expl or expl_initial)
841 default_initial if default is None else default,
843 if obj.default is None:
844 optional = optional_initial if optional is None else optional
845 optional = False if optional is None else optional
848 self.assertEqual(obj.optional, optional)
850 (obj._bound_min, obj._bound_max),
851 bounds or bounds_initial or (float("-inf"), float("+inf")),
855 {} if _specs_initial is None else dict(_specs_initial),
858 @given(integer_values_strategy())
859 def test_copy(self, values):
860 for klass in (Integer, IntegerInherited):
862 obj_copied = obj.copy()
863 self.assert_copied_basic_fields(obj, obj_copied)
864 self.assertEqual(obj.specs, obj_copied.specs)
865 self.assertEqual(obj._bound_min, obj_copied._bound_min)
866 self.assertEqual(obj._bound_max, obj_copied._bound_max)
867 self.assertEqual(obj._value, obj_copied._value)
871 integers(min_value=1).map(tag_encode),
873 def test_stripped(self, value, tag_impl):
874 obj = Integer(value, impl=tag_impl)
875 with self.assertRaises(NotEnoughData):
876 obj.decode(obj.encode()[:-1])
880 integers(min_value=1).map(tag_ctxc),
882 def test_stripped_expl(self, value, tag_expl):
883 obj = Integer(value, expl=tag_expl)
884 with self.assertRaises(NotEnoughData):
885 obj.decode(obj.encode()[:-1])
887 def test_zero_len(self):
888 with self.assertRaises(NotEnoughData):
889 Integer().decode(b"".join((
895 integers(min_value=31),
896 integers(min_value=0),
899 def test_bad_tag(self, tag, offset, decode_path):
900 decode_path = tuple(str(i) for i in decode_path)
901 with self.assertRaises(DecodeError) as err:
903 tag_encode(tag)[:-1],
905 decode_path=decode_path,
908 self.assertEqual(err.exception.offset, offset)
909 self.assertEqual(err.exception.decode_path, decode_path)
912 integers(min_value=128),
913 integers(min_value=0),
916 def test_bad_len(self, l, offset, decode_path):
917 decode_path = tuple(str(i) for i in decode_path)
918 with self.assertRaises(DecodeError) as err:
920 Integer.tag_default + len_encode(l)[:-1],
922 decode_path=decode_path,
925 self.assertEqual(err.exception.offset, offset)
926 self.assertEqual(err.exception.decode_path, decode_path)
929 sets(integers(), min_size=2, max_size=2),
930 integers(min_value=0),
933 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
934 decode_path = tuple(str(i) for i in decode_path)
935 value, bound_min = list(sorted(ints))
938 bounds = (bound_min, bound_min)
939 with self.assertRaises(DecodeError) as err:
941 Integer(value).encode(),
943 decode_path=decode_path,
946 self.assertEqual(err.exception.offset, offset)
947 self.assertEqual(err.exception.decode_path, decode_path)
949 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
951 integer_values_strategy(),
953 integers(min_value=1).map(tag_ctxc),
954 integers(min_value=0),
957 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
958 for klass in (Integer, IntegerInherited):
959 _, _, _, _, default, optional, _, _decoded = values
968 self.assertFalse(obj.expled)
969 obj_encoded = obj.encode()
970 obj_expled = obj(value, expl=tag_expl)
971 self.assertTrue(obj_expled.expled)
974 obj_expled_encoded = obj_expled.encode()
975 obj_decoded, tail = obj_expled.decode(
976 obj_expled_encoded + tail_junk,
981 self.assertEqual(tail, tail_junk)
982 self.assertEqual(obj_decoded, obj_expled)
983 self.assertNotEqual(obj_decoded, obj)
984 self.assertEqual(int(obj_decoded), int(obj_expled))
985 self.assertEqual(int(obj_decoded), int(obj))
986 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
987 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
988 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
990 obj_decoded.expl_llen,
991 len(len_encode(len(obj_encoded))),
993 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
994 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
997 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
999 self.assertEqual(obj_decoded.expl_offset, offset)
1001 def test_go_vectors_valid(self):
1002 for data, expect in ((
1006 (b"\xff\x7f", -129),
1010 (b"\xff\x00", -256),
1014 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1015 (b"\x80\x00\x00\x00", -2147483648),
1018 Integer().decode(b"".join((
1019 Integer.tag_default,
1020 len_encode(len(data)),
1026 def test_go_vectors_invalid(self):
1031 with self.assertRaises(DecodeError):
1032 Integer().decode(b"".join((
1033 Integer.tag_default,
1034 len_encode(len(data)),
1040 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1043 if draw(booleans()):
1044 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1046 integers(min_value=0, max_value=255),
1047 min_size=len(schema),
1048 max_size=len(schema),
1050 schema = list(zip(schema, bits))
1052 def _value(value_required):
1053 if not value_required and draw(booleans()):
1055 generation_choice = 0
1057 generation_choice = draw(sampled_from((1, 2, 3)))
1058 if generation_choice == 1 or draw(booleans()):
1059 return "'%s'B" % "".join(draw(lists(
1060 sampled_from(("0", "1")),
1061 max_size=len(schema),
1063 elif generation_choice == 2 or draw(booleans()):
1064 return draw(binary(max_size=len(schema) // 8))
1065 elif generation_choice == 3 or draw(booleans()):
1066 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1068 value = _value(value_required)
1069 default = _value(value_required=False)
1073 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1075 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1076 optional = draw(one_of(none(), booleans()))
1078 draw(integers(min_value=0)),
1079 draw(integers(min_value=0)),
1080 draw(integers(min_value=0)),
1082 return (schema, value, impl, expl, default, optional, _decoded)
1085 class BitStringInherited(BitString):
1089 class TestBitString(CommonMixin, TestCase):
1090 base_klass = BitString
1092 @given(lists(booleans()))
1093 def test_b_encoding(self, bits):
1094 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1095 self.assertEqual(obj.bit_len, len(bits))
1096 self.assertSequenceEqual(list(obj), bits)
1097 for i, bit in enumerate(bits):
1098 self.assertEqual(obj[i], bit)
1100 @given(lists(booleans()))
1101 def test_out_of_bounds_bits(self, bits):
1102 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1103 for i in range(len(bits), len(bits) * 2):
1104 self.assertFalse(obj[i])
1106 def test_bad_b_encoding(self):
1107 with self.assertRaises(ValueError):
1108 BitString("'010120101'B")
1111 integers(min_value=1, max_value=255),
1112 integers(min_value=1, max_value=255),
1114 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1115 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1116 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1117 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1119 class BS(BitString):
1120 schema = (("whatever", 0),)
1121 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1122 self.assertEqual(obj.bit_len, leading_zeros + 1)
1123 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1125 def test_zero_len(self):
1126 with self.assertRaises(NotEnoughData):
1127 BitString().decode(b"".join((
1128 BitString.tag_default,
1132 def test_invalid_value_type(self):
1133 with self.assertRaises(InvalidValueType) as err:
1136 with self.assertRaises(InvalidValueType) as err:
1140 def test_obj_unknown(self):
1141 with self.assertRaises(ObjUnknown) as err:
1142 BitString(b"whatever")["whenever"]
1145 def test_get_invalid_type(self):
1146 with self.assertRaises(InvalidValueType) as err:
1147 BitString(b"whatever")[(1, 2, 3)]
1150 @given(data_strategy())
1151 def test_unknown_name(self, d):
1152 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1153 missing = _schema.pop()
1155 class BS(BitString):
1156 schema = [(n, i) for i, n in enumerate(_schema)]
1157 with self.assertRaises(ObjUnknown) as err:
1162 def test_optional(self, optional):
1163 obj = BitString(default=BitString(b""), optional=optional)
1164 self.assertTrue(obj.optional)
1167 def test_ready(self, value):
1169 self.assertFalse(obj.ready)
1172 with self.assertRaises(ObjNotReady) as err:
1175 obj = BitString(value)
1176 self.assertTrue(obj.ready)
1181 tuples(integers(min_value=0), binary()),
1182 tuples(integers(min_value=0), binary()),
1186 def test_comparison(self, value1, value2, tag1, tag2):
1187 for klass in (BitString, BitStringInherited):
1188 obj1 = klass(value1)
1189 obj2 = klass(value2)
1190 self.assertEqual(obj1 == obj2, value1 == value2)
1191 self.assertEqual(obj1 != obj2, value1 != value2)
1192 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1193 obj1 = klass(value1, impl=tag1)
1194 obj2 = klass(value1, impl=tag2)
1195 self.assertEqual(obj1 == obj2, tag1 == tag2)
1196 self.assertEqual(obj1 != obj2, tag1 != tag2)
1198 @given(data_strategy())
1199 def test_call(self, d):
1200 for klass in (BitString, BitStringInherited):
1209 ) = d.draw(bit_string_values_strategy())
1212 schema = schema_initial
1214 value=value_initial,
1217 default=default_initial,
1218 optional=optional_initial or False,
1219 _decoded=_decoded_initial,
1229 ) = d.draw(bit_string_values_strategy(
1230 schema=schema_initial,
1231 do_expl=impl_initial is None,
1240 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1241 self.assertEqual(obj.expl_tag, expl or expl_initial)
1242 if obj.default is None:
1243 optional = optional_initial if optional is None else optional
1244 optional = False if optional is None else optional
1247 self.assertEqual(obj.optional, optional)
1248 self.assertEqual(obj.specs, obj_initial.specs)
1250 @given(bit_string_values_strategy())
1251 def test_copy(self, values):
1252 for klass in (BitString, BitStringInherited):
1253 _schema, value, impl, expl, default, optional, _decoded = values
1262 optional=optional or False,
1265 obj_copied = obj.copy()
1266 self.assert_copied_basic_fields(obj, obj_copied)
1267 self.assertEqual(obj.specs, obj_copied.specs)
1268 self.assertEqual(obj._value, obj_copied._value)
1272 integers(min_value=1).map(tag_encode),
1274 def test_stripped(self, value, tag_impl):
1275 obj = BitString(value, impl=tag_impl)
1276 with self.assertRaises(NotEnoughData):
1277 obj.decode(obj.encode()[:-1])
1281 integers(min_value=1).map(tag_ctxc),
1283 def test_stripped_expl(self, value, tag_expl):
1284 obj = BitString(value, expl=tag_expl)
1285 with self.assertRaises(NotEnoughData):
1286 obj.decode(obj.encode()[:-1])
1289 integers(min_value=31),
1290 integers(min_value=0),
1293 def test_bad_tag(self, tag, offset, decode_path):
1294 decode_path = tuple(str(i) for i in decode_path)
1295 with self.assertRaises(DecodeError) as err:
1297 tag_encode(tag)[:-1],
1299 decode_path=decode_path,
1302 self.assertEqual(err.exception.offset, offset)
1303 self.assertEqual(err.exception.decode_path, decode_path)
1306 integers(min_value=128),
1307 integers(min_value=0),
1310 def test_bad_len(self, l, offset, decode_path):
1311 decode_path = tuple(str(i) for i in decode_path)
1312 with self.assertRaises(DecodeError) as err:
1314 BitString.tag_default + len_encode(l)[:-1],
1316 decode_path=decode_path,
1319 self.assertEqual(err.exception.offset, offset)
1320 self.assertEqual(err.exception.decode_path, decode_path)
1322 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1323 @given(data_strategy())
1324 def test_symmetric(self, d):
1333 ) = d.draw(bit_string_values_strategy(value_required=True))
1334 tail_junk = d.draw(binary(max_size=5))
1335 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1336 offset = d.draw(integers(min_value=0))
1337 for klass in (BitString, BitStringInherited):
1348 self.assertFalse(obj.expled)
1349 obj_encoded = obj.encode()
1350 obj_expled = obj(value, expl=tag_expl)
1351 self.assertTrue(obj_expled.expled)
1354 obj_expled_encoded = obj_expled.encode()
1355 obj_decoded, tail = obj_expled.decode(
1356 obj_expled_encoded + tail_junk,
1361 self.assertEqual(tail, tail_junk)
1362 self.assertEqual(obj_decoded, obj_expled)
1363 self.assertNotEqual(obj_decoded, obj)
1364 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1365 self.assertEqual(bytes(obj_decoded), bytes(obj))
1366 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1367 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1368 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1370 obj_decoded.expl_llen,
1371 len(len_encode(len(obj_encoded))),
1373 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1374 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1377 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1379 self.assertEqual(obj_decoded.expl_offset, offset)
1380 if isinstance(value, tuple):
1381 self.assertSetEqual(set(value), set(obj_decoded.named))
1385 @given(integers(min_value=1, max_value=255))
1386 def test_bad_zero_value(self, pad_size):
1387 with self.assertRaises(DecodeError):
1388 BitString().decode(b"".join((
1389 BitString.tag_default,
1394 def test_go_vectors_invalid(self):
1400 with self.assertRaises(DecodeError):
1401 BitString().decode(b"".join((
1402 BitString.tag_default,
1407 def test_go_vectors_valid(self):
1408 obj, _ = BitString().decode(b"".join((
1409 BitString.tag_default,
1413 self.assertEqual(bytes(obj), b"")
1414 self.assertEqual(obj.bit_len, 0)
1416 obj, _ = BitString().decode(b"".join((
1417 BitString.tag_default,
1421 self.assertEqual(bytes(obj), b"\x00")
1422 self.assertEqual(obj.bit_len, 1)
1424 obj = BitString((16, b"\x82\x40"))
1425 self.assertTrue(obj[0])
1426 self.assertFalse(obj[1])
1427 self.assertTrue(obj[6])
1428 self.assertTrue(obj[9])
1429 self.assertFalse(obj[17])
1432 integers(min_value=1, max_value=30),
1435 binary(min_size=1, max_size=5),
1437 binary(min_size=1, max_size=5),
1445 lists(booleans(), min_size=1),
1447 def test_constructed(self, impl, chunk_inputs, chunk_last_bits):
1448 def chunk_constructed(contents):
1450 tag_encode(form=TagFormConstructed, num=3) +
1452 b"".join(BitString(content).encode() for content in contents) +
1456 payload_expected = b""
1457 bit_len_expected = 0
1458 for chunk_input in chunk_inputs:
1459 if isinstance(chunk_input, binary_type):
1460 chunks.append(BitString(chunk_input).encode())
1461 payload_expected += chunk_input
1462 bit_len_expected += len(chunk_input) * 8
1464 chunks.append(chunk_constructed(chunk_input))
1465 payload = b"".join(chunk_input)
1466 payload_expected += payload
1467 bit_len_expected += len(payload) * 8
1468 chunk_last = BitString("'%s'B" % "".join(
1469 "1" if bit else "0" for bit in chunk_last_bits
1471 payload_expected += bytes(chunk_last)
1472 bit_len_expected += chunk_last.bit_len
1473 encoded_indefinite = (
1474 tag_encode(form=TagFormConstructed, num=impl) +
1477 chunk_last.encode() +
1480 encoded_definite = (
1481 tag_encode(form=TagFormConstructed, num=impl) +
1482 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1486 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1487 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1488 for encoded in (encoded_indefinite, encoded_definite):
1489 obj, tail = BitString(impl=tag_encode(impl)).decode(
1490 encoded, ctx={"bered": True}
1492 self.assertSequenceEqual(tail, b"")
1493 self.assertEqual(obj.bit_len, bit_len_expected)
1494 self.assertSequenceEqual(bytes(obj), payload_expected)
1495 self.assertTrue(obj.bered)
1496 self.assertEqual(len(encoded), obj.tlvlen)
1498 def test_x690_vector(self):
1499 vector_payload = hexdec("0A3B5F291CD0")
1500 vector = BitString((len(vector_payload) * 8 - 4, vector_payload))
1501 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1502 self.assertSequenceEqual(tail, b"")
1503 self.assertEqual(obj, vector)
1504 obj, tail = BitString().decode(
1505 hexdec("23800303000A3B0305045F291CD00000"),
1506 ctx={"bered": True},
1508 self.assertSequenceEqual(tail, b"")
1509 self.assertEqual(obj, vector)
1513 def octet_string_values_strategy(draw, do_expl=False):
1514 bound_min, bound_max = sorted(draw(sets(
1515 integers(min_value=0, max_value=1 << 7),
1519 value = draw(one_of(
1521 binary(min_size=bound_min, max_size=bound_max),
1523 default = draw(one_of(
1525 binary(min_size=bound_min, max_size=bound_max),
1528 if draw(booleans()):
1529 bounds = (bound_min, bound_max)
1533 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1535 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1536 optional = draw(one_of(none(), booleans()))
1538 draw(integers(min_value=0)),
1539 draw(integers(min_value=0)),
1540 draw(integers(min_value=0)),
1542 return (value, bounds, impl, expl, default, optional, _decoded)
1545 class OctetStringInherited(OctetString):
1549 class TestOctetString(CommonMixin, TestCase):
1550 base_klass = OctetString
1552 def test_invalid_value_type(self):
1553 with self.assertRaises(InvalidValueType) as err:
1554 OctetString(text_type(123))
1558 def test_optional(self, optional):
1559 obj = OctetString(default=OctetString(b""), optional=optional)
1560 self.assertTrue(obj.optional)
1563 def test_ready(self, value):
1565 self.assertFalse(obj.ready)
1568 with self.assertRaises(ObjNotReady) as err:
1571 obj = OctetString(value)
1572 self.assertTrue(obj.ready)
1576 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1577 def test_comparison(self, value1, value2, tag1, tag2):
1578 for klass in (OctetString, OctetStringInherited):
1579 obj1 = klass(value1)
1580 obj2 = klass(value2)
1581 self.assertEqual(obj1 == obj2, value1 == value2)
1582 self.assertEqual(obj1 != obj2, value1 != value2)
1583 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1584 obj1 = klass(value1, impl=tag1)
1585 obj2 = klass(value1, impl=tag2)
1586 self.assertEqual(obj1 == obj2, tag1 == tag2)
1587 self.assertEqual(obj1 != obj2, tag1 != tag2)
1589 @given(lists(binary()))
1590 def test_sorted_works(self, values):
1591 self.assertSequenceEqual(
1592 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1596 @given(data_strategy())
1597 def test_bounds_satisfied(self, d):
1598 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1599 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1600 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1601 OctetString(value=value, bounds=(bound_min, bound_max))
1603 @given(data_strategy())
1604 def test_bounds_unsatisfied(self, d):
1605 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1606 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1607 value = d.draw(binary(max_size=bound_min - 1))
1608 with self.assertRaises(BoundsError) as err:
1609 OctetString(value=value, bounds=(bound_min, bound_max))
1611 value = d.draw(binary(min_size=bound_max + 1))
1612 with self.assertRaises(BoundsError) as err:
1613 OctetString(value=value, bounds=(bound_min, bound_max))
1616 @given(data_strategy())
1617 def test_call(self, d):
1618 for klass in (OctetString, OctetStringInherited):
1627 ) = d.draw(octet_string_values_strategy())
1628 obj_initial = klass(
1634 optional_initial or False,
1645 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1646 if (default is None) and (obj_initial.default is not None):
1649 (bounds is None) and
1650 (value is not None) and
1651 (bounds_initial is not None) and
1652 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1656 (bounds is None) and
1657 (default is not None) and
1658 (bounds_initial is not None) and
1659 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1662 obj = obj_initial(value, bounds, impl, expl, default, optional)
1664 value_expected = default if value is None else value
1666 default_initial if value_expected is None
1669 self.assertEqual(obj, value_expected)
1670 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1671 self.assertEqual(obj.expl_tag, expl or expl_initial)
1674 default_initial if default is None else default,
1676 if obj.default is None:
1677 optional = optional_initial if optional is None else optional
1678 optional = False if optional is None else optional
1681 self.assertEqual(obj.optional, optional)
1683 (obj._bound_min, obj._bound_max),
1684 bounds or bounds_initial or (0, float("+inf")),
1687 @given(octet_string_values_strategy())
1688 def test_copy(self, values):
1689 for klass in (OctetString, OctetStringInherited):
1690 obj = klass(*values)
1691 obj_copied = obj.copy()
1692 self.assert_copied_basic_fields(obj, obj_copied)
1693 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1694 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1695 self.assertEqual(obj._value, obj_copied._value)
1699 integers(min_value=1).map(tag_encode),
1701 def test_stripped(self, value, tag_impl):
1702 obj = OctetString(value, impl=tag_impl)
1703 with self.assertRaises(NotEnoughData):
1704 obj.decode(obj.encode()[:-1])
1708 integers(min_value=1).map(tag_ctxc),
1710 def test_stripped_expl(self, value, tag_expl):
1711 obj = OctetString(value, expl=tag_expl)
1712 with self.assertRaises(NotEnoughData):
1713 obj.decode(obj.encode()[:-1])
1716 integers(min_value=31),
1717 integers(min_value=0),
1720 def test_bad_tag(self, tag, offset, decode_path):
1721 decode_path = tuple(str(i) for i in decode_path)
1722 with self.assertRaises(DecodeError) as err:
1723 OctetString().decode(
1724 tag_encode(tag)[:-1],
1726 decode_path=decode_path,
1729 self.assertEqual(err.exception.offset, offset)
1730 self.assertEqual(err.exception.decode_path, decode_path)
1733 integers(min_value=128),
1734 integers(min_value=0),
1737 def test_bad_len(self, l, offset, decode_path):
1738 decode_path = tuple(str(i) for i in decode_path)
1739 with self.assertRaises(DecodeError) as err:
1740 OctetString().decode(
1741 OctetString.tag_default + len_encode(l)[:-1],
1743 decode_path=decode_path,
1746 self.assertEqual(err.exception.offset, offset)
1747 self.assertEqual(err.exception.decode_path, decode_path)
1750 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1751 integers(min_value=0),
1754 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1755 decode_path = tuple(str(i) for i in decode_path)
1756 value, bound_min = list(sorted(ints))
1758 class String(OctetString):
1759 bounds = (bound_min, bound_min)
1760 with self.assertRaises(DecodeError) as err:
1762 OctetString(b"\x00" * value).encode(),
1764 decode_path=decode_path,
1767 self.assertEqual(err.exception.offset, offset)
1768 self.assertEqual(err.exception.decode_path, decode_path)
1770 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1772 octet_string_values_strategy(),
1774 integers(min_value=1).map(tag_ctxc),
1775 integers(min_value=0),
1778 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1779 for klass in (OctetString, OctetStringInherited):
1780 _, _, _, _, default, optional, _decoded = values
1789 self.assertFalse(obj.expled)
1790 obj_encoded = obj.encode()
1791 obj_expled = obj(value, expl=tag_expl)
1792 self.assertTrue(obj_expled.expled)
1795 obj_expled_encoded = obj_expled.encode()
1796 obj_decoded, tail = obj_expled.decode(
1797 obj_expled_encoded + tail_junk,
1802 self.assertEqual(tail, tail_junk)
1803 self.assertEqual(obj_decoded, obj_expled)
1804 self.assertNotEqual(obj_decoded, obj)
1805 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1806 self.assertEqual(bytes(obj_decoded), bytes(obj))
1807 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1808 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1809 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1811 obj_decoded.expl_llen,
1812 len(len_encode(len(obj_encoded))),
1814 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1815 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1818 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1820 self.assertEqual(obj_decoded.expl_offset, offset)
1823 integers(min_value=1, max_value=30),
1826 binary(min_size=1, max_size=5),
1828 binary(min_size=1, max_size=5),
1837 def test_constructed(self, impl, chunk_inputs):
1838 def chunk_constructed(contents):
1840 tag_encode(form=TagFormConstructed, num=4) +
1842 b"".join(OctetString(content).encode() for content in contents) +
1846 payload_expected = b""
1847 for chunk_input in chunk_inputs:
1848 if isinstance(chunk_input, binary_type):
1849 chunks.append(OctetString(chunk_input).encode())
1850 payload_expected += chunk_input
1852 chunks.append(chunk_constructed(chunk_input))
1853 payload = b"".join(chunk_input)
1854 payload_expected += payload
1855 encoded_indefinite = (
1856 tag_encode(form=TagFormConstructed, num=impl) +
1861 encoded_definite = (
1862 tag_encode(form=TagFormConstructed, num=impl) +
1863 len_encode(len(b"".join(chunks))) +
1866 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1867 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
1868 for encoded in (encoded_indefinite, encoded_definite):
1869 obj, tail = OctetString(impl=tag_encode(impl)).decode(
1870 encoded, ctx={"bered": True}
1872 self.assertSequenceEqual(tail, b"")
1873 self.assertSequenceEqual(bytes(obj), payload_expected)
1874 self.assertTrue(obj.bered)
1875 self.assertEqual(len(encoded), obj.tlvlen)
1879 def null_values_strategy(draw, do_expl=False):
1883 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1885 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1886 optional = draw(one_of(none(), booleans()))
1888 draw(integers(min_value=0)),
1889 draw(integers(min_value=0)),
1890 draw(integers(min_value=0)),
1892 return (impl, expl, optional, _decoded)
1895 class NullInherited(Null):
1899 class TestNull(CommonMixin, TestCase):
1902 def test_ready(self):
1904 self.assertTrue(obj.ready)
1908 @given(binary(), binary())
1909 def test_comparison(self, tag1, tag2):
1910 for klass in (Null, NullInherited):
1911 obj1 = klass(impl=tag1)
1912 obj2 = klass(impl=tag2)
1913 self.assertEqual(obj1 == obj2, tag1 == tag2)
1914 self.assertEqual(obj1 != obj2, tag1 != tag2)
1915 self.assertNotEqual(obj1, tag2)
1917 @given(data_strategy())
1918 def test_call(self, d):
1919 for klass in (Null, NullInherited):
1925 ) = d.draw(null_values_strategy())
1926 obj_initial = klass(
1929 optional=optional_initial or False,
1930 _decoded=_decoded_initial,
1937 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
1938 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1939 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1940 self.assertEqual(obj.expl_tag, expl or expl_initial)
1941 optional = optional_initial if optional is None else optional
1942 optional = False if optional is None else optional
1943 self.assertEqual(obj.optional, optional)
1945 @given(null_values_strategy())
1946 def test_copy(self, values):
1947 for klass in (Null, NullInherited):
1948 impl, expl, optional, _decoded = values
1952 optional=optional or False,
1955 obj_copied = obj.copy()
1956 self.assert_copied_basic_fields(obj, obj_copied)
1958 @given(integers(min_value=1).map(tag_encode))
1959 def test_stripped(self, tag_impl):
1960 obj = Null(impl=tag_impl)
1961 with self.assertRaises(NotEnoughData):
1962 obj.decode(obj.encode()[:-1])
1964 @given(integers(min_value=1).map(tag_ctxc))
1965 def test_stripped_expl(self, tag_expl):
1966 obj = Null(expl=tag_expl)
1967 with self.assertRaises(NotEnoughData):
1968 obj.decode(obj.encode()[:-1])
1971 integers(min_value=31),
1972 integers(min_value=0),
1975 def test_bad_tag(self, tag, offset, decode_path):
1976 decode_path = tuple(str(i) for i in decode_path)
1977 with self.assertRaises(DecodeError) as err:
1979 tag_encode(tag)[:-1],
1981 decode_path=decode_path,
1984 self.assertEqual(err.exception.offset, offset)
1985 self.assertEqual(err.exception.decode_path, decode_path)
1988 integers(min_value=128),
1989 integers(min_value=0),
1992 def test_bad_len(self, l, offset, decode_path):
1993 decode_path = tuple(str(i) for i in decode_path)
1994 with self.assertRaises(DecodeError) as err:
1996 Null.tag_default + len_encode(l)[:-1],
1998 decode_path=decode_path,
2001 self.assertEqual(err.exception.offset, offset)
2002 self.assertEqual(err.exception.decode_path, decode_path)
2004 @given(binary(min_size=1))
2005 def test_tag_mismatch(self, impl):
2006 assume(impl != Null.tag_default)
2007 with self.assertRaises(TagMismatch):
2008 Null(impl=impl).decode(Null().encode())
2011 null_values_strategy(),
2012 integers(min_value=1).map(tag_ctxc),
2013 integers(min_value=0),
2016 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2017 for klass in (Null, NullInherited):
2018 _, _, optional, _decoded = values
2019 obj = klass(optional=optional, _decoded=_decoded)
2022 self.assertFalse(obj.expled)
2023 obj_encoded = obj.encode()
2024 obj_expled = obj(expl=tag_expl)
2025 self.assertTrue(obj_expled.expled)
2028 obj_expled_encoded = obj_expled.encode()
2029 obj_decoded, tail = obj_expled.decode(
2030 obj_expled_encoded + tail_junk,
2035 self.assertEqual(tail, tail_junk)
2036 self.assertEqual(obj_decoded, obj_expled)
2037 self.assertNotEqual(obj_decoded, obj)
2038 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2039 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2040 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2042 obj_decoded.expl_llen,
2043 len(len_encode(len(obj_encoded))),
2045 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2046 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2049 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2051 self.assertEqual(obj_decoded.expl_offset, offset)
2053 @given(integers(min_value=1))
2054 def test_invalid_len(self, l):
2055 with self.assertRaises(InvalidLength):
2056 Null().decode(b"".join((
2063 def oid_strategy(draw):
2064 first_arc = draw(integers(min_value=0, max_value=2))
2066 if first_arc in (0, 1):
2067 second_arc = draw(integers(min_value=0, max_value=39))
2069 second_arc = draw(integers(min_value=0))
2070 other_arcs = draw(lists(integers(min_value=0)))
2071 return tuple([first_arc, second_arc] + other_arcs)
2075 def oid_values_strategy(draw, do_expl=False):
2076 value = draw(one_of(none(), oid_strategy()))
2080 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2082 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2083 default = draw(one_of(none(), oid_strategy()))
2084 optional = draw(one_of(none(), booleans()))
2086 draw(integers(min_value=0)),
2087 draw(integers(min_value=0)),
2088 draw(integers(min_value=0)),
2090 return (value, impl, expl, default, optional, _decoded)
2093 class ObjectIdentifierInherited(ObjectIdentifier):
2097 class TestObjectIdentifier(CommonMixin, TestCase):
2098 base_klass = ObjectIdentifier
2100 def test_invalid_value_type(self):
2101 with self.assertRaises(InvalidValueType) as err:
2102 ObjectIdentifier(123)
2106 def test_optional(self, optional):
2107 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2108 self.assertTrue(obj.optional)
2110 @given(oid_strategy())
2111 def test_ready(self, value):
2112 obj = ObjectIdentifier()
2113 self.assertFalse(obj.ready)
2116 with self.assertRaises(ObjNotReady) as err:
2119 obj = ObjectIdentifier(value)
2120 self.assertTrue(obj.ready)
2125 @given(oid_strategy(), oid_strategy(), binary(), binary())
2126 def test_comparison(self, value1, value2, tag1, tag2):
2127 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2128 obj1 = klass(value1)
2129 obj2 = klass(value2)
2130 self.assertEqual(obj1 == obj2, value1 == value2)
2131 self.assertEqual(obj1 != obj2, value1 != value2)
2132 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2133 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2134 obj1 = klass(value1, impl=tag1)
2135 obj2 = klass(value1, impl=tag2)
2136 self.assertEqual(obj1 == obj2, tag1 == tag2)
2137 self.assertEqual(obj1 != obj2, tag1 != tag2)
2139 @given(lists(oid_strategy()))
2140 def test_sorted_works(self, values):
2141 self.assertSequenceEqual(
2142 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2146 @given(data_strategy())
2147 def test_call(self, d):
2148 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2156 ) = d.draw(oid_values_strategy())
2157 obj_initial = klass(
2158 value=value_initial,
2161 default=default_initial,
2162 optional=optional_initial or False,
2163 _decoded=_decoded_initial,
2172 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2181 value_expected = default if value is None else value
2183 default_initial if value_expected is None
2186 self.assertEqual(obj, value_expected)
2187 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2188 self.assertEqual(obj.expl_tag, expl or expl_initial)
2191 default_initial if default is None else default,
2193 if obj.default is None:
2194 optional = optional_initial if optional is None else optional
2195 optional = False if optional is None else optional
2198 self.assertEqual(obj.optional, optional)
2200 @given(oid_values_strategy())
2201 def test_copy(self, values):
2202 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2219 obj_copied = obj.copy()
2220 self.assert_copied_basic_fields(obj, obj_copied)
2221 self.assertEqual(obj._value, obj_copied._value)
2223 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2226 integers(min_value=1).map(tag_encode),
2228 def test_stripped(self, value, tag_impl):
2229 obj = ObjectIdentifier(value, impl=tag_impl)
2230 with self.assertRaises(NotEnoughData):
2231 obj.decode(obj.encode()[:-1])
2235 integers(min_value=1).map(tag_ctxc),
2237 def test_stripped_expl(self, value, tag_expl):
2238 obj = ObjectIdentifier(value, expl=tag_expl)
2239 with self.assertRaises(NotEnoughData):
2240 obj.decode(obj.encode()[:-1])
2243 integers(min_value=31),
2244 integers(min_value=0),
2247 def test_bad_tag(self, tag, offset, decode_path):
2248 decode_path = tuple(str(i) for i in decode_path)
2249 with self.assertRaises(DecodeError) as err:
2250 ObjectIdentifier().decode(
2251 tag_encode(tag)[:-1],
2253 decode_path=decode_path,
2256 self.assertEqual(err.exception.offset, offset)
2257 self.assertEqual(err.exception.decode_path, decode_path)
2260 integers(min_value=128),
2261 integers(min_value=0),
2264 def test_bad_len(self, l, offset, decode_path):
2265 decode_path = tuple(str(i) for i in decode_path)
2266 with self.assertRaises(DecodeError) as err:
2267 ObjectIdentifier().decode(
2268 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2270 decode_path=decode_path,
2273 self.assertEqual(err.exception.offset, offset)
2274 self.assertEqual(err.exception.decode_path, decode_path)
2276 def test_zero_oid(self):
2277 with self.assertRaises(NotEnoughData):
2278 ObjectIdentifier().decode(
2279 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2282 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2283 @given(oid_strategy())
2284 def test_unfinished_oid(self, value):
2285 assume(list(value)[-1] > 255)
2286 obj_encoded = ObjectIdentifier(value).encode()
2287 obj, _ = ObjectIdentifier().decode(obj_encoded)
2288 data = obj_encoded[obj.tlen + obj.llen:-1]
2290 ObjectIdentifier.tag_default,
2291 len_encode(len(data)),
2294 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2297 @given(integers(min_value=0))
2298 def test_invalid_short(self, value):
2299 with self.assertRaises(InvalidOID):
2300 ObjectIdentifier((value,))
2301 with self.assertRaises(InvalidOID):
2302 ObjectIdentifier("%d" % value)
2304 @given(integers(min_value=3), integers(min_value=0))
2305 def test_invalid_first_arc(self, first_arc, second_arc):
2306 with self.assertRaises(InvalidOID):
2307 ObjectIdentifier((first_arc, second_arc))
2308 with self.assertRaises(InvalidOID):
2309 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2311 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2312 def test_invalid_second_arc(self, first_arc, second_arc):
2313 with self.assertRaises(InvalidOID):
2314 ObjectIdentifier((first_arc, second_arc))
2315 with self.assertRaises(InvalidOID):
2316 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2318 @given(text(alphabet=ascii_letters + ".", min_size=1))
2319 def test_junk(self, oid):
2320 with self.assertRaises(InvalidOID):
2321 ObjectIdentifier(oid)
2323 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2324 @given(oid_strategy())
2325 def test_validness(self, oid):
2326 obj = ObjectIdentifier(oid)
2327 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2332 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2334 oid_values_strategy(),
2336 integers(min_value=1).map(tag_ctxc),
2337 integers(min_value=0),
2340 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2341 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2342 _, _, _, default, optional, _decoded = values
2351 self.assertFalse(obj.expled)
2352 obj_encoded = obj.encode()
2353 obj_expled = obj(value, expl=tag_expl)
2354 self.assertTrue(obj_expled.expled)
2357 obj_expled_encoded = obj_expled.encode()
2358 obj_decoded, tail = obj_expled.decode(
2359 obj_expled_encoded + tail_junk,
2364 self.assertEqual(tail, tail_junk)
2365 self.assertEqual(obj_decoded, obj_expled)
2366 self.assertNotEqual(obj_decoded, obj)
2367 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2368 self.assertEqual(tuple(obj_decoded), tuple(obj))
2369 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2370 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2371 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2373 obj_decoded.expl_llen,
2374 len(len_encode(len(obj_encoded))),
2376 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2377 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2380 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2382 self.assertEqual(obj_decoded.expl_offset, offset)
2385 oid_strategy().map(ObjectIdentifier),
2386 oid_strategy().map(ObjectIdentifier),
2388 def test_add(self, oid1, oid2):
2389 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2390 for oid_to_add in (oid2, tuple(oid2)):
2391 self.assertEqual(oid1 + oid_to_add, oid_expect)
2392 with self.assertRaises(InvalidValueType):
2395 def test_go_vectors_valid(self):
2396 for data, expect in (
2398 (b"\x55\x02", (2, 5, 2)),
2399 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2400 (b"\x81\x34\x03", (2, 100, 3)),
2403 ObjectIdentifier().decode(b"".join((
2404 ObjectIdentifier.tag_default,
2405 len_encode(len(data)),
2411 def test_go_vectors_invalid(self):
2412 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2413 with self.assertRaises(DecodeError):
2414 ObjectIdentifier().decode(b"".join((
2415 Integer.tag_default,
2416 len_encode(len(data)),
2420 def test_x690_vector(self):
2422 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2423 ObjectIdentifier((2, 999, 3)),
2428 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2430 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2431 values = list(draw(sets(
2433 min_size=len(schema),
2434 max_size=len(schema),
2436 schema = list(zip(schema, values))
2437 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2441 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2443 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2444 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2445 optional = draw(one_of(none(), booleans()))
2447 draw(integers(min_value=0)),
2448 draw(integers(min_value=0)),
2449 draw(integers(min_value=0)),
2451 return (schema, value, impl, expl, default, optional, _decoded)
2454 class TestEnumerated(CommonMixin, TestCase):
2455 class EWhatever(Enumerated):
2456 schema = (("whatever", 0),)
2458 base_klass = EWhatever
2460 def test_schema_required(self):
2461 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2464 def test_invalid_value_type(self):
2465 with self.assertRaises(InvalidValueType) as err:
2466 self.base_klass((1, 2))
2469 @given(sets(text_letters(), min_size=2))
2470 def test_unknown_name(self, schema_input):
2471 missing = schema_input.pop()
2473 class E(Enumerated):
2474 schema = [(n, 123) for n in schema_input]
2475 with self.assertRaises(ObjUnknown) as err:
2480 sets(text_letters(), min_size=2),
2481 sets(integers(), min_size=2),
2483 def test_unknown_value(self, schema_input, values_input):
2485 missing_value = values_input.pop()
2486 _input = list(zip(schema_input, values_input))
2488 class E(Enumerated):
2490 with self.assertRaises(DecodeError) as err:
2495 def test_optional(self, optional):
2496 obj = self.base_klass(default="whatever", optional=optional)
2497 self.assertTrue(obj.optional)
2499 def test_ready(self):
2500 obj = self.base_klass()
2501 self.assertFalse(obj.ready)
2504 with self.assertRaises(ObjNotReady) as err:
2507 obj = self.base_klass("whatever")
2508 self.assertTrue(obj.ready)
2512 @given(integers(), integers(), binary(), binary())
2513 def test_comparison(self, value1, value2, tag1, tag2):
2514 class E(Enumerated):
2516 ("whatever0", value1),
2517 ("whatever1", value2),
2520 class EInherited(E):
2522 for klass in (E, EInherited):
2523 obj1 = klass(value1)
2524 obj2 = klass(value2)
2525 self.assertEqual(obj1 == obj2, value1 == value2)
2526 self.assertEqual(obj1 != obj2, value1 != value2)
2527 self.assertEqual(obj1 == int(obj2), value1 == value2)
2528 obj1 = klass(value1, impl=tag1)
2529 obj2 = klass(value1, impl=tag2)
2530 self.assertEqual(obj1 == obj2, tag1 == tag2)
2531 self.assertEqual(obj1 != obj2, tag1 != tag2)
2533 @given(data_strategy())
2534 def test_call(self, d):
2543 ) = d.draw(enumerated_values_strategy())
2545 class E(Enumerated):
2546 schema = schema_initial
2548 value=value_initial,
2551 default=default_initial,
2552 optional=optional_initial or False,
2553 _decoded=_decoded_initial,
2563 ) = d.draw(enumerated_values_strategy(
2564 schema=schema_initial,
2565 do_expl=impl_initial is None,
2575 value_expected = default if value is None else value
2577 default_initial if value_expected is None
2582 dict(schema_initial).get(value_expected, value_expected),
2584 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2585 self.assertEqual(obj.expl_tag, expl or expl_initial)
2588 default_initial if default is None else default,
2590 if obj.default is None:
2591 optional = optional_initial if optional is None else optional
2592 optional = False if optional is None else optional
2595 self.assertEqual(obj.optional, optional)
2596 self.assertEqual(obj.specs, dict(schema_initial))
2598 @given(enumerated_values_strategy())
2599 def test_copy(self, values):
2600 schema_input, value, impl, expl, default, optional, _decoded = values
2602 class E(Enumerated):
2603 schema = schema_input
2612 obj_copied = obj.copy()
2613 self.assert_copied_basic_fields(obj, obj_copied)
2614 self.assertEqual(obj.specs, obj_copied.specs)
2616 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2617 @given(data_strategy())
2618 def test_symmetric(self, d):
2619 schema_input, _, _, _, default, optional, _decoded = d.draw(
2620 enumerated_values_strategy(),
2622 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2623 offset = d.draw(integers(min_value=0))
2624 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2625 tail_junk = d.draw(binary(max_size=5))
2627 class E(Enumerated):
2628 schema = schema_input
2637 self.assertFalse(obj.expled)
2638 obj_encoded = obj.encode()
2639 obj_expled = obj(value, expl=tag_expl)
2640 self.assertTrue(obj_expled.expled)
2643 obj_expled_encoded = obj_expled.encode()
2644 obj_decoded, tail = obj_expled.decode(
2645 obj_expled_encoded + tail_junk,
2650 self.assertEqual(tail, tail_junk)
2651 self.assertEqual(obj_decoded, obj_expled)
2652 self.assertNotEqual(obj_decoded, obj)
2653 self.assertEqual(int(obj_decoded), int(obj_expled))
2654 self.assertEqual(int(obj_decoded), int(obj))
2655 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2656 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2657 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2659 obj_decoded.expl_llen,
2660 len(len_encode(len(obj_encoded))),
2662 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2663 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2666 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2668 self.assertEqual(obj_decoded.expl_offset, offset)
2672 def string_values_strategy(draw, alphabet, do_expl=False):
2673 bound_min, bound_max = sorted(draw(sets(
2674 integers(min_value=0, max_value=1 << 7),
2678 value = draw(one_of(
2680 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2682 default = draw(one_of(
2684 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2687 if draw(booleans()):
2688 bounds = (bound_min, bound_max)
2692 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2694 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2695 optional = draw(one_of(none(), booleans()))
2697 draw(integers(min_value=0)),
2698 draw(integers(min_value=0)),
2699 draw(integers(min_value=0)),
2701 return (value, bounds, impl, expl, default, optional, _decoded)
2704 class StringMixin(object):
2705 def test_invalid_value_type(self):
2706 with self.assertRaises(InvalidValueType) as err:
2707 self.base_klass((1, 2))
2710 def text_alphabet(self):
2711 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2712 return printable + whitespace
2716 def test_optional(self, optional):
2717 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2718 self.assertTrue(obj.optional)
2720 @given(data_strategy())
2721 def test_ready(self, d):
2722 obj = self.base_klass()
2723 self.assertFalse(obj.ready)
2727 with self.assertRaises(ObjNotReady) as err:
2730 value = d.draw(text(alphabet=self.text_alphabet()))
2731 obj = self.base_klass(value)
2732 self.assertTrue(obj.ready)
2737 @given(data_strategy())
2738 def test_comparison(self, d):
2739 value1 = d.draw(text(alphabet=self.text_alphabet()))
2740 value2 = d.draw(text(alphabet=self.text_alphabet()))
2741 tag1 = d.draw(binary(min_size=1))
2742 tag2 = d.draw(binary(min_size=1))
2743 obj1 = self.base_klass(value1)
2744 obj2 = self.base_klass(value2)
2745 self.assertEqual(obj1 == obj2, value1 == value2)
2746 self.assertEqual(obj1 != obj2, value1 != value2)
2747 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2748 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2749 obj1 = self.base_klass(value1, impl=tag1)
2750 obj2 = self.base_klass(value1, impl=tag2)
2751 self.assertEqual(obj1 == obj2, tag1 == tag2)
2752 self.assertEqual(obj1 != obj2, tag1 != tag2)
2754 @given(data_strategy())
2755 def test_bounds_satisfied(self, d):
2756 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2757 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2758 value = d.draw(text(
2759 alphabet=self.text_alphabet(),
2763 self.base_klass(value=value, bounds=(bound_min, bound_max))
2765 @given(data_strategy())
2766 def test_bounds_unsatisfied(self, d):
2767 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2768 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2769 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2770 with self.assertRaises(BoundsError) as err:
2771 self.base_klass(value=value, bounds=(bound_min, bound_max))
2773 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2774 with self.assertRaises(BoundsError) as err:
2775 self.base_klass(value=value, bounds=(bound_min, bound_max))
2778 @given(data_strategy())
2779 def test_call(self, d):
2788 ) = d.draw(string_values_strategy(self.text_alphabet()))
2789 obj_initial = self.base_klass(
2795 optional_initial or False,
2806 ) = d.draw(string_values_strategy(
2807 self.text_alphabet(),
2808 do_expl=impl_initial is None,
2810 if (default is None) and (obj_initial.default is not None):
2813 (bounds is None) and
2814 (value is not None) and
2815 (bounds_initial is not None) and
2816 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2820 (bounds is None) and
2821 (default is not None) and
2822 (bounds_initial is not None) and
2823 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2826 obj = obj_initial(value, bounds, impl, expl, default, optional)
2828 value_expected = default if value is None else value
2830 default_initial if value_expected is None
2833 self.assertEqual(obj, value_expected)
2834 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2835 self.assertEqual(obj.expl_tag, expl or expl_initial)
2838 default_initial if default is None else default,
2840 if obj.default is None:
2841 optional = optional_initial if optional is None else optional
2842 optional = False if optional is None else optional
2845 self.assertEqual(obj.optional, optional)
2847 (obj._bound_min, obj._bound_max),
2848 bounds or bounds_initial or (0, float("+inf")),
2851 @given(data_strategy())
2852 def test_copy(self, d):
2853 values = d.draw(string_values_strategy(self.text_alphabet()))
2854 obj = self.base_klass(*values)
2855 obj_copied = obj.copy()
2856 self.assert_copied_basic_fields(obj, obj_copied)
2857 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2858 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2859 self.assertEqual(obj._value, obj_copied._value)
2861 @given(data_strategy())
2862 def test_stripped(self, d):
2863 value = d.draw(text(alphabet=self.text_alphabet()))
2864 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2865 obj = self.base_klass(value, impl=tag_impl)
2866 with self.assertRaises(NotEnoughData):
2867 obj.decode(obj.encode()[:-1])
2869 @given(data_strategy())
2870 def test_stripped_expl(self, d):
2871 value = d.draw(text(alphabet=self.text_alphabet()))
2872 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2873 obj = self.base_klass(value, expl=tag_expl)
2874 with self.assertRaises(NotEnoughData):
2875 obj.decode(obj.encode()[:-1])
2878 integers(min_value=31),
2879 integers(min_value=0),
2882 def test_bad_tag(self, tag, offset, decode_path):
2883 decode_path = tuple(str(i) for i in decode_path)
2884 with self.assertRaises(DecodeError) as err:
2885 self.base_klass().decode(
2886 tag_encode(tag)[:-1],
2888 decode_path=decode_path,
2891 self.assertEqual(err.exception.offset, offset)
2892 self.assertEqual(err.exception.decode_path, decode_path)
2895 integers(min_value=128),
2896 integers(min_value=0),
2899 def test_bad_len(self, l, offset, decode_path):
2900 decode_path = tuple(str(i) for i in decode_path)
2901 with self.assertRaises(DecodeError) as err:
2902 self.base_klass().decode(
2903 self.base_klass.tag_default + len_encode(l)[:-1],
2905 decode_path=decode_path,
2908 self.assertEqual(err.exception.offset, offset)
2909 self.assertEqual(err.exception.decode_path, decode_path)
2912 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2913 integers(min_value=0),
2916 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2917 decode_path = tuple(str(i) for i in decode_path)
2918 value, bound_min = list(sorted(ints))
2920 class String(self.base_klass):
2921 # Multiply this value by four, to satisfy UTF-32 bounds
2922 # (4 bytes per character) validation
2923 bounds = (bound_min * 4, bound_min * 4)
2924 with self.assertRaises(DecodeError) as err:
2926 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2928 decode_path=decode_path,
2931 self.assertEqual(err.exception.offset, offset)
2932 self.assertEqual(err.exception.decode_path, decode_path)
2934 @given(data_strategy())
2935 def test_symmetric(self, d):
2936 values = d.draw(string_values_strategy(self.text_alphabet()))
2937 value = d.draw(text(alphabet=self.text_alphabet()))
2938 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2939 offset = d.draw(integers(min_value=0))
2940 tail_junk = d.draw(binary(max_size=5))
2941 _, _, _, _, default, optional, _decoded = values
2942 obj = self.base_klass(
2950 self.assertFalse(obj.expled)
2951 obj_encoded = obj.encode()
2952 obj_expled = obj(value, expl=tag_expl)
2953 self.assertTrue(obj_expled.expled)
2956 obj_expled_encoded = obj_expled.encode()
2957 obj_decoded, tail = obj_expled.decode(
2958 obj_expled_encoded + tail_junk,
2963 self.assertEqual(tail, tail_junk)
2964 self.assertEqual(obj_decoded, obj_expled)
2965 self.assertNotEqual(obj_decoded, obj)
2966 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2967 self.assertEqual(bytes(obj_decoded), bytes(obj))
2968 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2969 self.assertEqual(text_type(obj_decoded), text_type(obj))
2970 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2971 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2972 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2974 obj_decoded.expl_llen,
2975 len(len_encode(len(obj_encoded))),
2977 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2978 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2981 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2983 self.assertEqual(obj_decoded.expl_offset, offset)
2986 class TestUTF8String(StringMixin, CommonMixin, TestCase):
2987 base_klass = UTF8String
2990 class UnicodeDecodeErrorMixin(object):
2992 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
2996 def test_unicode_decode_error(self, cyrillic_text):
2997 with self.assertRaises(DecodeError):
2998 self.base_klass(cyrillic_text)
3001 class TestNumericString(StringMixin, CommonMixin, TestCase):
3002 base_klass = NumericString
3004 def text_alphabet(self):
3007 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3008 def test_non_numeric(self, cyrillic_text):
3009 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3010 self.base_klass(cyrillic_text)
3013 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3014 integers(min_value=0),
3017 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3018 decode_path = tuple(str(i) for i in decode_path)
3019 value, bound_min = list(sorted(ints))
3021 class String(self.base_klass):
3022 bounds = (bound_min, bound_min)
3023 with self.assertRaises(DecodeError) as err:
3025 self.base_klass(b"1" * value).encode(),
3027 decode_path=decode_path,
3030 self.assertEqual(err.exception.offset, offset)
3031 self.assertEqual(err.exception.decode_path, decode_path)
3034 class TestPrintableString(
3035 UnicodeDecodeErrorMixin,
3040 base_klass = PrintableString
3043 class TestTeletexString(
3044 UnicodeDecodeErrorMixin,
3049 base_klass = TeletexString
3052 class TestVideotexString(
3053 UnicodeDecodeErrorMixin,
3058 base_klass = VideotexString
3061 class TestIA5String(
3062 UnicodeDecodeErrorMixin,
3067 base_klass = IA5String
3070 class TestGraphicString(
3071 UnicodeDecodeErrorMixin,
3076 base_klass = GraphicString
3079 class TestVisibleString(
3080 UnicodeDecodeErrorMixin,
3085 base_klass = VisibleString
3087 def test_x690_vector(self):
3089 str(VisibleString().decode(hexdec("1A054A6F6E6573"))[0]),
3093 str(VisibleString().decode(
3094 hexdec("3A0904034A6F6E04026573"),
3095 ctx={"bered": True},
3100 str(VisibleString().decode(
3101 hexdec("3A8004034A6F6E040265730000"),
3102 ctx={"bered": True},
3108 class TestGeneralString(
3109 UnicodeDecodeErrorMixin,
3114 base_klass = GeneralString
3117 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3118 base_klass = UniversalString
3121 class TestBMPString(StringMixin, CommonMixin, TestCase):
3122 base_klass = BMPString
3126 def generalized_time_values_strategy(
3134 if draw(booleans()):
3135 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3137 value = value.replace(microsecond=0)
3139 if draw(booleans()):
3140 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3142 default = default.replace(microsecond=0)
3146 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3148 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3149 optional = draw(one_of(none(), booleans()))
3151 draw(integers(min_value=0)),
3152 draw(integers(min_value=0)),
3153 draw(integers(min_value=0)),
3155 return (value, impl, expl, default, optional, _decoded)
3158 class TimeMixin(object):
3159 def test_invalid_value_type(self):
3160 with self.assertRaises(InvalidValueType) as err:
3161 self.base_klass(datetime.now().timetuple())
3164 @given(data_strategy())
3165 def test_optional(self, d):
3166 default = d.draw(datetimes(
3167 min_value=self.min_datetime,
3168 max_value=self.max_datetime,
3170 optional = d.draw(booleans())
3171 obj = self.base_klass(default=default, optional=optional)
3172 self.assertTrue(obj.optional)
3174 @given(data_strategy())
3175 def test_ready(self, d):
3176 obj = self.base_klass()
3177 self.assertFalse(obj.ready)
3180 with self.assertRaises(ObjNotReady) as err:
3183 value = d.draw(datetimes(min_value=self.min_datetime))
3184 obj = self.base_klass(value)
3185 self.assertTrue(obj.ready)
3189 @given(data_strategy())
3190 def test_comparison(self, d):
3191 value1 = d.draw(datetimes(
3192 min_value=self.min_datetime,
3193 max_value=self.max_datetime,
3195 value2 = d.draw(datetimes(
3196 min_value=self.min_datetime,
3197 max_value=self.max_datetime,
3199 tag1 = d.draw(binary(min_size=1))
3200 tag2 = d.draw(binary(min_size=1))
3202 value1 = value1.replace(microsecond=0)
3203 value2 = value2.replace(microsecond=0)
3204 obj1 = self.base_klass(value1)
3205 obj2 = self.base_klass(value2)
3206 self.assertEqual(obj1 == obj2, value1 == value2)
3207 self.assertEqual(obj1 != obj2, value1 != value2)
3208 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3209 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3210 obj1 = self.base_klass(value1, impl=tag1)
3211 obj2 = self.base_klass(value1, impl=tag2)
3212 self.assertEqual(obj1 == obj2, tag1 == tag2)
3213 self.assertEqual(obj1 != obj2, tag1 != tag2)
3215 @given(data_strategy())
3216 def test_call(self, d):
3224 ) = d.draw(generalized_time_values_strategy(
3225 min_datetime=self.min_datetime,
3226 max_datetime=self.max_datetime,
3227 omit_ms=self.omit_ms,
3229 obj_initial = self.base_klass(
3230 value=value_initial,
3233 default=default_initial,
3234 optional=optional_initial or False,
3235 _decoded=_decoded_initial,
3244 ) = d.draw(generalized_time_values_strategy(
3245 min_datetime=self.min_datetime,
3246 max_datetime=self.max_datetime,
3247 omit_ms=self.omit_ms,
3248 do_expl=impl_initial is None,
3258 value_expected = default if value is None else value
3260 default_initial if value_expected is None
3263 self.assertEqual(obj, value_expected)
3264 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3265 self.assertEqual(obj.expl_tag, expl or expl_initial)
3268 default_initial if default is None else default,
3270 if obj.default is None:
3271 optional = optional_initial if optional is None else optional
3272 optional = False if optional is None else optional
3275 self.assertEqual(obj.optional, optional)
3277 @given(data_strategy())
3278 def test_copy(self, d):
3279 values = d.draw(generalized_time_values_strategy(
3280 min_datetime=self.min_datetime,
3281 max_datetime=self.max_datetime,
3283 obj = self.base_klass(*values)
3284 obj_copied = obj.copy()
3285 self.assert_copied_basic_fields(obj, obj_copied)
3286 self.assertEqual(obj._value, obj_copied._value)
3288 @given(data_strategy())
3289 def test_stripped(self, d):
3290 value = d.draw(datetimes(
3291 min_value=self.min_datetime,
3292 max_value=self.max_datetime,
3294 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3295 obj = self.base_klass(value, impl=tag_impl)
3296 with self.assertRaises(NotEnoughData):
3297 obj.decode(obj.encode()[:-1])
3299 @given(data_strategy())
3300 def test_stripped_expl(self, d):
3301 value = d.draw(datetimes(
3302 min_value=self.min_datetime,
3303 max_value=self.max_datetime,
3305 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3306 obj = self.base_klass(value, expl=tag_expl)
3307 with self.assertRaises(NotEnoughData):
3308 obj.decode(obj.encode()[:-1])
3310 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3311 @given(data_strategy())
3312 def test_symmetric(self, d):
3313 values = d.draw(generalized_time_values_strategy(
3314 min_datetime=self.min_datetime,
3315 max_datetime=self.max_datetime,
3317 value = d.draw(datetimes(
3318 min_value=self.min_datetime,
3319 max_value=self.max_datetime,
3321 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3322 offset = d.draw(integers(min_value=0))
3323 tail_junk = d.draw(binary(max_size=5))
3324 _, _, _, default, optional, _decoded = values
3325 obj = self.base_klass(
3333 self.assertFalse(obj.expled)
3334 obj_encoded = obj.encode()
3335 obj_expled = obj(value, expl=tag_expl)
3336 self.assertTrue(obj_expled.expled)
3339 obj_expled_encoded = obj_expled.encode()
3340 obj_decoded, tail = obj_expled.decode(
3341 obj_expled_encoded + tail_junk,
3346 self.assertEqual(tail, tail_junk)
3347 self.assertEqual(obj_decoded, obj_expled)
3348 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3349 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3350 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3351 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3352 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3354 obj_decoded.expl_llen,
3355 len(len_encode(len(obj_encoded))),
3357 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3358 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3361 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3363 self.assertEqual(obj_decoded.expl_offset, offset)
3366 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3367 base_klass = GeneralizedTime
3369 min_datetime = datetime(1900, 1, 1)
3370 max_datetime = datetime(9999, 12, 31)
3372 def test_go_vectors_invalid(self):
3384 b"-20100102030410Z",
3385 b"2010-0102030410Z",
3386 b"2010-0002030410Z",
3387 b"201001-02030410Z",
3388 b"20100102-030410Z",
3389 b"2010010203-0410Z",
3390 b"201001020304-10Z",
3391 # These ones are INVALID in *DER*, but accepted
3392 # by Go's encoding/asn1
3393 b"20100102030405+0607",
3394 b"20100102030405-0607",
3396 with self.assertRaises(DecodeError) as err:
3397 GeneralizedTime(data)
3400 def test_go_vectors_valid(self):
3402 GeneralizedTime(b"20100102030405Z").todatetime(),
3403 datetime(2010, 1, 2, 3, 4, 5, 0),
3407 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3408 base_klass = UTCTime
3410 min_datetime = datetime(2000, 1, 1)
3411 max_datetime = datetime(2049, 12, 31)
3413 def test_go_vectors_invalid(self):
3439 # These ones are INVALID in *DER*, but accepted
3440 # by Go's encoding/asn1
3441 b"910506164540-0700",
3442 b"910506164540+0730",
3446 with self.assertRaises(DecodeError) as err:
3450 def test_go_vectors_valid(self):
3452 UTCTime(b"910506234540Z").todatetime(),
3453 datetime(1991, 5, 6, 23, 45, 40, 0),
3456 @given(integers(min_value=0, max_value=49))
3457 def test_pre50(self, year):
3459 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3463 @given(integers(min_value=50, max_value=99))
3464 def test_post50(self, year):
3466 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3472 def any_values_strategy(draw, do_expl=False):
3473 value = draw(one_of(none(), binary()))
3476 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3477 optional = draw(one_of(none(), booleans()))
3479 draw(integers(min_value=0)),
3480 draw(integers(min_value=0)),
3481 draw(integers(min_value=0)),
3483 return (value, expl, optional, _decoded)
3486 class AnyInherited(Any):
3490 class TestAny(CommonMixin, TestCase):
3493 def test_invalid_value_type(self):
3494 with self.assertRaises(InvalidValueType) as err:
3499 def test_optional(self, optional):
3500 obj = Any(optional=optional)
3501 self.assertEqual(obj.optional, optional)
3504 def test_ready(self, value):
3506 self.assertFalse(obj.ready)
3509 with self.assertRaises(ObjNotReady) as err:
3513 self.assertTrue(obj.ready)
3518 def test_basic(self, value):
3519 integer_encoded = Integer(value).encode()
3521 Any(integer_encoded),
3522 Any(Integer(value)),
3523 Any(Any(Integer(value))),
3525 self.assertSequenceEqual(bytes(obj), integer_encoded)
3527 obj.decode(obj.encode())[0].vlen,
3528 len(integer_encoded),
3532 self.assertSequenceEqual(obj.encode(), integer_encoded)
3534 @given(binary(), binary())
3535 def test_comparison(self, value1, value2):
3536 for klass in (Any, AnyInherited):
3537 obj1 = klass(value1)
3538 obj2 = klass(value2)
3539 self.assertEqual(obj1 == obj2, value1 == value2)
3540 self.assertEqual(obj1 != obj2, value1 != value2)
3541 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3543 @given(data_strategy())
3544 def test_call(self, d):
3545 for klass in (Any, AnyInherited):
3551 ) = d.draw(any_values_strategy())
3552 obj_initial = klass(
3555 optional_initial or False,
3563 ) = d.draw(any_values_strategy(do_expl=True))
3564 obj = obj_initial(value, expl, optional)
3566 value_expected = None if value is None else value
3567 self.assertEqual(obj, value_expected)
3568 self.assertEqual(obj.expl_tag, expl or expl_initial)
3569 if obj.default is None:
3570 optional = optional_initial if optional is None else optional
3571 optional = False if optional is None else optional
3572 self.assertEqual(obj.optional, optional)
3574 def test_simultaneous_impl_expl(self):
3575 # override it, as Any does not have implicit tag
3578 def test_decoded(self):
3579 # override it, as Any does not have implicit tag
3582 @given(any_values_strategy())
3583 def test_copy(self, values):
3584 for klass in (Any, AnyInherited):
3585 obj = klass(*values)
3586 obj_copied = obj.copy()
3587 self.assert_copied_basic_fields(obj, obj_copied)
3588 self.assertEqual(obj._value, obj_copied._value)
3590 @given(binary().map(OctetString))
3591 def test_stripped(self, value):
3593 with self.assertRaises(NotEnoughData):
3594 obj.decode(obj.encode()[:-1])
3598 integers(min_value=1).map(tag_ctxc),
3600 def test_stripped_expl(self, value, tag_expl):
3601 obj = Any(value, expl=tag_expl)
3602 with self.assertRaises(NotEnoughData):
3603 obj.decode(obj.encode()[:-1])
3606 integers(min_value=31),
3607 integers(min_value=0),
3610 def test_bad_tag(self, tag, offset, decode_path):
3611 decode_path = tuple(str(i) for i in decode_path)
3612 with self.assertRaises(DecodeError) as err:
3614 tag_encode(tag)[:-1],
3616 decode_path=decode_path,
3619 self.assertEqual(err.exception.offset, offset)
3620 self.assertEqual(err.exception.decode_path, decode_path)
3623 integers(min_value=128),
3624 integers(min_value=0),
3627 def test_bad_len(self, l, offset, decode_path):
3628 decode_path = tuple(str(i) for i in decode_path)
3629 with self.assertRaises(DecodeError) as err:
3631 Any.tag_default + len_encode(l)[:-1],
3633 decode_path=decode_path,
3636 self.assertEqual(err.exception.offset, offset)
3637 self.assertEqual(err.exception.decode_path, decode_path)
3639 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3641 any_values_strategy(),
3642 integers().map(lambda x: Integer(x).encode()),
3643 integers(min_value=1).map(tag_ctxc),
3644 integers(min_value=0),
3647 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3648 for klass in (Any, AnyInherited):
3649 _, _, optional, _decoded = values
3650 obj = klass(value=value, optional=optional, _decoded=_decoded)
3653 self.assertFalse(obj.expled)
3654 obj_encoded = obj.encode()
3655 obj_expled = obj(value, expl=tag_expl)
3656 self.assertTrue(obj_expled.expled)
3659 obj_expled_encoded = obj_expled.encode()
3660 obj_decoded, tail = obj_expled.decode(
3661 obj_expled_encoded + tail_junk,
3666 self.assertEqual(tail, tail_junk)
3667 self.assertEqual(obj_decoded, obj_expled)
3668 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3669 self.assertEqual(bytes(obj_decoded), bytes(obj))
3670 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3671 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3672 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3674 obj_decoded.expl_llen,
3675 len(len_encode(len(obj_encoded))),
3677 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3678 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3681 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3683 self.assertEqual(obj_decoded.expl_offset, offset)
3684 self.assertEqual(obj_decoded.tlen, 0)
3685 self.assertEqual(obj_decoded.llen, 0)
3686 self.assertEqual(obj_decoded.vlen, len(value))
3690 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3692 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3693 tags = [tag_encode(tag) for tag in draw(sets(
3694 integers(min_value=0),
3695 min_size=len(names),
3696 max_size=len(names),
3698 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3700 if value_required or draw(booleans()):
3701 value = draw(tuples(
3702 sampled_from([name for name, _ in schema]),
3703 integers().map(Integer),
3707 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3708 default = draw(one_of(
3710 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3712 optional = draw(one_of(none(), booleans()))
3714 draw(integers(min_value=0)),
3715 draw(integers(min_value=0)),
3716 draw(integers(min_value=0)),
3718 return (schema, value, expl, default, optional, _decoded)
3721 class ChoiceInherited(Choice):
3725 class TestChoice(CommonMixin, TestCase):
3727 schema = (("whatever", Boolean()),)
3730 def test_schema_required(self):
3731 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3734 def test_impl_forbidden(self):
3735 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3736 Choice(impl=b"whatever")
3738 def test_invalid_value_type(self):
3739 with self.assertRaises(InvalidValueType) as err:
3740 self.base_klass(123)
3742 with self.assertRaises(ObjUnknown) as err:
3743 self.base_klass(("whenever", Boolean(False)))
3745 with self.assertRaises(InvalidValueType) as err:
3746 self.base_klass(("whatever", Integer(123)))
3750 def test_optional(self, optional):
3751 obj = self.base_klass(
3752 default=self.base_klass(("whatever", Boolean(False))),
3755 self.assertTrue(obj.optional)
3758 def test_ready(self, value):
3759 obj = self.base_klass()
3760 self.assertFalse(obj.ready)
3763 self.assertIsNone(obj["whatever"])
3764 with self.assertRaises(ObjNotReady) as err:
3767 obj["whatever"] = Boolean()
3768 self.assertFalse(obj.ready)
3771 obj["whatever"] = Boolean(value)
3772 self.assertTrue(obj.ready)
3776 @given(booleans(), booleans())
3777 def test_comparison(self, value1, value2):
3778 class WahlInherited(self.base_klass):
3780 for klass in (self.base_klass, WahlInherited):
3781 obj1 = klass(("whatever", Boolean(value1)))
3782 obj2 = klass(("whatever", Boolean(value2)))
3783 self.assertEqual(obj1 == obj2, value1 == value2)
3784 self.assertEqual(obj1 != obj2, value1 != value2)
3785 self.assertEqual(obj1 == obj2._value, value1 == value2)
3786 self.assertFalse(obj1 == obj2._value[1])
3788 @given(data_strategy())
3789 def test_call(self, d):
3790 for klass in (Choice, ChoiceInherited):
3798 ) = d.draw(choice_values_strategy())
3801 schema = schema_initial
3803 value=value_initial,
3805 default=default_initial,
3806 optional=optional_initial or False,
3807 _decoded=_decoded_initial,
3816 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
3817 obj = obj_initial(value, expl, default, optional)
3819 value_expected = default if value is None else value
3821 default_initial if value_expected is None
3824 self.assertEqual(obj.choice, value_expected[0])
3825 self.assertEqual(obj.value, int(value_expected[1]))
3826 self.assertEqual(obj.expl_tag, expl or expl_initial)
3827 default_expect = default_initial if default is None else default
3828 if default_expect is not None:
3829 self.assertEqual(obj.default.choice, default_expect[0])
3830 self.assertEqual(obj.default.value, int(default_expect[1]))
3831 if obj.default is None:
3832 optional = optional_initial if optional is None else optional
3833 optional = False if optional is None else optional
3836 self.assertEqual(obj.optional, optional)
3837 self.assertEqual(obj.specs, obj_initial.specs)
3839 def test_simultaneous_impl_expl(self):
3840 # override it, as Any does not have implicit tag
3843 def test_decoded(self):
3844 # override it, as Any does not have implicit tag
3847 @given(choice_values_strategy())
3848 def test_copy(self, values):
3849 _schema, value, expl, default, optional, _decoded = values
3851 class Wahl(self.base_klass):
3857 optional=optional or False,
3860 obj_copied = obj.copy()
3861 self.assertIsNone(obj.tag)
3862 self.assertIsNone(obj_copied.tag)
3863 # hack for assert_copied_basic_fields
3864 obj.tag = "whatever"
3865 obj_copied.tag = "whatever"
3866 self.assert_copied_basic_fields(obj, obj_copied)
3867 self.assertEqual(obj._value, obj_copied._value)
3868 self.assertEqual(obj.specs, obj_copied.specs)
3871 def test_stripped(self, value):
3872 obj = self.base_klass(("whatever", Boolean(value)))
3873 with self.assertRaises(NotEnoughData):
3874 obj.decode(obj.encode()[:-1])
3878 integers(min_value=1).map(tag_ctxc),
3880 def test_stripped_expl(self, value, tag_expl):
3881 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3882 with self.assertRaises(NotEnoughData):
3883 obj.decode(obj.encode()[:-1])
3885 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3886 @given(data_strategy())
3887 def test_symmetric(self, d):
3888 _schema, value, _, default, optional, _decoded = d.draw(
3889 choice_values_strategy(value_required=True)
3891 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3892 offset = d.draw(integers(min_value=0))
3893 tail_junk = d.draw(binary(max_size=5))
3895 class Wahl(self.base_klass):
3905 self.assertFalse(obj.expled)
3906 obj_encoded = obj.encode()
3907 obj_expled = obj(value, expl=tag_expl)
3908 self.assertTrue(obj_expled.expled)
3911 obj_expled_encoded = obj_expled.encode()
3912 obj_decoded, tail = obj_expled.decode(
3913 obj_expled_encoded + tail_junk,
3918 self.assertEqual(tail, tail_junk)
3919 self.assertEqual(obj_decoded, obj_expled)
3920 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3921 self.assertEqual(obj_decoded.value, obj_expled.value)
3922 self.assertEqual(obj_decoded.choice, obj.choice)
3923 self.assertEqual(obj_decoded.value, obj.value)
3924 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3925 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3926 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3928 obj_decoded.expl_llen,
3929 len(len_encode(len(obj_encoded))),
3931 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3932 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3935 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3937 self.assertEqual(obj_decoded.expl_offset, offset)
3938 self.assertSequenceEqual(
3940 obj_decoded.value.offset - offset:
3941 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3947 def test_set_get(self, value):
3950 ("erste", Boolean()),
3951 ("zweite", Integer()),
3954 with self.assertRaises(ObjUnknown) as err:
3955 obj["whatever"] = "whenever"
3956 with self.assertRaises(InvalidValueType) as err:
3957 obj["zweite"] = Boolean(False)
3958 obj["zweite"] = Integer(value)
3960 with self.assertRaises(ObjUnknown) as err:
3963 self.assertIsNone(obj["erste"])
3964 self.assertEqual(obj["zweite"], Integer(value))
3966 def test_tag_mismatch(self):
3969 ("erste", Boolean()),
3971 int_encoded = Integer(123).encode()
3972 bool_encoded = Boolean(False).encode()
3974 obj.decode(bool_encoded)
3975 with self.assertRaises(TagMismatch):
3976 obj.decode(int_encoded)
3978 def test_tag_mismatch_underlying(self):
3979 class SeqOfBoolean(SequenceOf):
3982 class SeqOfInteger(SequenceOf):
3987 ("erste", SeqOfBoolean()),
3990 int_encoded = SeqOfInteger((Integer(123),)).encode()
3991 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
3993 obj.decode(bool_encoded)
3994 with self.assertRaises(TagMismatch) as err:
3995 obj.decode(int_encoded)
3996 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4000 def seq_values_strategy(draw, seq_klass, do_expl=False):
4002 if draw(booleans()):
4005 k: v for k, v in draw(dictionaries(
4008 booleans().map(Boolean),
4009 integers().map(Integer),
4014 if draw(booleans()):
4015 schema = list(draw(dictionaries(
4018 booleans().map(Boolean),
4019 integers().map(Integer),
4025 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4027 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4029 if draw(booleans()):
4030 default = seq_klass()
4032 k: v for k, v in draw(dictionaries(
4035 booleans().map(Boolean),
4036 integers().map(Integer),
4040 optional = draw(one_of(none(), booleans()))
4042 draw(integers(min_value=0)),
4043 draw(integers(min_value=0)),
4044 draw(integers(min_value=0)),
4046 return (value, schema, impl, expl, default, optional, _decoded)
4050 def sequence_strategy(draw, seq_klass):
4051 inputs = draw(lists(
4053 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4054 tuples(just(Integer), integers(), one_of(none(), integers())),
4059 integers(min_value=1),
4060 min_size=len(inputs),
4061 max_size=len(inputs),
4064 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4065 for tag, expled in zip(tags, draw(lists(
4067 min_size=len(inputs),
4068 max_size=len(inputs),
4072 for i, optional in enumerate(draw(lists(
4073 sampled_from(("required", "optional", "empty")),
4074 min_size=len(inputs),
4075 max_size=len(inputs),
4077 if optional in ("optional", "empty"):
4078 inits[i]["optional"] = True
4079 if optional == "empty":
4081 empties = set(empties)
4082 names = list(draw(sets(
4084 min_size=len(inputs),
4085 max_size=len(inputs),
4088 for i, (klass, value, default) in enumerate(inputs):
4089 schema.append((names[i], klass(default=default, **inits[i])))
4090 seq_name = draw(text_letters())
4091 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4094 for i, (klass, value, default) in enumerate(inputs):
4101 "default_value": None if spec.default is None else default,
4105 expect["optional"] = True
4107 expect["presented"] = True
4108 expect["value"] = value
4110 expect["optional"] = True
4111 if default is not None and default == value:
4112 expect["presented"] = False
4113 seq[name] = klass(value)
4114 expects.append(expect)
4119 def sequences_strategy(draw, seq_klass):
4120 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4122 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4123 for tag, expled in zip(tags, draw(lists(
4130 i for i, is_default in enumerate(draw(lists(
4136 names = list(draw(sets(
4141 seq_expectses = draw(lists(
4142 sequence_strategy(seq_klass=seq_klass),
4146 seqs = [seq for seq, _ in seq_expectses]
4148 for i, (name, seq) in enumerate(zip(names, seqs)):
4151 seq(default=(seq if i in defaulted else None), **inits[i]),
4153 seq_name = draw(text_letters())
4154 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4157 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4160 "expects": expects_inner,
4163 seq_outer[name] = seq_inner
4164 if seq_outer.specs[name].default is None:
4165 expect["presented"] = True
4166 expect_outers.append(expect)
4167 return seq_outer, expect_outers
4170 class SeqMixing(object):
4171 def test_invalid_value_type(self):
4172 with self.assertRaises(InvalidValueType) as err:
4173 self.base_klass(123)
4176 def test_invalid_value_type_set(self):
4177 class Seq(self.base_klass):
4178 schema = (("whatever", Boolean()),)
4180 with self.assertRaises(InvalidValueType) as err:
4181 seq["whatever"] = Integer(123)
4185 def test_optional(self, optional):
4186 obj = self.base_klass(default=self.base_klass(), optional=optional)
4187 self.assertTrue(obj.optional)
4189 @given(data_strategy())
4190 def test_ready(self, d):
4192 str(i): v for i, v in enumerate(d.draw(lists(
4199 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4206 for name in d.draw(permutations(
4207 list(ready.keys()) + list(non_ready.keys()),
4209 schema_input.append((name, Boolean()))
4211 class Seq(self.base_klass):
4212 schema = tuple(schema_input)
4214 for name in ready.keys():
4216 seq[name] = Boolean()
4217 self.assertFalse(seq.ready)
4220 for name, value in ready.items():
4221 seq[name] = Boolean(value)
4222 self.assertFalse(seq.ready)
4225 with self.assertRaises(ObjNotReady) as err:
4228 for name, value in non_ready.items():
4229 seq[name] = Boolean(value)
4230 self.assertTrue(seq.ready)
4234 @given(data_strategy())
4235 def test_call(self, d):
4236 class SeqInherited(self.base_klass):
4238 for klass in (self.base_klass, SeqInherited):
4247 ) = d.draw(seq_values_strategy(seq_klass=klass))
4248 obj_initial = klass(
4254 optional_initial or False,
4265 ) = d.draw(seq_values_strategy(
4267 do_expl=impl_initial is None,
4269 obj = obj_initial(value, impl, expl, default, optional)
4270 value_expected = default if value is None else value
4272 default_initial if value_expected is None
4275 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4276 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4277 self.assertEqual(obj.expl_tag, expl or expl_initial)
4279 {} if obj.default is None else obj.default._value,
4280 getattr(default_initial if default is None else default, "_value", {}),
4282 if obj.default is None:
4283 optional = optional_initial if optional is None else optional
4284 optional = False if optional is None else optional
4287 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4288 self.assertEqual(obj.optional, optional)
4290 @given(data_strategy())
4291 def test_copy(self, d):
4292 class SeqInherited(self.base_klass):
4294 for klass in (self.base_klass, SeqInherited):
4295 values = d.draw(seq_values_strategy(seq_klass=klass))
4296 obj = klass(*values)
4297 obj_copied = obj.copy()
4298 self.assert_copied_basic_fields(obj, obj_copied)
4299 self.assertEqual(obj.specs, obj_copied.specs)
4300 self.assertEqual(obj._value, obj_copied._value)
4302 @given(data_strategy())
4303 def test_stripped(self, d):
4304 value = d.draw(integers())
4305 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4307 class Seq(self.base_klass):
4309 schema = (("whatever", Integer()),)
4311 seq["whatever"] = Integer(value)
4312 with self.assertRaises(NotEnoughData):
4313 seq.decode(seq.encode()[:-1])
4315 @given(data_strategy())
4316 def test_stripped_expl(self, d):
4317 value = d.draw(integers())
4318 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4320 class Seq(self.base_klass):
4322 schema = (("whatever", Integer()),)
4324 seq["whatever"] = Integer(value)
4325 with self.assertRaises(NotEnoughData):
4326 seq.decode(seq.encode()[:-1])
4328 @given(binary(min_size=2))
4329 def test_non_tag_mismatch_raised(self, junk):
4331 _, _, len_encoded = tag_strip(memoryview(junk))
4332 len_decode(len_encoded)
4338 class Seq(self.base_klass):
4340 ("whatever", Integer()),
4342 ("whenever", Integer()),
4345 seq["whatever"] = Integer(123)
4346 seq["junk"] = Any(junk)
4347 seq["whenever"] = Integer(123)
4348 with self.assertRaises(DecodeError):
4349 seq.decode(seq.encode())
4352 integers(min_value=31),
4353 integers(min_value=0),
4356 def test_bad_tag(self, tag, offset, decode_path):
4357 decode_path = tuple(str(i) for i in decode_path)
4358 with self.assertRaises(DecodeError) as err:
4359 self.base_klass().decode(
4360 tag_encode(tag)[:-1],
4362 decode_path=decode_path,
4365 self.assertEqual(err.exception.offset, offset)
4366 self.assertEqual(err.exception.decode_path, decode_path)
4369 integers(min_value=128),
4370 integers(min_value=0),
4373 def test_bad_len(self, l, offset, decode_path):
4374 decode_path = tuple(str(i) for i in decode_path)
4375 with self.assertRaises(DecodeError) as err:
4376 self.base_klass().decode(
4377 self.base_klass.tag_default + len_encode(l)[:-1],
4379 decode_path=decode_path,
4382 self.assertEqual(err.exception.offset, offset)
4383 self.assertEqual(err.exception.decode_path, decode_path)
4385 def _assert_expects(self, seq, expects):
4386 for expect in expects:
4388 seq.specs[expect["name"]].optional,
4391 if expect["default_value"] is not None:
4393 seq.specs[expect["name"]].default,
4394 expect["default_value"],
4396 if expect["presented"]:
4397 self.assertIn(expect["name"], seq)
4398 self.assertEqual(seq[expect["name"]], expect["value"])
4400 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4401 @given(data_strategy())
4402 def test_symmetric(self, d):
4403 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4404 tail_junk = d.draw(binary(max_size=5))
4405 self.assertTrue(seq.ready)
4406 self.assertFalse(seq.decoded)
4407 self._assert_expects(seq, expects)
4410 seq_encoded = seq.encode()
4411 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4412 self.assertEqual(tail, tail_junk)
4413 self.assertTrue(seq.ready)
4414 self._assert_expects(seq_decoded, expects)
4415 self.assertEqual(seq, seq_decoded)
4416 self.assertEqual(seq_decoded.encode(), seq_encoded)
4417 for expect in expects:
4418 if not expect["presented"]:
4419 self.assertNotIn(expect["name"], seq_decoded)
4421 self.assertIn(expect["name"], seq_decoded)
4422 obj = seq_decoded[expect["name"]]
4423 self.assertTrue(obj.decoded)
4424 offset = obj.expl_offset if obj.expled else obj.offset
4425 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4426 self.assertSequenceEqual(
4427 seq_encoded[offset:offset + tlvlen],
4431 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4432 @given(data_strategy())
4433 def test_symmetric_with_seq(self, d):
4434 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4435 self.assertTrue(seq.ready)
4436 seq_encoded = seq.encode()
4437 seq_decoded, tail = seq.decode(seq_encoded)
4438 self.assertEqual(tail, b"")
4439 self.assertTrue(seq.ready)
4440 self.assertEqual(seq, seq_decoded)
4441 self.assertEqual(seq_decoded.encode(), seq_encoded)
4442 for expect_outer in expect_outers:
4443 if not expect_outer["presented"]:
4444 self.assertNotIn(expect_outer["name"], seq_decoded)
4446 self.assertIn(expect_outer["name"], seq_decoded)
4447 obj = seq_decoded[expect_outer["name"]]
4448 self.assertTrue(obj.decoded)
4449 offset = obj.expl_offset if obj.expled else obj.offset
4450 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4451 self.assertSequenceEqual(
4452 seq_encoded[offset:offset + tlvlen],
4455 self._assert_expects(obj, expect_outer["expects"])
4457 @given(data_strategy())
4458 def test_default_disappears(self, d):
4459 _schema = list(d.draw(dictionaries(
4461 sets(integers(), min_size=2, max_size=2),
4465 class Seq(self.base_klass):
4467 (n, Integer(default=d))
4468 for n, (_, d) in _schema
4471 for name, (value, _) in _schema:
4472 seq[name] = Integer(value)
4473 self.assertEqual(len(seq._value), len(_schema))
4474 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4475 self.assertGreater(len(seq.encode()), len(empty_seq))
4476 for name, (_, default) in _schema:
4477 seq[name] = Integer(default)
4478 self.assertEqual(len(seq._value), 0)
4479 self.assertSequenceEqual(seq.encode(), empty_seq)
4481 @given(data_strategy())
4482 def test_encoded_default_accepted(self, d):
4483 _schema = list(d.draw(dictionaries(
4488 tags = [tag_encode(tag) for tag in d.draw(sets(
4489 integers(min_value=0),
4490 min_size=len(_schema),
4491 max_size=len(_schema),
4494 class SeqWithoutDefault(self.base_klass):
4496 (n, Integer(impl=t))
4497 for (n, _), t in zip(_schema, tags)
4499 seq_without_default = SeqWithoutDefault()
4500 for name, value in _schema:
4501 seq_without_default[name] = Integer(value)
4502 seq_encoded = seq_without_default.encode()
4504 class SeqWithDefault(self.base_klass):
4506 (n, Integer(default=v, impl=t))
4507 for (n, v), t in zip(_schema, tags)
4509 seq_with_default = SeqWithDefault()
4510 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4511 for name, value in _schema:
4512 self.assertEqual(seq_decoded[name], seq_with_default[name])
4513 self.assertEqual(seq_decoded[name], value)
4515 @given(data_strategy())
4516 def test_missing_from_spec(self, d):
4517 names = list(d.draw(sets(text_letters(), min_size=2)))
4518 tags = [tag_encode(tag) for tag in d.draw(sets(
4519 integers(min_value=0),
4520 min_size=len(names),
4521 max_size=len(names),
4523 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4525 class SeqFull(self.base_klass):
4526 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4527 seq_full = SeqFull()
4528 for i, name in enumerate(names):
4529 seq_full[name] = Integer(i)
4530 seq_encoded = seq_full.encode()
4531 altered = names_tags[:-2] + names_tags[-1:]
4533 class SeqMissing(self.base_klass):
4534 schema = [(n, Integer(impl=t)) for n, t in altered]
4535 seq_missing = SeqMissing()
4536 with self.assertRaises(TagMismatch):
4537 seq_missing.decode(seq_encoded)
4540 class TestSequence(SeqMixing, CommonMixin, TestCase):
4541 base_klass = Sequence
4547 def test_remaining(self, value, junk):
4548 class Seq(Sequence):
4550 ("whatever", Integer()),
4552 int_encoded = Integer(value).encode()
4554 Sequence.tag_default,
4555 len_encode(len(int_encoded + junk)),
4558 with assertRaisesRegex(self, DecodeError, "remaining"):
4559 Seq().decode(junked)
4561 @given(sets(text_letters(), min_size=2))
4562 def test_obj_unknown(self, names):
4563 missing = names.pop()
4565 class Seq(Sequence):
4566 schema = [(n, Boolean()) for n in names]
4568 with self.assertRaises(ObjUnknown) as err:
4571 with self.assertRaises(ObjUnknown) as err:
4572 seq[missing] = Boolean()
4575 def test_x690_vector(self):
4576 class Seq(Sequence):
4578 ("name", IA5String()),
4581 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4582 self.assertEqual(seq["name"], "Smith")
4583 self.assertEqual(seq["ok"], True)
4586 class TestSet(SeqMixing, CommonMixin, TestCase):
4589 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4590 @given(data_strategy())
4591 def test_sorted(self, d):
4593 tag_encode(tag) for tag in
4594 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4598 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4600 for name, _ in Seq.schema:
4601 seq[name] = OctetString(b"")
4602 seq_encoded = seq.encode()
4603 seq_decoded, _ = seq.decode(seq_encoded)
4604 self.assertSequenceEqual(
4605 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4606 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4611 def seqof_values_strategy(draw, schema=None, do_expl=False):
4613 schema = draw(sampled_from((Boolean(), Integer())))
4614 bound_min, bound_max = sorted(draw(sets(
4615 integers(min_value=0, max_value=10),
4619 if isinstance(schema, Boolean):
4620 values_generator = booleans().map(Boolean)
4621 elif isinstance(schema, Integer):
4622 values_generator = integers().map(Integer)
4623 values_generator = lists(
4628 values = draw(one_of(none(), values_generator))
4632 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4634 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4635 default = draw(one_of(none(), values_generator))
4636 optional = draw(one_of(none(), booleans()))
4638 draw(integers(min_value=0)),
4639 draw(integers(min_value=0)),
4640 draw(integers(min_value=0)),
4645 (bound_min, bound_max),
4654 class SeqOfMixing(object):
4655 def test_invalid_value_type(self):
4656 with self.assertRaises(InvalidValueType) as err:
4657 self.base_klass(123)
4660 def test_invalid_values_type(self):
4661 class SeqOf(self.base_klass):
4663 with self.assertRaises(InvalidValueType) as err:
4664 SeqOf([Integer(123), Boolean(False), Integer(234)])
4667 def test_schema_required(self):
4668 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4669 self.base_klass.__mro__[1]()
4671 @given(booleans(), booleans(), binary(), binary())
4672 def test_comparison(self, value1, value2, tag1, tag2):
4673 class SeqOf(self.base_klass):
4675 obj1 = SeqOf([Boolean(value1)])
4676 obj2 = SeqOf([Boolean(value2)])
4677 self.assertEqual(obj1 == obj2, value1 == value2)
4678 self.assertEqual(obj1 != obj2, value1 != value2)
4679 self.assertEqual(obj1 == list(obj2), value1 == value2)
4680 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4681 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4682 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4683 self.assertEqual(obj1 == obj2, tag1 == tag2)
4684 self.assertEqual(obj1 != obj2, tag1 != tag2)
4686 @given(lists(booleans()))
4687 def test_iter(self, values):
4688 class SeqOf(self.base_klass):
4690 obj = SeqOf([Boolean(value) for value in values])
4691 self.assertEqual(len(obj), len(values))
4692 for i, value in enumerate(obj):
4693 self.assertEqual(value, values[i])
4695 @given(data_strategy())
4696 def test_ready(self, d):
4697 ready = [Integer(v) for v in d.draw(lists(
4704 range(d.draw(integers(min_value=1, max_value=5)))
4707 class SeqOf(self.base_klass):
4709 values = d.draw(permutations(ready + non_ready))
4711 for value in values:
4713 self.assertFalse(seqof.ready)
4716 with self.assertRaises(ObjNotReady) as err:
4719 for i, value in enumerate(values):
4720 self.assertEqual(seqof[i], value)
4721 if not seqof[i].ready:
4722 seqof[i] = Integer(i)
4723 self.assertTrue(seqof.ready)
4727 def test_spec_mismatch(self):
4728 class SeqOf(self.base_klass):
4731 seqof.append(Integer(123))
4732 with self.assertRaises(ValueError):
4733 seqof.append(Boolean(False))
4734 with self.assertRaises(ValueError):
4735 seqof[0] = Boolean(False)
4737 @given(data_strategy())
4738 def test_bounds_satisfied(self, d):
4739 class SeqOf(self.base_klass):
4741 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4742 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4743 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4744 SeqOf(value=value, bounds=(bound_min, bound_max))
4746 @given(data_strategy())
4747 def test_bounds_unsatisfied(self, d):
4748 class SeqOf(self.base_klass):
4750 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4751 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4752 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4753 with self.assertRaises(BoundsError) as err:
4754 SeqOf(value=value, bounds=(bound_min, bound_max))
4756 value = [Boolean()] * d.draw(integers(
4757 min_value=bound_max + 1,
4758 max_value=bound_max + 10,
4760 with self.assertRaises(BoundsError) as err:
4761 SeqOf(value=value, bounds=(bound_min, bound_max))
4764 @given(integers(min_value=1, max_value=10))
4765 def test_out_of_bounds(self, bound_max):
4766 class SeqOf(self.base_klass):
4768 bounds = (0, bound_max)
4770 for _ in range(bound_max):
4771 seqof.append(Integer(123))
4772 with self.assertRaises(BoundsError):
4773 seqof.append(Integer(123))
4775 @given(data_strategy())
4776 def test_call(self, d):
4786 ) = d.draw(seqof_values_strategy())
4788 class SeqOf(self.base_klass):
4789 schema = schema_initial
4790 obj_initial = SeqOf(
4791 value=value_initial,
4792 bounds=bounds_initial,
4795 default=default_initial,
4796 optional=optional_initial or False,
4797 _decoded=_decoded_initial,
4808 ) = d.draw(seqof_values_strategy(
4809 schema=schema_initial,
4810 do_expl=impl_initial is None,
4812 if (default is None) and (obj_initial.default is not None):
4815 (bounds is None) and
4816 (value is not None) and
4817 (bounds_initial is not None) and
4818 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4822 (bounds is None) and
4823 (default is not None) and
4824 (bounds_initial is not None) and
4825 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4837 value_expected = default if value is None else value
4839 default_initial if value_expected is None
4842 value_expected = () if value_expected is None else value_expected
4843 self.assertEqual(obj, value_expected)
4844 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4845 self.assertEqual(obj.expl_tag, expl or expl_initial)
4848 default_initial if default is None else default,
4850 if obj.default is None:
4851 optional = optional_initial if optional is None else optional
4852 optional = False if optional is None else optional
4855 self.assertEqual(obj.optional, optional)
4857 (obj._bound_min, obj._bound_max),
4858 bounds or bounds_initial or (0, float("+inf")),
4861 @given(seqof_values_strategy())
4862 def test_copy(self, values):
4863 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4865 class SeqOf(self.base_klass):
4873 optional=optional or False,
4876 obj_copied = obj.copy()
4877 self.assert_copied_basic_fields(obj, obj_copied)
4878 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4879 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4880 self.assertEqual(obj._value, obj_copied._value)
4884 integers(min_value=1).map(tag_encode),
4886 def test_stripped(self, values, tag_impl):
4887 class SeqOf(self.base_klass):
4888 schema = OctetString()
4889 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4890 with self.assertRaises(NotEnoughData):
4891 obj.decode(obj.encode()[:-1])
4895 integers(min_value=1).map(tag_ctxc),
4897 def test_stripped_expl(self, values, tag_expl):
4898 class SeqOf(self.base_klass):
4899 schema = OctetString()
4900 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4901 with self.assertRaises(NotEnoughData):
4902 obj.decode(obj.encode()[:-1])
4905 integers(min_value=31),
4906 integers(min_value=0),
4909 def test_bad_tag(self, tag, offset, decode_path):
4910 decode_path = tuple(str(i) for i in decode_path)
4911 with self.assertRaises(DecodeError) as err:
4912 self.base_klass().decode(
4913 tag_encode(tag)[:-1],
4915 decode_path=decode_path,
4918 self.assertEqual(err.exception.offset, offset)
4919 self.assertEqual(err.exception.decode_path, decode_path)
4922 integers(min_value=128),
4923 integers(min_value=0),
4926 def test_bad_len(self, l, offset, decode_path):
4927 decode_path = tuple(str(i) for i in decode_path)
4928 with self.assertRaises(DecodeError) as err:
4929 self.base_klass().decode(
4930 self.base_klass.tag_default + len_encode(l)[:-1],
4932 decode_path=decode_path,
4935 self.assertEqual(err.exception.offset, offset)
4936 self.assertEqual(err.exception.decode_path, decode_path)
4938 @given(binary(min_size=1))
4939 def test_tag_mismatch(self, impl):
4940 assume(impl != self.base_klass.tag_default)
4941 with self.assertRaises(TagMismatch):
4942 self.base_klass(impl=impl).decode(self.base_klass().encode())
4944 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4946 seqof_values_strategy(schema=Integer()),
4947 lists(integers().map(Integer)),
4948 integers(min_value=1).map(tag_ctxc),
4949 integers(min_value=0),
4952 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4953 _, _, _, _, _, default, optional, _decoded = values
4955 class SeqOf(self.base_klass):
4965 self.assertFalse(obj.expled)
4966 obj_encoded = obj.encode()
4967 obj_expled = obj(value, expl=tag_expl)
4968 self.assertTrue(obj_expled.expled)
4971 obj_expled_encoded = obj_expled.encode()
4972 obj_decoded, tail = obj_expled.decode(
4973 obj_expled_encoded + tail_junk,
4978 self.assertEqual(tail, tail_junk)
4979 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
4980 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4981 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4982 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4984 obj_decoded.expl_llen,
4985 len(len_encode(len(obj_encoded))),
4987 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4988 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4991 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4993 self.assertEqual(obj_decoded.expl_offset, offset)
4994 for obj_inner in obj_decoded:
4995 self.assertIn(obj_inner, obj_decoded)
4996 self.assertSequenceEqual(
4999 obj_inner.offset - offset:
5000 obj_inner.offset + obj_inner.tlvlen - offset
5005 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5006 class SeqOf(SequenceOf):
5010 def _test_symmetric_compare_objs(self, obj1, obj2):
5011 self.assertEqual(obj1, obj2)
5012 self.assertSequenceEqual(list(obj1), list(obj2))
5015 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5020 def _test_symmetric_compare_objs(self, obj1, obj2):
5021 self.assertSetEqual(
5022 set(int(v) for v in obj1),
5023 set(int(v) for v in obj2),
5026 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5027 @given(data_strategy())
5028 def test_sorted(self, d):
5029 values = [OctetString(v) for v in d.draw(lists(binary()))]
5032 schema = OctetString()
5034 seq_encoded = seq.encode()
5035 seq_decoded, _ = seq.decode(seq_encoded)
5036 self.assertSequenceEqual(
5037 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5038 b"".join(sorted([v.encode() for v in values])),
5042 class TestGoMarshalVectors(TestCase):
5044 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5045 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5046 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5047 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5048 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5050 class Seq(Sequence):
5052 ("erste", Integer()),
5053 ("zweite", Integer(optional=True))
5056 seq["erste"] = Integer(64)
5057 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5058 seq["erste"] = Integer(0x123456)
5059 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5060 seq["erste"] = Integer(64)
5061 seq["zweite"] = Integer(65)
5062 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5064 class NestedSeq(Sequence):
5068 seq["erste"] = Integer(127)
5069 seq["zweite"] = None
5070 nested = NestedSeq()
5071 nested["nest"] = seq
5072 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5074 self.assertSequenceEqual(
5075 OctetString(b"\x01\x02\x03").encode(),
5076 hexdec("0403010203"),
5079 class Seq(Sequence):
5081 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5084 seq["erste"] = Integer(64)
5085 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5087 class Seq(Sequence):
5089 ("erste", Integer(expl=tag_ctxc(5))),
5092 seq["erste"] = Integer(64)
5093 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5095 class Seq(Sequence):
5098 impl=tag_encode(0, klass=TagClassContext),
5103 seq["erste"] = Null()
5104 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5106 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5108 self.assertSequenceEqual(
5109 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5110 hexdec("170d3730303130313030303030305a"),
5112 self.assertSequenceEqual(
5113 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5114 hexdec("170d3039313131353232353631365a"),
5116 self.assertSequenceEqual(
5117 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5118 hexdec("180f32313030303430353132303130315a"),
5121 class Seq(Sequence):
5123 ("erste", GeneralizedTime()),
5126 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5127 self.assertSequenceEqual(
5129 hexdec("3011180f32303039313131353232353631365a"),
5132 self.assertSequenceEqual(
5133 BitString((1, b"\x80")).encode(),
5136 self.assertSequenceEqual(
5137 BitString((12, b"\x81\xF0")).encode(),
5138 hexdec("03030481f0"),
5141 self.assertSequenceEqual(
5142 ObjectIdentifier("1.2.3.4").encode(),
5143 hexdec("06032a0304"),
5145 self.assertSequenceEqual(
5146 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5147 hexdec("06092a864888932d010105"),
5149 self.assertSequenceEqual(
5150 ObjectIdentifier("2.100.3").encode(),
5151 hexdec("0603813403"),
5154 self.assertSequenceEqual(
5155 PrintableString("test").encode(),
5156 hexdec("130474657374"),
5158 self.assertSequenceEqual(
5159 PrintableString("x" * 127).encode(),
5160 hexdec("137F" + "78" * 127),
5162 self.assertSequenceEqual(
5163 PrintableString("x" * 128).encode(),
5164 hexdec("138180" + "78" * 128),
5166 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5168 class Seq(Sequence):
5170 ("erste", IA5String()),
5173 seq["erste"] = IA5String("test")
5174 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5176 class Seq(Sequence):
5178 ("erste", PrintableString()),
5181 seq["erste"] = PrintableString("test")
5182 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5183 seq["erste"] = PrintableString("test*")
5184 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5186 class Seq(Sequence):
5188 ("erste", Any(optional=True)),
5189 ("zweite", Integer()),
5192 seq["zweite"] = Integer(64)
5193 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5198 seq.append(Integer(10))
5199 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5201 class _SeqOf(SequenceOf):
5202 schema = PrintableString()
5204 class SeqOf(SequenceOf):
5207 _seqof.append(PrintableString("1"))
5209 seqof.append(_seqof)
5210 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5212 class Seq(Sequence):
5214 ("erste", Integer(default=1)),
5217 seq["erste"] = Integer(0)
5218 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5219 seq["erste"] = Integer(1)
5220 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5221 seq["erste"] = Integer(2)
5222 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5225 class TestPP(TestCase):
5226 @given(data_strategy())
5227 def test_oid_printing(self, d):
5229 str(ObjectIdentifier(k)): v * 2
5230 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5232 chosen = d.draw(sampled_from(sorted(oids)))
5233 chosen_id = oids[chosen]
5234 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5235 self.assertNotIn(chosen_id, pp_console_row(pp))
5236 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5239 class TestAutoAddSlots(TestCase):
5241 class Inher(Integer):
5244 with self.assertRaises(AttributeError):
5246 inher.unexistent = "whatever"
5249 class TestOIDDefines(TestCase):
5250 @given(data_strategy())
5251 def runTest(self, d):
5252 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5253 value_name_chosen = d.draw(sampled_from(value_names))
5255 ObjectIdentifier(oid)
5256 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5258 oid_chosen = d.draw(sampled_from(oids))
5259 values = d.draw(lists(
5261 min_size=len(value_names),
5262 max_size=len(value_names),
5265 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5266 oid: Integer() for oid in oids[:-1]
5269 for i, value_name in enumerate(value_names):
5270 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5272 class Seq(Sequence):
5275 for value_name, value in zip(value_names, values):
5276 seq[value_name] = Any(Integer(value).encode())
5277 seq["type"] = oid_chosen
5278 seq, _ = Seq().decode(seq.encode())
5279 for value_name in value_names:
5280 if value_name == value_name_chosen:
5282 self.assertIsNone(seq[value_name].defined)
5283 if value_name_chosen in oids[:-1]:
5284 self.assertIsNotNone(seq[value_name_chosen].defined)
5285 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5286 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5289 class TestDefinesByPath(TestCase):
5290 def test_generated(self):
5291 class Seq(Sequence):
5293 ("type", ObjectIdentifier()),
5294 ("value", OctetString(expl=tag_ctxc(123))),
5297 class SeqInner(Sequence):
5299 ("typeInner", ObjectIdentifier()),
5300 ("valueInner", Any()),
5303 class PairValue(SetOf):
5306 class Pair(Sequence):
5308 ("type", ObjectIdentifier()),
5309 ("value", PairValue()),
5312 class Pairs(SequenceOf):
5319 type_octet_stringed,
5321 ObjectIdentifier(oid)
5322 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5324 seq_integered = Seq()
5325 seq_integered["type"] = type_integered
5326 seq_integered["value"] = OctetString(Integer(123).encode())
5327 seq_integered_raw = seq_integered.encode()
5331 (type_octet_stringed, OctetString(b"whatever")),
5332 (type_integered, Integer(123)),
5333 (type_octet_stringed, OctetString(b"whenever")),
5334 (type_integered, Integer(234)),
5336 for t, v in pairs_input:
5339 pair["value"] = PairValue((Any(v),))
5341 seq_inner = SeqInner()
5342 seq_inner["typeInner"] = type_innered
5343 seq_inner["valueInner"] = Any(pairs)
5344 seq_sequenced = Seq()
5345 seq_sequenced["type"] = type_sequenced
5346 seq_sequenced["value"] = OctetString(seq_inner.encode())
5347 seq_sequenced_raw = seq_sequenced.encode()
5349 defines_by_path = []
5350 seq_integered, _ = Seq().decode(seq_integered_raw)
5351 self.assertIsNone(seq_integered["value"].defined)
5352 defines_by_path.append(
5353 (("type",), ((("value",), {
5354 type_integered: Integer(),
5355 type_sequenced: SeqInner(),
5358 seq_integered, _ = Seq().decode(
5360 ctx={"defines_by_path": defines_by_path},
5362 self.assertIsNotNone(seq_integered["value"].defined)
5363 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5364 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5365 self.assertTrue(seq_integered_raw[
5366 seq_integered["value"].defined[1].offset:
5367 ].startswith(Integer(123).encode()))
5369 seq_sequenced, _ = Seq().decode(
5371 ctx={"defines_by_path": defines_by_path},
5373 self.assertIsNotNone(seq_sequenced["value"].defined)
5374 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5375 seq_inner = seq_sequenced["value"].defined[1]
5376 self.assertIsNone(seq_inner["valueInner"].defined)
5378 defines_by_path.append((
5379 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5380 ((("valueInner",), {type_innered: Pairs()}),),
5382 seq_sequenced, _ = Seq().decode(
5384 ctx={"defines_by_path": defines_by_path},
5386 self.assertIsNotNone(seq_sequenced["value"].defined)
5387 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5388 seq_inner = seq_sequenced["value"].defined[1]
5389 self.assertIsNotNone(seq_inner["valueInner"].defined)
5390 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5391 pairs = seq_inner["valueInner"].defined[1]
5393 self.assertIsNone(pair["value"][0].defined)
5395 defines_by_path.append((
5398 DecodePathDefBy(type_sequenced),
5400 DecodePathDefBy(type_innered),
5405 type_integered: Integer(),
5406 type_octet_stringed: OctetString(),
5409 seq_sequenced, _ = Seq().decode(
5411 ctx={"defines_by_path": defines_by_path},
5413 self.assertIsNotNone(seq_sequenced["value"].defined)
5414 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5415 seq_inner = seq_sequenced["value"].defined[1]
5416 self.assertIsNotNone(seq_inner["valueInner"].defined)
5417 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5418 pairs_got = seq_inner["valueInner"].defined[1]
5419 for pair_input, pair_got in zip(pairs_input, pairs_got):
5420 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5421 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5423 @given(oid_strategy(), integers())
5424 def test_simple(self, oid, tgt):
5425 class Inner(Sequence):
5427 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5428 ObjectIdentifier(oid): Integer(),
5432 class Outer(Sequence):
5435 ("tgt", OctetString()),
5439 inner["oid"] = ObjectIdentifier(oid)
5441 outer["inner"] = inner
5442 outer["tgt"] = OctetString(Integer(tgt).encode())
5443 decoded, _ = Outer().decode(outer.encode())
5444 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5447 class TestAbsDecodePath(TestCase):
5449 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5450 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5452 def test_concat(self, decode_path, rel_path):
5453 self.assertSequenceEqual(
5454 abs_decode_path(decode_path, rel_path),
5455 decode_path + rel_path,
5459 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5460 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5462 def test_abs(self, decode_path, rel_path):
5463 self.assertSequenceEqual(
5464 abs_decode_path(decode_path, ("/",) + rel_path),
5469 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5470 integers(min_value=1, max_value=3),
5471 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5473 def test_dots(self, decode_path, number_of_dots, rel_path):
5474 self.assertSequenceEqual(
5475 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5476 decode_path[:-number_of_dots] + rel_path,
5480 class TestStrictDefaultExistence(TestCase):
5481 @given(data_strategy())
5482 def runTest(self, d):
5483 count = d.draw(integers(min_value=1, max_value=10))
5484 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5486 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5487 for i in range(count)
5490 class Seq(Sequence):
5493 for i in range(count):
5494 seq["int%d" % i] = Integer(123)
5496 chosen = "int%d" % chosen
5497 seq.specs[chosen] = seq.specs[chosen](default=123)
5499 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5500 seq.decode(raw, ctx={"strict_default_existence": True})
5503 class TestX690PrefixedType(TestCase):
5505 self.assertSequenceEqual(
5506 VisibleString("Jones").encode(),
5507 hexdec("1A054A6F6E6573"),
5509 self.assertSequenceEqual(
5512 impl=tag_encode(3, klass=TagClassApplication),
5514 hexdec("43054A6F6E6573"),
5516 self.assertSequenceEqual(
5520 impl=tag_encode(3, klass=TagClassApplication),
5524 hexdec("A20743054A6F6E6573"),
5526 self.assertSequenceEqual(
5530 impl=tag_encode(3, klass=TagClassApplication),
5532 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5534 hexdec("670743054A6F6E6573"),
5536 self.assertSequenceEqual(
5537 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5538 hexdec("82054A6F6E6573"),