2 # PyDERASN -- Python ASN.1 DER/BER 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))
128 decode_path_strat = lists(integers(), max_size=3).map(
129 lambda decode_path: tuple(str(dp) for dp in decode_path)
133 class TestHex(TestCase):
135 def test_symmetric(self, data):
136 self.assertEqual(hexdec(hexenc(data)), data)
139 class TestTagCoder(TestCase):
140 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
144 integers(min_value=0, max_value=30),
147 def test_short(self, klass, form, num, junk):
148 raw = tag_encode(klass=klass, form=form, num=num)
149 self.assertEqual(tag_decode(raw), (klass, form, num))
150 self.assertEqual(len(raw), 1)
152 byte2int(tag_encode(klass=klass, form=form, num=0)),
153 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
155 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
156 self.assertSequenceEqual(stripped.tobytes(), raw)
157 self.assertEqual(tlen, len(raw))
158 self.assertSequenceEqual(tail, junk)
160 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
164 integers(min_value=31),
167 def test_long(self, klass, form, num, junk):
168 raw = tag_encode(klass=klass, form=form, num=num)
169 self.assertEqual(tag_decode(raw), (klass, form, num))
170 self.assertGreater(len(raw), 1)
172 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
175 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
176 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
177 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
178 self.assertSequenceEqual(stripped.tobytes(), raw)
179 self.assertEqual(tlen, len(raw))
180 self.assertSequenceEqual(tail, junk)
182 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
183 @given(integers(min_value=31))
184 def test_unfinished_tag(self, num):
185 raw = bytearray(tag_encode(num=num))
186 for i in range(1, len(raw)):
188 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
189 tag_strip(bytes(raw))
191 def test_go_vectors_valid(self):
192 for data, (eklass, etag, elen, eform) in (
193 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
194 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
195 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
196 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
197 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
198 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
199 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
200 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
201 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
202 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
204 tag, _, len_encoded = tag_strip(memoryview(data))
205 klass, form, num = tag_decode(tag)
206 _len, _, tail = len_decode(len_encoded)
207 self.assertSequenceEqual(tail, b"")
208 self.assertEqual(klass, eklass)
209 self.assertEqual(num, etag)
210 self.assertEqual(_len, elen)
211 self.assertEqual(form, eform)
213 def test_go_vectors_invalid(self):
221 with self.assertRaises(DecodeError):
222 _, _, len_encoded = tag_strip(memoryview(data))
223 len_decode(len_encoded)
226 integers(min_value=0, max_value=127),
227 integers(min_value=0, max_value=2),
229 def test_long_instead_of_short(self, l, dummy_num):
230 octets = (b"\x00" * dummy_num) + int2byte(l)
231 octets = int2byte((dummy_num + 1) | 0x80) + octets
232 with self.assertRaises(DecodeError):
236 class TestLenCoder(TestCase):
237 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
239 integers(min_value=0, max_value=127),
242 def test_short(self, l, junk):
243 raw = len_encode(l) + junk
244 decoded, llen, tail = len_decode(memoryview(raw))
245 self.assertEqual(decoded, l)
246 self.assertEqual(llen, 1)
247 self.assertEqual(len(raw), 1 + len(junk))
248 self.assertEqual(tail.tobytes(), junk)
250 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
252 integers(min_value=128),
255 def test_long(self, l, junk):
256 raw = len_encode(l) + junk
257 decoded, llen, tail = len_decode(memoryview(raw))
258 self.assertEqual(decoded, l)
259 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
260 self.assertEqual(llen, len(raw) - len(junk))
261 self.assertNotEqual(indexbytes(raw, 1), 0)
262 self.assertSequenceEqual(tail.tobytes(), junk)
264 def test_empty(self):
265 with self.assertRaises(NotEnoughData):
268 @given(integers(min_value=128))
269 def test_stripped(self, _len):
270 with self.assertRaises(NotEnoughData):
271 len_decode(len_encode(_len)[:-1])
274 text_printable = text(alphabet=printable, min_size=1)
278 def text_letters(draw):
279 result = draw(text(alphabet=ascii_letters, min_size=1))
281 result = result.encode("ascii")
285 class CommonMixin(object):
286 def test_tag_default(self):
287 obj = self.base_klass()
288 self.assertEqual(obj.tag, obj.tag_default)
290 def test_simultaneous_impl_expl(self):
291 with self.assertRaises(ValueError):
292 self.base_klass(impl=b"whatever", expl=b"whenever")
294 @given(binary(min_size=1), integers(), integers(), integers())
295 def test_decoded(self, impl, offset, llen, vlen):
296 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
297 self.assertEqual(obj.offset, offset)
298 self.assertEqual(obj.llen, llen)
299 self.assertEqual(obj.vlen, vlen)
300 self.assertEqual(obj.tlen, len(impl))
301 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
303 @given(binary(min_size=1))
304 def test_impl_inherited(self, impl_tag):
305 class Inherited(self.base_klass):
308 self.assertSequenceEqual(obj.impl, impl_tag)
309 self.assertFalse(obj.expled)
312 def test_expl_inherited(self, expl_tag):
313 class Inherited(self.base_klass):
316 self.assertSequenceEqual(obj.expl, expl_tag)
317 self.assertTrue(obj.expled)
319 def assert_copied_basic_fields(self, obj, obj_copied):
320 self.assertEqual(obj, obj_copied)
321 self.assertSequenceEqual(obj.tag, obj_copied.tag)
322 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
323 self.assertEqual(obj.default, obj_copied.default)
324 self.assertEqual(obj.optional, obj_copied.optional)
325 self.assertEqual(obj.offset, obj_copied.offset)
326 self.assertEqual(obj.llen, obj_copied.llen)
327 self.assertEqual(obj.vlen, obj_copied.vlen)
331 def boolean_values_strategy(draw, do_expl=False):
332 value = draw(one_of(none(), booleans()))
336 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
338 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
339 default = draw(one_of(none(), booleans()))
340 optional = draw(one_of(none(), booleans()))
342 draw(integers(min_value=0)),
343 draw(integers(min_value=0)),
344 draw(integers(min_value=0)),
346 return (value, impl, expl, default, optional, _decoded)
349 class BooleanInherited(Boolean):
353 class TestBoolean(CommonMixin, TestCase):
356 def test_invalid_value_type(self):
357 with self.assertRaises(InvalidValueType) as err:
362 def test_optional(self, optional):
363 obj = Boolean(default=Boolean(False), optional=optional)
364 self.assertTrue(obj.optional)
367 def test_ready(self, value):
369 self.assertFalse(obj.ready)
372 with self.assertRaises(ObjNotReady) as err:
376 self.assertTrue(obj.ready)
380 @given(booleans(), booleans(), binary(), binary())
381 def test_comparison(self, value1, value2, tag1, tag2):
382 for klass in (Boolean, BooleanInherited):
385 self.assertEqual(obj1 == obj2, value1 == value2)
386 self.assertEqual(obj1 != obj2, value1 != value2)
387 self.assertEqual(obj1 == bool(obj2), value1 == value2)
388 obj1 = klass(value1, impl=tag1)
389 obj2 = klass(value1, impl=tag2)
390 self.assertEqual(obj1 == obj2, tag1 == tag2)
391 self.assertEqual(obj1 != obj2, tag1 != tag2)
393 @given(data_strategy())
394 def test_call(self, d):
395 for klass in (Boolean, BooleanInherited):
403 ) = d.draw(boolean_values_strategy())
409 optional_initial or False,
419 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
420 obj = obj_initial(value, impl, expl, default, optional)
422 value_expected = default if value is None else value
424 default_initial if value_expected is None
427 self.assertEqual(obj, value_expected)
428 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
429 self.assertEqual(obj.expl_tag, expl or expl_initial)
432 default_initial if default is None else default,
434 if obj.default is None:
435 optional = optional_initial if optional is None else optional
436 optional = False if optional is None else optional
439 self.assertEqual(obj.optional, optional)
441 @given(boolean_values_strategy())
442 def test_copy(self, values):
443 for klass in (Boolean, BooleanInherited):
445 obj_copied = obj.copy()
446 self.assert_copied_basic_fields(obj, obj_copied)
450 integers(min_value=1).map(tag_encode),
452 def test_stripped(self, value, tag_impl):
453 obj = Boolean(value, impl=tag_impl)
454 with self.assertRaises(NotEnoughData):
455 obj.decode(obj.encode()[:-1])
459 integers(min_value=1).map(tag_ctxc),
461 def test_stripped_expl(self, value, tag_expl):
462 obj = Boolean(value, expl=tag_expl)
463 with self.assertRaises(NotEnoughData):
464 obj.decode(obj.encode()[:-1])
467 integers(min_value=31),
468 integers(min_value=0),
471 def test_bad_tag(self, tag, offset, decode_path):
472 with self.assertRaises(DecodeError) as err:
474 tag_encode(tag)[:-1],
476 decode_path=decode_path,
479 self.assertEqual(err.exception.offset, offset)
480 self.assertEqual(err.exception.decode_path, decode_path)
483 integers(min_value=31),
484 integers(min_value=0),
487 def test_bad_expl_tag(self, tag, offset, decode_path):
488 with self.assertRaises(DecodeError) as err:
489 Boolean(expl=Boolean.tag_default).decode(
490 tag_encode(tag)[:-1],
492 decode_path=decode_path,
495 self.assertEqual(err.exception.offset, offset)
496 self.assertEqual(err.exception.decode_path, decode_path)
499 integers(min_value=128),
500 integers(min_value=0),
503 def test_bad_len(self, l, offset, 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 with self.assertRaises(DecodeError) as err:
521 Boolean(expl=Boolean.tag_default).decode(
522 Boolean.tag_default + len_encode(l)[:-1],
524 decode_path=decode_path,
527 self.assertEqual(err.exception.offset, offset)
528 self.assertEqual(err.exception.decode_path, decode_path)
530 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
532 boolean_values_strategy(),
534 integers(min_value=1).map(tag_ctxc),
535 integers(min_value=0),
538 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
539 for klass in (Boolean, BooleanInherited):
540 _, _, _, default, optional, _decoded = values
549 self.assertFalse(obj.expled)
550 obj_encoded = obj.encode()
551 obj_expled = obj(value, expl=tag_expl)
552 self.assertTrue(obj_expled.expled)
555 obj_expled_encoded = obj_expled.encode()
556 obj_decoded, tail = obj_expled.decode(
557 obj_expled_encoded + tail_junk,
562 self.assertEqual(tail, tail_junk)
563 self.assertEqual(obj_decoded, obj_expled)
564 self.assertNotEqual(obj_decoded, obj)
565 self.assertEqual(bool(obj_decoded), bool(obj_expled))
566 self.assertEqual(bool(obj_decoded), bool(obj))
567 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
568 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
569 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
571 obj_decoded.expl_llen,
572 len(len_encode(len(obj_encoded))),
574 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
575 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
578 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
580 self.assertEqual(obj_decoded.expl_offset, offset)
582 @given(integers(min_value=2))
583 def test_invalid_len(self, l):
584 with self.assertRaises(InvalidLength):
585 Boolean().decode(b"".join((
591 @given(integers(min_value=0 + 1, max_value=255 - 1))
592 def test_ber_value(self, value):
593 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
594 Boolean().decode(b"".join((
599 obj, _ = Boolean().decode(
607 self.assertTrue(bool(obj))
608 self.assertTrue(obj.bered)
609 self.assertFalse(obj.lenindef)
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)
649 len(expl) + 1 + 3 + EOC_LEN,
660 def integer_values_strategy(draw, do_expl=False):
661 bound_min, value, default, bound_max = sorted(draw(sets(
670 _specs = draw(sets(text_letters()))
673 min_size=len(_specs),
674 max_size=len(_specs),
676 _specs = list(zip(_specs, values))
679 bounds = (bound_min, bound_max)
683 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
685 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
688 optional = draw(one_of(none(), booleans()))
690 draw(integers(min_value=0)),
691 draw(integers(min_value=0)),
692 draw(integers(min_value=0)),
694 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
697 class IntegerInherited(Integer):
701 class TestInteger(CommonMixin, TestCase):
704 def test_invalid_value_type(self):
705 with self.assertRaises(InvalidValueType) as err:
709 @given(sets(text_letters(), min_size=2))
710 def test_unknown_name(self, names_input):
711 missing = names_input.pop()
714 schema = [(n, 123) for n in names_input]
715 with self.assertRaises(ObjUnknown) as err:
719 @given(sets(text_letters(), min_size=2))
720 def test_known_name(self, names_input):
722 schema = [(n, 123) for n in names_input]
723 Int(names_input.pop())
726 def test_optional(self, optional):
727 obj = Integer(default=Integer(0), optional=optional)
728 self.assertTrue(obj.optional)
731 def test_ready(self, value):
733 self.assertFalse(obj.ready)
736 with self.assertRaises(ObjNotReady) as err:
740 self.assertTrue(obj.ready)
745 @given(integers(), integers(), binary(), binary())
746 def test_comparison(self, value1, value2, tag1, tag2):
747 for klass in (Integer, IntegerInherited):
750 self.assertEqual(obj1 == obj2, value1 == value2)
751 self.assertEqual(obj1 != obj2, value1 != value2)
752 self.assertEqual(obj1 == int(obj2), value1 == value2)
753 obj1 = klass(value1, impl=tag1)
754 obj2 = klass(value1, impl=tag2)
755 self.assertEqual(obj1 == obj2, tag1 == tag2)
756 self.assertEqual(obj1 != obj2, tag1 != tag2)
758 @given(lists(integers()))
759 def test_sorted_works(self, values):
760 self.assertSequenceEqual(
761 [int(v) for v in sorted(Integer(v) for v in values)],
765 @given(data_strategy())
766 def test_named(self, d):
767 names_input = list(d.draw(sets(text_letters(), min_size=1)))
768 values_input = list(d.draw(sets(
770 min_size=len(names_input),
771 max_size=len(names_input),
773 chosen_name = d.draw(sampled_from(names_input))
774 names_input = dict(zip(names_input, values_input))
778 _int = Int(chosen_name)
779 self.assertEqual(_int.named, chosen_name)
780 self.assertEqual(int(_int), names_input[chosen_name])
782 @given(integers(), integers(min_value=0), integers(min_value=0))
783 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
784 value = bound_min + value_delta
785 bound_max = value + bound_delta
786 Integer(value=value, bounds=(bound_min, bound_max))
788 @given(sets(integers(), min_size=3, max_size=3))
789 def test_bounds_unsatisfied(self, values):
790 values = sorted(values)
791 with self.assertRaises(BoundsError) as err:
792 Integer(value=values[0], bounds=(values[1], values[2]))
794 with self.assertRaises(BoundsError) as err:
795 Integer(value=values[2], bounds=(values[0], values[1]))
798 @given(data_strategy())
799 def test_call(self, d):
800 for klass in (Integer, IntegerInherited):
810 ) = d.draw(integer_values_strategy())
817 optional_initial or False,
830 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
831 if (default is None) and (obj_initial.default is not None):
835 (value is not None) and
836 (bounds_initial is not None) and
837 not (bounds_initial[0] <= value <= bounds_initial[1])
842 (default is not None) and
843 (bounds_initial is not None) and
844 not (bounds_initial[0] <= default <= bounds_initial[1])
847 obj = obj_initial(value, bounds, impl, expl, default, optional)
849 value_expected = default if value is None else value
851 default_initial if value_expected is None
854 self.assertEqual(obj, value_expected)
855 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
856 self.assertEqual(obj.expl_tag, expl or expl_initial)
859 default_initial if default is None else default,
861 if obj.default is None:
862 optional = optional_initial if optional is None else optional
863 optional = False if optional is None else optional
866 self.assertEqual(obj.optional, optional)
868 (obj._bound_min, obj._bound_max),
869 bounds or bounds_initial or (float("-inf"), float("+inf")),
873 {} if _specs_initial is None else dict(_specs_initial),
876 @given(integer_values_strategy())
877 def test_copy(self, values):
878 for klass in (Integer, IntegerInherited):
880 obj_copied = obj.copy()
881 self.assert_copied_basic_fields(obj, obj_copied)
882 self.assertEqual(obj.specs, obj_copied.specs)
883 self.assertEqual(obj._bound_min, obj_copied._bound_min)
884 self.assertEqual(obj._bound_max, obj_copied._bound_max)
885 self.assertEqual(obj._value, obj_copied._value)
889 integers(min_value=1).map(tag_encode),
891 def test_stripped(self, value, tag_impl):
892 obj = Integer(value, impl=tag_impl)
893 with self.assertRaises(NotEnoughData):
894 obj.decode(obj.encode()[:-1])
898 integers(min_value=1).map(tag_ctxc),
900 def test_stripped_expl(self, value, tag_expl):
901 obj = Integer(value, expl=tag_expl)
902 with self.assertRaises(NotEnoughData):
903 obj.decode(obj.encode()[:-1])
905 def test_zero_len(self):
906 with self.assertRaises(NotEnoughData):
907 Integer().decode(b"".join((
913 integers(min_value=31),
914 integers(min_value=0),
917 def test_bad_tag(self, tag, offset, decode_path):
918 with self.assertRaises(DecodeError) as err:
920 tag_encode(tag)[:-1],
922 decode_path=decode_path,
925 self.assertEqual(err.exception.offset, offset)
926 self.assertEqual(err.exception.decode_path, decode_path)
929 integers(min_value=128),
930 integers(min_value=0),
933 def test_bad_len(self, l, offset, decode_path):
934 with self.assertRaises(DecodeError) as err:
936 Integer.tag_default + len_encode(l)[:-1],
938 decode_path=decode_path,
941 self.assertEqual(err.exception.offset, offset)
942 self.assertEqual(err.exception.decode_path, decode_path)
945 sets(integers(), min_size=2, max_size=2),
946 integers(min_value=0),
949 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
950 value, bound_min = list(sorted(ints))
953 bounds = (bound_min, bound_min)
954 with self.assertRaises(DecodeError) as err:
956 Integer(value).encode(),
958 decode_path=decode_path,
961 self.assertEqual(err.exception.offset, offset)
962 self.assertEqual(err.exception.decode_path, decode_path)
964 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
966 integer_values_strategy(),
968 integers(min_value=1).map(tag_ctxc),
969 integers(min_value=0),
972 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
973 for klass in (Integer, IntegerInherited):
974 _, _, _, _, default, optional, _, _decoded = values
983 self.assertFalse(obj.expled)
984 obj_encoded = obj.encode()
985 obj_expled = obj(value, expl=tag_expl)
986 self.assertTrue(obj_expled.expled)
989 obj_expled_encoded = obj_expled.encode()
990 obj_decoded, tail = obj_expled.decode(
991 obj_expled_encoded + tail_junk,
996 self.assertEqual(tail, tail_junk)
997 self.assertEqual(obj_decoded, obj_expled)
998 self.assertNotEqual(obj_decoded, obj)
999 self.assertEqual(int(obj_decoded), int(obj_expled))
1000 self.assertEqual(int(obj_decoded), int(obj))
1001 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1002 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1003 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1005 obj_decoded.expl_llen,
1006 len(len_encode(len(obj_encoded))),
1008 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1009 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1012 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1014 self.assertEqual(obj_decoded.expl_offset, offset)
1016 def test_go_vectors_valid(self):
1017 for data, expect in ((
1021 (b"\xff\x7f", -129),
1025 (b"\xff\x00", -256),
1029 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1030 (b"\x80\x00\x00\x00", -2147483648),
1033 Integer().decode(b"".join((
1034 Integer.tag_default,
1035 len_encode(len(data)),
1041 def test_go_vectors_invalid(self):
1046 with self.assertRaises(DecodeError):
1047 Integer().decode(b"".join((
1048 Integer.tag_default,
1049 len_encode(len(data)),
1055 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1058 if draw(booleans()):
1059 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1061 integers(min_value=0, max_value=255),
1062 min_size=len(schema),
1063 max_size=len(schema),
1065 schema = list(zip(schema, bits))
1067 def _value(value_required):
1068 if not value_required and draw(booleans()):
1070 generation_choice = 0
1072 generation_choice = draw(sampled_from((1, 2, 3)))
1073 if generation_choice == 1 or draw(booleans()):
1074 return "'%s'B" % "".join(draw(lists(
1075 sampled_from(("0", "1")),
1076 max_size=len(schema),
1078 elif generation_choice == 2 or draw(booleans()):
1079 return draw(binary(max_size=len(schema) // 8))
1080 elif generation_choice == 3 or draw(booleans()):
1081 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1083 value = _value(value_required)
1084 default = _value(value_required=False)
1088 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1090 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1091 optional = draw(one_of(none(), booleans()))
1093 draw(integers(min_value=0)),
1094 draw(integers(min_value=0)),
1095 draw(integers(min_value=0)),
1097 return (schema, value, impl, expl, default, optional, _decoded)
1100 class BitStringInherited(BitString):
1104 class TestBitString(CommonMixin, TestCase):
1105 base_klass = BitString
1107 @given(lists(booleans()))
1108 def test_b_encoding(self, bits):
1109 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1110 self.assertEqual(obj.bit_len, len(bits))
1111 self.assertSequenceEqual(list(obj), bits)
1112 for i, bit in enumerate(bits):
1113 self.assertEqual(obj[i], bit)
1115 @given(lists(booleans()))
1116 def test_out_of_bounds_bits(self, bits):
1117 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1118 for i in range(len(bits), len(bits) * 2):
1119 self.assertFalse(obj[i])
1121 def test_bad_b_encoding(self):
1122 with self.assertRaises(ValueError):
1123 BitString("'010120101'B")
1126 integers(min_value=1, max_value=255),
1127 integers(min_value=1, max_value=255),
1129 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1130 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1131 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1132 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1134 class BS(BitString):
1135 schema = (("whatever", 0),)
1136 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1137 self.assertEqual(obj.bit_len, leading_zeros + 1)
1138 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1140 def test_zero_len(self):
1141 with self.assertRaises(NotEnoughData):
1142 BitString().decode(b"".join((
1143 BitString.tag_default,
1147 def test_invalid_value_type(self):
1148 with self.assertRaises(InvalidValueType) as err:
1151 with self.assertRaises(InvalidValueType) as err:
1155 def test_obj_unknown(self):
1156 with self.assertRaises(ObjUnknown) as err:
1157 BitString(b"whatever")["whenever"]
1160 def test_get_invalid_type(self):
1161 with self.assertRaises(InvalidValueType) as err:
1162 BitString(b"whatever")[(1, 2, 3)]
1165 @given(data_strategy())
1166 def test_unknown_name(self, d):
1167 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1168 missing = _schema.pop()
1170 class BS(BitString):
1171 schema = [(n, i) for i, n in enumerate(_schema)]
1172 with self.assertRaises(ObjUnknown) as err:
1177 def test_optional(self, optional):
1178 obj = BitString(default=BitString(b""), optional=optional)
1179 self.assertTrue(obj.optional)
1182 def test_ready(self, value):
1184 self.assertFalse(obj.ready)
1187 with self.assertRaises(ObjNotReady) as err:
1190 obj = BitString(value)
1191 self.assertTrue(obj.ready)
1196 tuples(integers(min_value=0), binary()),
1197 tuples(integers(min_value=0), binary()),
1201 def test_comparison(self, value1, value2, tag1, tag2):
1202 for klass in (BitString, BitStringInherited):
1203 obj1 = klass(value1)
1204 obj2 = klass(value2)
1205 self.assertEqual(obj1 == obj2, value1 == value2)
1206 self.assertEqual(obj1 != obj2, value1 != value2)
1207 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1208 obj1 = klass(value1, impl=tag1)
1209 obj2 = klass(value1, impl=tag2)
1210 self.assertEqual(obj1 == obj2, tag1 == tag2)
1211 self.assertEqual(obj1 != obj2, tag1 != tag2)
1213 @given(data_strategy())
1214 def test_call(self, d):
1215 for klass in (BitString, BitStringInherited):
1224 ) = d.draw(bit_string_values_strategy())
1227 schema = schema_initial
1229 value=value_initial,
1232 default=default_initial,
1233 optional=optional_initial or False,
1234 _decoded=_decoded_initial,
1244 ) = d.draw(bit_string_values_strategy(
1245 schema=schema_initial,
1246 do_expl=impl_initial is None,
1255 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1256 self.assertEqual(obj.expl_tag, expl or expl_initial)
1257 if obj.default is None:
1258 optional = optional_initial if optional is None else optional
1259 optional = False if optional is None else optional
1262 self.assertEqual(obj.optional, optional)
1263 self.assertEqual(obj.specs, obj_initial.specs)
1265 @given(bit_string_values_strategy())
1266 def test_copy(self, values):
1267 for klass in (BitString, BitStringInherited):
1268 _schema, value, impl, expl, default, optional, _decoded = values
1277 optional=optional or False,
1280 obj_copied = obj.copy()
1281 self.assert_copied_basic_fields(obj, obj_copied)
1282 self.assertEqual(obj.specs, obj_copied.specs)
1283 self.assertEqual(obj._value, obj_copied._value)
1287 integers(min_value=1).map(tag_encode),
1289 def test_stripped(self, value, tag_impl):
1290 obj = BitString(value, impl=tag_impl)
1291 with self.assertRaises(NotEnoughData):
1292 obj.decode(obj.encode()[:-1])
1296 integers(min_value=1).map(tag_ctxc),
1298 def test_stripped_expl(self, value, tag_expl):
1299 obj = BitString(value, expl=tag_expl)
1300 with self.assertRaises(NotEnoughData):
1301 obj.decode(obj.encode()[:-1])
1304 integers(min_value=31),
1305 integers(min_value=0),
1308 def test_bad_tag(self, tag, offset, decode_path):
1309 with self.assertRaises(DecodeError) as err:
1311 tag_encode(tag)[:-1],
1313 decode_path=decode_path,
1316 self.assertEqual(err.exception.offset, offset)
1317 self.assertEqual(err.exception.decode_path, decode_path)
1320 integers(min_value=128),
1321 integers(min_value=0),
1324 def test_bad_len(self, l, offset, decode_path):
1325 with self.assertRaises(DecodeError) as err:
1327 BitString.tag_default + len_encode(l)[:-1],
1329 decode_path=decode_path,
1332 self.assertEqual(err.exception.offset, offset)
1333 self.assertEqual(err.exception.decode_path, decode_path)
1335 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1336 @given(data_strategy())
1337 def test_symmetric(self, d):
1346 ) = d.draw(bit_string_values_strategy(value_required=True))
1347 tail_junk = d.draw(binary(max_size=5))
1348 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1349 offset = d.draw(integers(min_value=0))
1350 for klass in (BitString, BitStringInherited):
1361 self.assertFalse(obj.expled)
1362 obj_encoded = obj.encode()
1363 obj_expled = obj(value, expl=tag_expl)
1364 self.assertTrue(obj_expled.expled)
1367 obj_expled_encoded = obj_expled.encode()
1368 obj_decoded, tail = obj_expled.decode(
1369 obj_expled_encoded + tail_junk,
1374 self.assertEqual(tail, tail_junk)
1375 self.assertEqual(obj_decoded, obj_expled)
1376 self.assertNotEqual(obj_decoded, obj)
1377 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1378 self.assertEqual(bytes(obj_decoded), bytes(obj))
1379 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1380 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1381 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1383 obj_decoded.expl_llen,
1384 len(len_encode(len(obj_encoded))),
1386 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1387 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1390 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1392 self.assertEqual(obj_decoded.expl_offset, offset)
1393 if isinstance(value, tuple):
1394 self.assertSetEqual(set(value), set(obj_decoded.named))
1398 @given(integers(min_value=1, max_value=255))
1399 def test_bad_zero_value(self, pad_size):
1400 with self.assertRaises(DecodeError):
1401 BitString().decode(b"".join((
1402 BitString.tag_default,
1407 def test_go_vectors_invalid(self):
1413 with self.assertRaises(DecodeError):
1414 BitString().decode(b"".join((
1415 BitString.tag_default,
1420 def test_go_vectors_valid(self):
1421 obj, _ = BitString().decode(b"".join((
1422 BitString.tag_default,
1426 self.assertEqual(bytes(obj), b"")
1427 self.assertEqual(obj.bit_len, 0)
1429 obj, _ = BitString().decode(b"".join((
1430 BitString.tag_default,
1434 self.assertEqual(bytes(obj), b"\x00")
1435 self.assertEqual(obj.bit_len, 1)
1437 obj = BitString((16, b"\x82\x40"))
1438 self.assertTrue(obj[0])
1439 self.assertFalse(obj[1])
1440 self.assertTrue(obj[6])
1441 self.assertTrue(obj[9])
1442 self.assertFalse(obj[17])
1445 integers(min_value=1, max_value=30),
1448 binary(min_size=1, max_size=5),
1450 binary(min_size=1, max_size=5),
1458 lists(booleans(), min_size=1),
1460 def test_constructed(self, impl, chunk_inputs, chunk_last_bits):
1461 def chunk_constructed(contents):
1463 tag_encode(form=TagFormConstructed, num=3) +
1465 b"".join(BitString(content).encode() for content in contents) +
1469 payload_expected = b""
1470 bit_len_expected = 0
1471 for chunk_input in chunk_inputs:
1472 if isinstance(chunk_input, binary_type):
1473 chunks.append(BitString(chunk_input).encode())
1474 payload_expected += chunk_input
1475 bit_len_expected += len(chunk_input) * 8
1477 chunks.append(chunk_constructed(chunk_input))
1478 payload = b"".join(chunk_input)
1479 payload_expected += payload
1480 bit_len_expected += len(payload) * 8
1481 chunk_last = BitString("'%s'B" % "".join(
1482 "1" if bit else "0" for bit in chunk_last_bits
1484 payload_expected += bytes(chunk_last)
1485 bit_len_expected += chunk_last.bit_len
1486 encoded_indefinite = (
1487 tag_encode(form=TagFormConstructed, num=impl) +
1490 chunk_last.encode() +
1493 encoded_definite = (
1494 tag_encode(form=TagFormConstructed, num=impl) +
1495 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1499 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1500 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1501 for lenindef_expected, encoded in (
1502 (True, encoded_indefinite),
1503 (False, encoded_definite),
1505 obj, tail = BitString(impl=tag_encode(impl)).decode(
1506 encoded, ctx={"bered": True}
1508 self.assertSequenceEqual(tail, b"")
1509 self.assertEqual(obj.bit_len, bit_len_expected)
1510 self.assertSequenceEqual(bytes(obj), payload_expected)
1511 self.assertTrue(obj.bered)
1512 self.assertEqual(obj.lenindef, lenindef_expected)
1513 self.assertEqual(len(encoded), obj.tlvlen)
1515 def test_x690_vector(self):
1516 vector = BitString("'0A3B5F291CD'H")
1517 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1518 self.assertSequenceEqual(tail, b"")
1519 self.assertEqual(obj, vector)
1520 obj, tail = BitString().decode(
1521 hexdec("23800303000A3B0305045F291CD00000"),
1522 ctx={"bered": True},
1524 self.assertSequenceEqual(tail, b"")
1525 self.assertEqual(obj, vector)
1526 self.assertTrue(obj.bered)
1527 self.assertTrue(obj.lenindef)
1531 def octet_string_values_strategy(draw, do_expl=False):
1532 bound_min, bound_max = sorted(draw(sets(
1533 integers(min_value=0, max_value=1 << 7),
1537 value = draw(one_of(
1539 binary(min_size=bound_min, max_size=bound_max),
1541 default = draw(one_of(
1543 binary(min_size=bound_min, max_size=bound_max),
1546 if draw(booleans()):
1547 bounds = (bound_min, bound_max)
1551 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1553 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1554 optional = draw(one_of(none(), booleans()))
1556 draw(integers(min_value=0)),
1557 draw(integers(min_value=0)),
1558 draw(integers(min_value=0)),
1560 return (value, bounds, impl, expl, default, optional, _decoded)
1563 class OctetStringInherited(OctetString):
1567 class TestOctetString(CommonMixin, TestCase):
1568 base_klass = OctetString
1570 def test_invalid_value_type(self):
1571 with self.assertRaises(InvalidValueType) as err:
1572 OctetString(text_type(123))
1576 def test_optional(self, optional):
1577 obj = OctetString(default=OctetString(b""), optional=optional)
1578 self.assertTrue(obj.optional)
1581 def test_ready(self, value):
1583 self.assertFalse(obj.ready)
1586 with self.assertRaises(ObjNotReady) as err:
1589 obj = OctetString(value)
1590 self.assertTrue(obj.ready)
1594 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1595 def test_comparison(self, value1, value2, tag1, tag2):
1596 for klass in (OctetString, OctetStringInherited):
1597 obj1 = klass(value1)
1598 obj2 = klass(value2)
1599 self.assertEqual(obj1 == obj2, value1 == value2)
1600 self.assertEqual(obj1 != obj2, value1 != value2)
1601 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1602 obj1 = klass(value1, impl=tag1)
1603 obj2 = klass(value1, impl=tag2)
1604 self.assertEqual(obj1 == obj2, tag1 == tag2)
1605 self.assertEqual(obj1 != obj2, tag1 != tag2)
1607 @given(lists(binary()))
1608 def test_sorted_works(self, values):
1609 self.assertSequenceEqual(
1610 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1614 @given(data_strategy())
1615 def test_bounds_satisfied(self, d):
1616 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1617 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1618 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1619 OctetString(value=value, bounds=(bound_min, bound_max))
1621 @given(data_strategy())
1622 def test_bounds_unsatisfied(self, d):
1623 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1624 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1625 value = d.draw(binary(max_size=bound_min - 1))
1626 with self.assertRaises(BoundsError) as err:
1627 OctetString(value=value, bounds=(bound_min, bound_max))
1629 value = d.draw(binary(min_size=bound_max + 1))
1630 with self.assertRaises(BoundsError) as err:
1631 OctetString(value=value, bounds=(bound_min, bound_max))
1634 @given(data_strategy())
1635 def test_call(self, d):
1636 for klass in (OctetString, OctetStringInherited):
1645 ) = d.draw(octet_string_values_strategy())
1646 obj_initial = klass(
1652 optional_initial or False,
1663 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1664 if (default is None) and (obj_initial.default is not None):
1667 (bounds is None) and
1668 (value is not None) and
1669 (bounds_initial is not None) and
1670 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1674 (bounds is None) and
1675 (default is not None) and
1676 (bounds_initial is not None) and
1677 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1680 obj = obj_initial(value, bounds, impl, expl, default, optional)
1682 value_expected = default if value is None else value
1684 default_initial if value_expected is None
1687 self.assertEqual(obj, value_expected)
1688 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1689 self.assertEqual(obj.expl_tag, expl or expl_initial)
1692 default_initial if default is None else default,
1694 if obj.default is None:
1695 optional = optional_initial if optional is None else optional
1696 optional = False if optional is None else optional
1699 self.assertEqual(obj.optional, optional)
1701 (obj._bound_min, obj._bound_max),
1702 bounds or bounds_initial or (0, float("+inf")),
1705 @given(octet_string_values_strategy())
1706 def test_copy(self, values):
1707 for klass in (OctetString, OctetStringInherited):
1708 obj = klass(*values)
1709 obj_copied = obj.copy()
1710 self.assert_copied_basic_fields(obj, obj_copied)
1711 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1712 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1713 self.assertEqual(obj._value, obj_copied._value)
1717 integers(min_value=1).map(tag_encode),
1719 def test_stripped(self, value, tag_impl):
1720 obj = OctetString(value, impl=tag_impl)
1721 with self.assertRaises(NotEnoughData):
1722 obj.decode(obj.encode()[:-1])
1726 integers(min_value=1).map(tag_ctxc),
1728 def test_stripped_expl(self, value, tag_expl):
1729 obj = OctetString(value, expl=tag_expl)
1730 with self.assertRaises(NotEnoughData):
1731 obj.decode(obj.encode()[:-1])
1734 integers(min_value=31),
1735 integers(min_value=0),
1738 def test_bad_tag(self, tag, offset, decode_path):
1739 with self.assertRaises(DecodeError) as err:
1740 OctetString().decode(
1741 tag_encode(tag)[:-1],
1743 decode_path=decode_path,
1746 self.assertEqual(err.exception.offset, offset)
1747 self.assertEqual(err.exception.decode_path, decode_path)
1750 integers(min_value=128),
1751 integers(min_value=0),
1754 def test_bad_len(self, l, offset, decode_path):
1755 with self.assertRaises(DecodeError) as err:
1756 OctetString().decode(
1757 OctetString.tag_default + len_encode(l)[:-1],
1759 decode_path=decode_path,
1762 self.assertEqual(err.exception.offset, offset)
1763 self.assertEqual(err.exception.decode_path, decode_path)
1766 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1767 integers(min_value=0),
1770 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1771 value, bound_min = list(sorted(ints))
1773 class String(OctetString):
1774 bounds = (bound_min, bound_min)
1775 with self.assertRaises(DecodeError) as err:
1777 OctetString(b"\x00" * value).encode(),
1779 decode_path=decode_path,
1782 self.assertEqual(err.exception.offset, offset)
1783 self.assertEqual(err.exception.decode_path, decode_path)
1785 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1787 octet_string_values_strategy(),
1789 integers(min_value=1).map(tag_ctxc),
1790 integers(min_value=0),
1793 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1794 for klass in (OctetString, OctetStringInherited):
1795 _, _, _, _, default, optional, _decoded = values
1804 self.assertFalse(obj.expled)
1805 obj_encoded = obj.encode()
1806 obj_expled = obj(value, expl=tag_expl)
1807 self.assertTrue(obj_expled.expled)
1810 obj_expled_encoded = obj_expled.encode()
1811 obj_decoded, tail = obj_expled.decode(
1812 obj_expled_encoded + tail_junk,
1817 self.assertEqual(tail, tail_junk)
1818 self.assertEqual(obj_decoded, obj_expled)
1819 self.assertNotEqual(obj_decoded, obj)
1820 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1821 self.assertEqual(bytes(obj_decoded), bytes(obj))
1822 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1823 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1824 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1826 obj_decoded.expl_llen,
1827 len(len_encode(len(obj_encoded))),
1829 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1830 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1833 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1835 self.assertEqual(obj_decoded.expl_offset, offset)
1838 integers(min_value=1, max_value=30),
1841 binary(min_size=1, max_size=5),
1843 binary(min_size=1, max_size=5),
1852 def test_constructed(self, impl, chunk_inputs):
1853 def chunk_constructed(contents):
1855 tag_encode(form=TagFormConstructed, num=4) +
1857 b"".join(OctetString(content).encode() for content in contents) +
1861 payload_expected = b""
1862 for chunk_input in chunk_inputs:
1863 if isinstance(chunk_input, binary_type):
1864 chunks.append(OctetString(chunk_input).encode())
1865 payload_expected += chunk_input
1867 chunks.append(chunk_constructed(chunk_input))
1868 payload = b"".join(chunk_input)
1869 payload_expected += payload
1870 encoded_indefinite = (
1871 tag_encode(form=TagFormConstructed, num=impl) +
1876 encoded_definite = (
1877 tag_encode(form=TagFormConstructed, num=impl) +
1878 len_encode(len(b"".join(chunks))) +
1881 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1882 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
1883 for lenindef_expected, encoded in (
1884 (True, encoded_indefinite),
1885 (False, encoded_definite),
1887 obj, tail = OctetString(impl=tag_encode(impl)).decode(
1888 encoded, ctx={"bered": True}
1890 self.assertSequenceEqual(tail, b"")
1891 self.assertSequenceEqual(bytes(obj), payload_expected)
1892 self.assertTrue(obj.bered)
1893 self.assertEqual(obj.lenindef, lenindef_expected)
1894 self.assertEqual(len(encoded), obj.tlvlen)
1898 def null_values_strategy(draw, do_expl=False):
1902 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1904 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1905 optional = draw(one_of(none(), booleans()))
1907 draw(integers(min_value=0)),
1908 draw(integers(min_value=0)),
1909 draw(integers(min_value=0)),
1911 return (impl, expl, optional, _decoded)
1914 class NullInherited(Null):
1918 class TestNull(CommonMixin, TestCase):
1921 def test_ready(self):
1923 self.assertTrue(obj.ready)
1927 @given(binary(), binary())
1928 def test_comparison(self, tag1, tag2):
1929 for klass in (Null, NullInherited):
1930 obj1 = klass(impl=tag1)
1931 obj2 = klass(impl=tag2)
1932 self.assertEqual(obj1 == obj2, tag1 == tag2)
1933 self.assertEqual(obj1 != obj2, tag1 != tag2)
1934 self.assertNotEqual(obj1, tag2)
1936 @given(data_strategy())
1937 def test_call(self, d):
1938 for klass in (Null, NullInherited):
1944 ) = d.draw(null_values_strategy())
1945 obj_initial = klass(
1948 optional=optional_initial or False,
1949 _decoded=_decoded_initial,
1956 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
1957 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1958 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1959 self.assertEqual(obj.expl_tag, expl or expl_initial)
1960 optional = optional_initial if optional is None else optional
1961 optional = False if optional is None else optional
1962 self.assertEqual(obj.optional, optional)
1964 @given(null_values_strategy())
1965 def test_copy(self, values):
1966 for klass in (Null, NullInherited):
1967 impl, expl, optional, _decoded = values
1971 optional=optional or False,
1974 obj_copied = obj.copy()
1975 self.assert_copied_basic_fields(obj, obj_copied)
1977 @given(integers(min_value=1).map(tag_encode))
1978 def test_stripped(self, tag_impl):
1979 obj = Null(impl=tag_impl)
1980 with self.assertRaises(NotEnoughData):
1981 obj.decode(obj.encode()[:-1])
1983 @given(integers(min_value=1).map(tag_ctxc))
1984 def test_stripped_expl(self, tag_expl):
1985 obj = Null(expl=tag_expl)
1986 with self.assertRaises(NotEnoughData):
1987 obj.decode(obj.encode()[:-1])
1990 integers(min_value=31),
1991 integers(min_value=0),
1994 def test_bad_tag(self, tag, offset, decode_path):
1995 with self.assertRaises(DecodeError) as err:
1997 tag_encode(tag)[:-1],
1999 decode_path=decode_path,
2002 self.assertEqual(err.exception.offset, offset)
2003 self.assertEqual(err.exception.decode_path, decode_path)
2006 integers(min_value=128),
2007 integers(min_value=0),
2010 def test_bad_len(self, l, offset, decode_path):
2011 with self.assertRaises(DecodeError) as err:
2013 Null.tag_default + len_encode(l)[:-1],
2015 decode_path=decode_path,
2018 self.assertEqual(err.exception.offset, offset)
2019 self.assertEqual(err.exception.decode_path, decode_path)
2021 @given(binary(min_size=1))
2022 def test_tag_mismatch(self, impl):
2023 assume(impl != Null.tag_default)
2024 with self.assertRaises(TagMismatch):
2025 Null(impl=impl).decode(Null().encode())
2028 null_values_strategy(),
2029 integers(min_value=1).map(tag_ctxc),
2030 integers(min_value=0),
2033 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2034 for klass in (Null, NullInherited):
2035 _, _, optional, _decoded = values
2036 obj = klass(optional=optional, _decoded=_decoded)
2039 self.assertFalse(obj.expled)
2040 obj_encoded = obj.encode()
2041 obj_expled = obj(expl=tag_expl)
2042 self.assertTrue(obj_expled.expled)
2045 obj_expled_encoded = obj_expled.encode()
2046 obj_decoded, tail = obj_expled.decode(
2047 obj_expled_encoded + tail_junk,
2052 self.assertEqual(tail, tail_junk)
2053 self.assertEqual(obj_decoded, obj_expled)
2054 self.assertNotEqual(obj_decoded, obj)
2055 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2056 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2057 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2059 obj_decoded.expl_llen,
2060 len(len_encode(len(obj_encoded))),
2062 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2063 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2066 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2068 self.assertEqual(obj_decoded.expl_offset, offset)
2070 @given(integers(min_value=1))
2071 def test_invalid_len(self, l):
2072 with self.assertRaises(InvalidLength):
2073 Null().decode(b"".join((
2080 def oid_strategy(draw):
2081 first_arc = draw(integers(min_value=0, max_value=2))
2083 if first_arc in (0, 1):
2084 second_arc = draw(integers(min_value=0, max_value=39))
2086 second_arc = draw(integers(min_value=0))
2087 other_arcs = draw(lists(integers(min_value=0)))
2088 return tuple([first_arc, second_arc] + other_arcs)
2092 def oid_values_strategy(draw, do_expl=False):
2093 value = draw(one_of(none(), oid_strategy()))
2097 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2099 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2100 default = draw(one_of(none(), oid_strategy()))
2101 optional = draw(one_of(none(), booleans()))
2103 draw(integers(min_value=0)),
2104 draw(integers(min_value=0)),
2105 draw(integers(min_value=0)),
2107 return (value, impl, expl, default, optional, _decoded)
2110 class ObjectIdentifierInherited(ObjectIdentifier):
2114 class TestObjectIdentifier(CommonMixin, TestCase):
2115 base_klass = ObjectIdentifier
2117 def test_invalid_value_type(self):
2118 with self.assertRaises(InvalidValueType) as err:
2119 ObjectIdentifier(123)
2123 def test_optional(self, optional):
2124 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2125 self.assertTrue(obj.optional)
2127 @given(oid_strategy())
2128 def test_ready(self, value):
2129 obj = ObjectIdentifier()
2130 self.assertFalse(obj.ready)
2133 with self.assertRaises(ObjNotReady) as err:
2136 obj = ObjectIdentifier(value)
2137 self.assertTrue(obj.ready)
2142 @given(oid_strategy(), oid_strategy(), binary(), binary())
2143 def test_comparison(self, value1, value2, tag1, tag2):
2144 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2145 obj1 = klass(value1)
2146 obj2 = klass(value2)
2147 self.assertEqual(obj1 == obj2, value1 == value2)
2148 self.assertEqual(obj1 != obj2, value1 != value2)
2149 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2150 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2151 obj1 = klass(value1, impl=tag1)
2152 obj2 = klass(value1, impl=tag2)
2153 self.assertEqual(obj1 == obj2, tag1 == tag2)
2154 self.assertEqual(obj1 != obj2, tag1 != tag2)
2156 @given(lists(oid_strategy()))
2157 def test_sorted_works(self, values):
2158 self.assertSequenceEqual(
2159 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2163 @given(data_strategy())
2164 def test_call(self, d):
2165 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2173 ) = d.draw(oid_values_strategy())
2174 obj_initial = klass(
2175 value=value_initial,
2178 default=default_initial,
2179 optional=optional_initial or False,
2180 _decoded=_decoded_initial,
2189 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2198 value_expected = default if value is None else value
2200 default_initial if value_expected is None
2203 self.assertEqual(obj, value_expected)
2204 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2205 self.assertEqual(obj.expl_tag, expl or expl_initial)
2208 default_initial if default is None else default,
2210 if obj.default is None:
2211 optional = optional_initial if optional is None else optional
2212 optional = False if optional is None else optional
2215 self.assertEqual(obj.optional, optional)
2217 @given(oid_values_strategy())
2218 def test_copy(self, values):
2219 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2236 obj_copied = obj.copy()
2237 self.assert_copied_basic_fields(obj, obj_copied)
2238 self.assertEqual(obj._value, obj_copied._value)
2240 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2243 integers(min_value=1).map(tag_encode),
2245 def test_stripped(self, value, tag_impl):
2246 obj = ObjectIdentifier(value, impl=tag_impl)
2247 with self.assertRaises(NotEnoughData):
2248 obj.decode(obj.encode()[:-1])
2252 integers(min_value=1).map(tag_ctxc),
2254 def test_stripped_expl(self, value, tag_expl):
2255 obj = ObjectIdentifier(value, expl=tag_expl)
2256 with self.assertRaises(NotEnoughData):
2257 obj.decode(obj.encode()[:-1])
2260 integers(min_value=31),
2261 integers(min_value=0),
2264 def test_bad_tag(self, tag, offset, decode_path):
2265 with self.assertRaises(DecodeError) as err:
2266 ObjectIdentifier().decode(
2267 tag_encode(tag)[:-1],
2269 decode_path=decode_path,
2272 self.assertEqual(err.exception.offset, offset)
2273 self.assertEqual(err.exception.decode_path, decode_path)
2276 integers(min_value=128),
2277 integers(min_value=0),
2280 def test_bad_len(self, l, offset, decode_path):
2281 with self.assertRaises(DecodeError) as err:
2282 ObjectIdentifier().decode(
2283 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2285 decode_path=decode_path,
2288 self.assertEqual(err.exception.offset, offset)
2289 self.assertEqual(err.exception.decode_path, decode_path)
2291 def test_zero_oid(self):
2292 with self.assertRaises(NotEnoughData):
2293 ObjectIdentifier().decode(
2294 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2297 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2298 @given(oid_strategy())
2299 def test_unfinished_oid(self, value):
2300 assume(list(value)[-1] > 255)
2301 obj_encoded = ObjectIdentifier(value).encode()
2302 obj, _ = ObjectIdentifier().decode(obj_encoded)
2303 data = obj_encoded[obj.tlen + obj.llen:-1]
2305 ObjectIdentifier.tag_default,
2306 len_encode(len(data)),
2309 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2312 @given(integers(min_value=0))
2313 def test_invalid_short(self, value):
2314 with self.assertRaises(InvalidOID):
2315 ObjectIdentifier((value,))
2316 with self.assertRaises(InvalidOID):
2317 ObjectIdentifier("%d" % value)
2319 @given(integers(min_value=3), integers(min_value=0))
2320 def test_invalid_first_arc(self, first_arc, second_arc):
2321 with self.assertRaises(InvalidOID):
2322 ObjectIdentifier((first_arc, second_arc))
2323 with self.assertRaises(InvalidOID):
2324 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2326 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2327 def test_invalid_second_arc(self, first_arc, second_arc):
2328 with self.assertRaises(InvalidOID):
2329 ObjectIdentifier((first_arc, second_arc))
2330 with self.assertRaises(InvalidOID):
2331 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2333 @given(text(alphabet=ascii_letters + ".", min_size=1))
2334 def test_junk(self, oid):
2335 with self.assertRaises(InvalidOID):
2336 ObjectIdentifier(oid)
2338 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2339 @given(oid_strategy())
2340 def test_validness(self, oid):
2341 obj = ObjectIdentifier(oid)
2342 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2347 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2349 oid_values_strategy(),
2351 integers(min_value=1).map(tag_ctxc),
2352 integers(min_value=0),
2355 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2356 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2357 _, _, _, default, optional, _decoded = values
2366 self.assertFalse(obj.expled)
2367 obj_encoded = obj.encode()
2368 obj_expled = obj(value, expl=tag_expl)
2369 self.assertTrue(obj_expled.expled)
2372 obj_expled_encoded = obj_expled.encode()
2373 obj_decoded, tail = obj_expled.decode(
2374 obj_expled_encoded + tail_junk,
2379 self.assertEqual(tail, tail_junk)
2380 self.assertEqual(obj_decoded, obj_expled)
2381 self.assertNotEqual(obj_decoded, obj)
2382 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2383 self.assertEqual(tuple(obj_decoded), tuple(obj))
2384 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2385 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2386 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2388 obj_decoded.expl_llen,
2389 len(len_encode(len(obj_encoded))),
2391 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2392 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2395 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2397 self.assertEqual(obj_decoded.expl_offset, offset)
2400 oid_strategy().map(ObjectIdentifier),
2401 oid_strategy().map(ObjectIdentifier),
2403 def test_add(self, oid1, oid2):
2404 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2405 for oid_to_add in (oid2, tuple(oid2)):
2406 self.assertEqual(oid1 + oid_to_add, oid_expect)
2407 with self.assertRaises(InvalidValueType):
2410 def test_go_vectors_valid(self):
2411 for data, expect in (
2413 (b"\x55\x02", (2, 5, 2)),
2414 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2415 (b"\x81\x34\x03", (2, 100, 3)),
2418 ObjectIdentifier().decode(b"".join((
2419 ObjectIdentifier.tag_default,
2420 len_encode(len(data)),
2426 def test_go_vectors_invalid(self):
2427 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2428 with self.assertRaises(DecodeError):
2429 ObjectIdentifier().decode(b"".join((
2430 Integer.tag_default,
2431 len_encode(len(data)),
2435 def test_x690_vector(self):
2437 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2438 ObjectIdentifier((2, 999, 3)),
2443 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2445 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2446 values = list(draw(sets(
2448 min_size=len(schema),
2449 max_size=len(schema),
2451 schema = list(zip(schema, values))
2452 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2456 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2458 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2459 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2460 optional = draw(one_of(none(), booleans()))
2462 draw(integers(min_value=0)),
2463 draw(integers(min_value=0)),
2464 draw(integers(min_value=0)),
2466 return (schema, value, impl, expl, default, optional, _decoded)
2469 class TestEnumerated(CommonMixin, TestCase):
2470 class EWhatever(Enumerated):
2471 schema = (("whatever", 0),)
2473 base_klass = EWhatever
2475 def test_schema_required(self):
2476 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2479 def test_invalid_value_type(self):
2480 with self.assertRaises(InvalidValueType) as err:
2481 self.base_klass((1, 2))
2484 @given(sets(text_letters(), min_size=2))
2485 def test_unknown_name(self, schema_input):
2486 missing = schema_input.pop()
2488 class E(Enumerated):
2489 schema = [(n, 123) for n in schema_input]
2490 with self.assertRaises(ObjUnknown) as err:
2495 sets(text_letters(), min_size=2),
2496 sets(integers(), min_size=2),
2498 def test_unknown_value(self, schema_input, values_input):
2500 missing_value = values_input.pop()
2501 _input = list(zip(schema_input, values_input))
2503 class E(Enumerated):
2505 with self.assertRaises(DecodeError) as err:
2510 def test_optional(self, optional):
2511 obj = self.base_klass(default="whatever", optional=optional)
2512 self.assertTrue(obj.optional)
2514 def test_ready(self):
2515 obj = self.base_klass()
2516 self.assertFalse(obj.ready)
2519 with self.assertRaises(ObjNotReady) as err:
2522 obj = self.base_klass("whatever")
2523 self.assertTrue(obj.ready)
2527 @given(integers(), integers(), binary(), binary())
2528 def test_comparison(self, value1, value2, tag1, tag2):
2529 class E(Enumerated):
2531 ("whatever0", value1),
2532 ("whatever1", value2),
2535 class EInherited(E):
2537 for klass in (E, EInherited):
2538 obj1 = klass(value1)
2539 obj2 = klass(value2)
2540 self.assertEqual(obj1 == obj2, value1 == value2)
2541 self.assertEqual(obj1 != obj2, value1 != value2)
2542 self.assertEqual(obj1 == int(obj2), value1 == value2)
2543 obj1 = klass(value1, impl=tag1)
2544 obj2 = klass(value1, impl=tag2)
2545 self.assertEqual(obj1 == obj2, tag1 == tag2)
2546 self.assertEqual(obj1 != obj2, tag1 != tag2)
2548 @given(data_strategy())
2549 def test_call(self, d):
2558 ) = d.draw(enumerated_values_strategy())
2560 class E(Enumerated):
2561 schema = schema_initial
2563 value=value_initial,
2566 default=default_initial,
2567 optional=optional_initial or False,
2568 _decoded=_decoded_initial,
2578 ) = d.draw(enumerated_values_strategy(
2579 schema=schema_initial,
2580 do_expl=impl_initial is None,
2590 value_expected = default if value is None else value
2592 default_initial if value_expected is None
2597 dict(schema_initial).get(value_expected, value_expected),
2599 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2600 self.assertEqual(obj.expl_tag, expl or expl_initial)
2603 default_initial if default is None else default,
2605 if obj.default is None:
2606 optional = optional_initial if optional is None else optional
2607 optional = False if optional is None else optional
2610 self.assertEqual(obj.optional, optional)
2611 self.assertEqual(obj.specs, dict(schema_initial))
2613 @given(enumerated_values_strategy())
2614 def test_copy(self, values):
2615 schema_input, value, impl, expl, default, optional, _decoded = values
2617 class E(Enumerated):
2618 schema = schema_input
2627 obj_copied = obj.copy()
2628 self.assert_copied_basic_fields(obj, obj_copied)
2629 self.assertEqual(obj.specs, obj_copied.specs)
2631 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2632 @given(data_strategy())
2633 def test_symmetric(self, d):
2634 schema_input, _, _, _, default, optional, _decoded = d.draw(
2635 enumerated_values_strategy(),
2637 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2638 offset = d.draw(integers(min_value=0))
2639 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2640 tail_junk = d.draw(binary(max_size=5))
2642 class E(Enumerated):
2643 schema = schema_input
2652 self.assertFalse(obj.expled)
2653 obj_encoded = obj.encode()
2654 obj_expled = obj(value, expl=tag_expl)
2655 self.assertTrue(obj_expled.expled)
2658 obj_expled_encoded = obj_expled.encode()
2659 obj_decoded, tail = obj_expled.decode(
2660 obj_expled_encoded + tail_junk,
2665 self.assertEqual(tail, tail_junk)
2666 self.assertEqual(obj_decoded, obj_expled)
2667 self.assertNotEqual(obj_decoded, obj)
2668 self.assertEqual(int(obj_decoded), int(obj_expled))
2669 self.assertEqual(int(obj_decoded), int(obj))
2670 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2671 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2672 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2674 obj_decoded.expl_llen,
2675 len(len_encode(len(obj_encoded))),
2677 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2678 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2681 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2683 self.assertEqual(obj_decoded.expl_offset, offset)
2687 def string_values_strategy(draw, alphabet, do_expl=False):
2688 bound_min, bound_max = sorted(draw(sets(
2689 integers(min_value=0, max_value=1 << 7),
2693 value = draw(one_of(
2695 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2697 default = draw(one_of(
2699 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2702 if draw(booleans()):
2703 bounds = (bound_min, bound_max)
2707 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2709 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2710 optional = draw(one_of(none(), booleans()))
2712 draw(integers(min_value=0)),
2713 draw(integers(min_value=0)),
2714 draw(integers(min_value=0)),
2716 return (value, bounds, impl, expl, default, optional, _decoded)
2719 class StringMixin(object):
2720 def test_invalid_value_type(self):
2721 with self.assertRaises(InvalidValueType) as err:
2722 self.base_klass((1, 2))
2725 def text_alphabet(self):
2726 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2727 return printable + whitespace
2731 def test_optional(self, optional):
2732 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2733 self.assertTrue(obj.optional)
2735 @given(data_strategy())
2736 def test_ready(self, d):
2737 obj = self.base_klass()
2738 self.assertFalse(obj.ready)
2742 with self.assertRaises(ObjNotReady) as err:
2745 value = d.draw(text(alphabet=self.text_alphabet()))
2746 obj = self.base_klass(value)
2747 self.assertTrue(obj.ready)
2752 @given(data_strategy())
2753 def test_comparison(self, d):
2754 value1 = d.draw(text(alphabet=self.text_alphabet()))
2755 value2 = d.draw(text(alphabet=self.text_alphabet()))
2756 tag1 = d.draw(binary(min_size=1))
2757 tag2 = d.draw(binary(min_size=1))
2758 obj1 = self.base_klass(value1)
2759 obj2 = self.base_klass(value2)
2760 self.assertEqual(obj1 == obj2, value1 == value2)
2761 self.assertEqual(obj1 != obj2, value1 != value2)
2762 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2763 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2764 obj1 = self.base_klass(value1, impl=tag1)
2765 obj2 = self.base_klass(value1, impl=tag2)
2766 self.assertEqual(obj1 == obj2, tag1 == tag2)
2767 self.assertEqual(obj1 != obj2, tag1 != tag2)
2769 @given(data_strategy())
2770 def test_bounds_satisfied(self, d):
2771 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2772 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2773 value = d.draw(text(
2774 alphabet=self.text_alphabet(),
2778 self.base_klass(value=value, bounds=(bound_min, bound_max))
2780 @given(data_strategy())
2781 def test_bounds_unsatisfied(self, d):
2782 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2783 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2784 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2785 with self.assertRaises(BoundsError) as err:
2786 self.base_klass(value=value, bounds=(bound_min, bound_max))
2788 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2789 with self.assertRaises(BoundsError) as err:
2790 self.base_klass(value=value, bounds=(bound_min, bound_max))
2793 @given(data_strategy())
2794 def test_call(self, d):
2803 ) = d.draw(string_values_strategy(self.text_alphabet()))
2804 obj_initial = self.base_klass(
2810 optional_initial or False,
2821 ) = d.draw(string_values_strategy(
2822 self.text_alphabet(),
2823 do_expl=impl_initial is None,
2825 if (default is None) and (obj_initial.default is not None):
2828 (bounds is None) and
2829 (value is not None) and
2830 (bounds_initial is not None) and
2831 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2835 (bounds is None) and
2836 (default is not None) and
2837 (bounds_initial is not None) and
2838 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2841 obj = obj_initial(value, bounds, impl, expl, default, optional)
2843 value_expected = default if value is None else value
2845 default_initial if value_expected is None
2848 self.assertEqual(obj, value_expected)
2849 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2850 self.assertEqual(obj.expl_tag, expl or expl_initial)
2853 default_initial if default is None else default,
2855 if obj.default is None:
2856 optional = optional_initial if optional is None else optional
2857 optional = False if optional is None else optional
2860 self.assertEqual(obj.optional, optional)
2862 (obj._bound_min, obj._bound_max),
2863 bounds or bounds_initial or (0, float("+inf")),
2866 @given(data_strategy())
2867 def test_copy(self, d):
2868 values = d.draw(string_values_strategy(self.text_alphabet()))
2869 obj = self.base_klass(*values)
2870 obj_copied = obj.copy()
2871 self.assert_copied_basic_fields(obj, obj_copied)
2872 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2873 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2874 self.assertEqual(obj._value, obj_copied._value)
2876 @given(data_strategy())
2877 def test_stripped(self, d):
2878 value = d.draw(text(alphabet=self.text_alphabet()))
2879 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2880 obj = self.base_klass(value, impl=tag_impl)
2881 with self.assertRaises(NotEnoughData):
2882 obj.decode(obj.encode()[:-1])
2884 @given(data_strategy())
2885 def test_stripped_expl(self, d):
2886 value = d.draw(text(alphabet=self.text_alphabet()))
2887 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2888 obj = self.base_klass(value, expl=tag_expl)
2889 with self.assertRaises(NotEnoughData):
2890 obj.decode(obj.encode()[:-1])
2893 integers(min_value=31),
2894 integers(min_value=0),
2897 def test_bad_tag(self, tag, offset, decode_path):
2898 with self.assertRaises(DecodeError) as err:
2899 self.base_klass().decode(
2900 tag_encode(tag)[:-1],
2902 decode_path=decode_path,
2905 self.assertEqual(err.exception.offset, offset)
2906 self.assertEqual(err.exception.decode_path, decode_path)
2909 integers(min_value=128),
2910 integers(min_value=0),
2913 def test_bad_len(self, l, offset, decode_path):
2914 with self.assertRaises(DecodeError) as err:
2915 self.base_klass().decode(
2916 self.base_klass.tag_default + len_encode(l)[:-1],
2918 decode_path=decode_path,
2921 self.assertEqual(err.exception.offset, offset)
2922 self.assertEqual(err.exception.decode_path, decode_path)
2925 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2926 integers(min_value=0),
2929 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2930 value, bound_min = list(sorted(ints))
2932 class String(self.base_klass):
2933 # Multiply this value by four, to satisfy UTF-32 bounds
2934 # (4 bytes per character) validation
2935 bounds = (bound_min * 4, bound_min * 4)
2936 with self.assertRaises(DecodeError) as err:
2938 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2940 decode_path=decode_path,
2943 self.assertEqual(err.exception.offset, offset)
2944 self.assertEqual(err.exception.decode_path, decode_path)
2946 @given(data_strategy())
2947 def test_symmetric(self, d):
2948 values = d.draw(string_values_strategy(self.text_alphabet()))
2949 value = d.draw(text(alphabet=self.text_alphabet()))
2950 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2951 offset = d.draw(integers(min_value=0))
2952 tail_junk = d.draw(binary(max_size=5))
2953 _, _, _, _, default, optional, _decoded = values
2954 obj = self.base_klass(
2962 self.assertFalse(obj.expled)
2963 obj_encoded = obj.encode()
2964 obj_expled = obj(value, expl=tag_expl)
2965 self.assertTrue(obj_expled.expled)
2968 obj_expled_encoded = obj_expled.encode()
2969 obj_decoded, tail = obj_expled.decode(
2970 obj_expled_encoded + tail_junk,
2975 self.assertEqual(tail, tail_junk)
2976 self.assertEqual(obj_decoded, obj_expled)
2977 self.assertNotEqual(obj_decoded, obj)
2978 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2979 self.assertEqual(bytes(obj_decoded), bytes(obj))
2980 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2981 self.assertEqual(text_type(obj_decoded), text_type(obj))
2982 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2983 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2984 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2986 obj_decoded.expl_llen,
2987 len(len_encode(len(obj_encoded))),
2989 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2990 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2993 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2995 self.assertEqual(obj_decoded.expl_offset, offset)
2998 class TestUTF8String(StringMixin, CommonMixin, TestCase):
2999 base_klass = UTF8String
3002 class UnicodeDecodeErrorMixin(object):
3004 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3008 def test_unicode_decode_error(self, cyrillic_text):
3009 with self.assertRaises(DecodeError):
3010 self.base_klass(cyrillic_text)
3013 class TestNumericString(StringMixin, CommonMixin, TestCase):
3014 base_klass = NumericString
3016 def text_alphabet(self):
3019 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3020 def test_non_numeric(self, cyrillic_text):
3021 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3022 self.base_klass(cyrillic_text)
3025 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3026 integers(min_value=0),
3029 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3030 value, bound_min = list(sorted(ints))
3032 class String(self.base_klass):
3033 bounds = (bound_min, bound_min)
3034 with self.assertRaises(DecodeError) as err:
3036 self.base_klass(b"1" * value).encode(),
3038 decode_path=decode_path,
3041 self.assertEqual(err.exception.offset, offset)
3042 self.assertEqual(err.exception.decode_path, decode_path)
3045 class TestPrintableString(
3046 UnicodeDecodeErrorMixin,
3051 base_klass = PrintableString
3054 class TestTeletexString(
3055 UnicodeDecodeErrorMixin,
3060 base_klass = TeletexString
3063 class TestVideotexString(
3064 UnicodeDecodeErrorMixin,
3069 base_klass = VideotexString
3072 class TestIA5String(
3073 UnicodeDecodeErrorMixin,
3078 base_klass = IA5String
3081 class TestGraphicString(
3082 UnicodeDecodeErrorMixin,
3087 base_klass = GraphicString
3090 class TestVisibleString(
3091 UnicodeDecodeErrorMixin,
3096 base_klass = VisibleString
3098 def test_x690_vector(self):
3099 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3100 self.assertSequenceEqual(tail, b"")
3101 self.assertEqual(str(obj), "Jones")
3102 self.assertFalse(obj.bered)
3103 self.assertFalse(obj.lenindef)
3105 obj, tail = VisibleString().decode(
3106 hexdec("3A0904034A6F6E04026573"),
3107 ctx={"bered": True},
3109 self.assertSequenceEqual(tail, b"")
3110 self.assertEqual(str(obj), "Jones")
3111 self.assertTrue(obj.bered)
3112 self.assertFalse(obj.lenindef)
3114 obj, tail = VisibleString().decode(
3115 hexdec("3A8004034A6F6E040265730000"),
3116 ctx={"bered": True},
3118 self.assertSequenceEqual(tail, b"")
3119 self.assertEqual(str(obj), "Jones")
3120 self.assertTrue(obj.bered)
3121 self.assertTrue(obj.lenindef)
3124 class TestGeneralString(
3125 UnicodeDecodeErrorMixin,
3130 base_klass = GeneralString
3133 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3134 base_klass = UniversalString
3137 class TestBMPString(StringMixin, CommonMixin, TestCase):
3138 base_klass = BMPString
3142 def generalized_time_values_strategy(
3150 if draw(booleans()):
3151 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3153 value = value.replace(microsecond=0)
3155 if draw(booleans()):
3156 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3158 default = default.replace(microsecond=0)
3162 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3164 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3165 optional = draw(one_of(none(), booleans()))
3167 draw(integers(min_value=0)),
3168 draw(integers(min_value=0)),
3169 draw(integers(min_value=0)),
3171 return (value, impl, expl, default, optional, _decoded)
3174 class TimeMixin(object):
3175 def test_invalid_value_type(self):
3176 with self.assertRaises(InvalidValueType) as err:
3177 self.base_klass(datetime.now().timetuple())
3180 @given(data_strategy())
3181 def test_optional(self, d):
3182 default = d.draw(datetimes(
3183 min_value=self.min_datetime,
3184 max_value=self.max_datetime,
3186 optional = d.draw(booleans())
3187 obj = self.base_klass(default=default, optional=optional)
3188 self.assertTrue(obj.optional)
3190 @given(data_strategy())
3191 def test_ready(self, d):
3192 obj = self.base_klass()
3193 self.assertFalse(obj.ready)
3196 with self.assertRaises(ObjNotReady) as err:
3199 value = d.draw(datetimes(min_value=self.min_datetime))
3200 obj = self.base_klass(value)
3201 self.assertTrue(obj.ready)
3205 @given(data_strategy())
3206 def test_comparison(self, d):
3207 value1 = d.draw(datetimes(
3208 min_value=self.min_datetime,
3209 max_value=self.max_datetime,
3211 value2 = d.draw(datetimes(
3212 min_value=self.min_datetime,
3213 max_value=self.max_datetime,
3215 tag1 = d.draw(binary(min_size=1))
3216 tag2 = d.draw(binary(min_size=1))
3218 value1 = value1.replace(microsecond=0)
3219 value2 = value2.replace(microsecond=0)
3220 obj1 = self.base_klass(value1)
3221 obj2 = self.base_klass(value2)
3222 self.assertEqual(obj1 == obj2, value1 == value2)
3223 self.assertEqual(obj1 != obj2, value1 != value2)
3224 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3225 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3226 obj1 = self.base_klass(value1, impl=tag1)
3227 obj2 = self.base_klass(value1, impl=tag2)
3228 self.assertEqual(obj1 == obj2, tag1 == tag2)
3229 self.assertEqual(obj1 != obj2, tag1 != tag2)
3231 @given(data_strategy())
3232 def test_call(self, d):
3240 ) = d.draw(generalized_time_values_strategy(
3241 min_datetime=self.min_datetime,
3242 max_datetime=self.max_datetime,
3243 omit_ms=self.omit_ms,
3245 obj_initial = self.base_klass(
3246 value=value_initial,
3249 default=default_initial,
3250 optional=optional_initial or False,
3251 _decoded=_decoded_initial,
3260 ) = d.draw(generalized_time_values_strategy(
3261 min_datetime=self.min_datetime,
3262 max_datetime=self.max_datetime,
3263 omit_ms=self.omit_ms,
3264 do_expl=impl_initial is None,
3274 value_expected = default if value is None else value
3276 default_initial if value_expected is None
3279 self.assertEqual(obj, value_expected)
3280 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3281 self.assertEqual(obj.expl_tag, expl or expl_initial)
3284 default_initial if default is None else default,
3286 if obj.default is None:
3287 optional = optional_initial if optional is None else optional
3288 optional = False if optional is None else optional
3291 self.assertEqual(obj.optional, optional)
3293 @given(data_strategy())
3294 def test_copy(self, d):
3295 values = d.draw(generalized_time_values_strategy(
3296 min_datetime=self.min_datetime,
3297 max_datetime=self.max_datetime,
3299 obj = self.base_klass(*values)
3300 obj_copied = obj.copy()
3301 self.assert_copied_basic_fields(obj, obj_copied)
3302 self.assertEqual(obj._value, obj_copied._value)
3304 @given(data_strategy())
3305 def test_stripped(self, d):
3306 value = d.draw(datetimes(
3307 min_value=self.min_datetime,
3308 max_value=self.max_datetime,
3310 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3311 obj = self.base_klass(value, impl=tag_impl)
3312 with self.assertRaises(NotEnoughData):
3313 obj.decode(obj.encode()[:-1])
3315 @given(data_strategy())
3316 def test_stripped_expl(self, d):
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 obj = self.base_klass(value, expl=tag_expl)
3323 with self.assertRaises(NotEnoughData):
3324 obj.decode(obj.encode()[:-1])
3326 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3327 @given(data_strategy())
3328 def test_symmetric(self, d):
3329 values = d.draw(generalized_time_values_strategy(
3330 min_datetime=self.min_datetime,
3331 max_datetime=self.max_datetime,
3333 value = d.draw(datetimes(
3334 min_value=self.min_datetime,
3335 max_value=self.max_datetime,
3337 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3338 offset = d.draw(integers(min_value=0))
3339 tail_junk = d.draw(binary(max_size=5))
3340 _, _, _, default, optional, _decoded = values
3341 obj = self.base_klass(
3349 self.assertFalse(obj.expled)
3350 obj_encoded = obj.encode()
3351 obj_expled = obj(value, expl=tag_expl)
3352 self.assertTrue(obj_expled.expled)
3355 obj_expled_encoded = obj_expled.encode()
3356 obj_decoded, tail = obj_expled.decode(
3357 obj_expled_encoded + tail_junk,
3362 self.assertEqual(tail, tail_junk)
3363 self.assertEqual(obj_decoded, obj_expled)
3364 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3365 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3366 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3367 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3368 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3370 obj_decoded.expl_llen,
3371 len(len_encode(len(obj_encoded))),
3373 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3374 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3377 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3379 self.assertEqual(obj_decoded.expl_offset, offset)
3382 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3383 base_klass = GeneralizedTime
3385 min_datetime = datetime(1900, 1, 1)
3386 max_datetime = datetime(9999, 12, 31)
3388 def test_go_vectors_invalid(self):
3400 b"-20100102030410Z",
3401 b"2010-0102030410Z",
3402 b"2010-0002030410Z",
3403 b"201001-02030410Z",
3404 b"20100102-030410Z",
3405 b"2010010203-0410Z",
3406 b"201001020304-10Z",
3407 # These ones are INVALID in *DER*, but accepted
3408 # by Go's encoding/asn1
3409 b"20100102030405+0607",
3410 b"20100102030405-0607",
3412 with self.assertRaises(DecodeError) as err:
3413 GeneralizedTime(data)
3416 def test_go_vectors_valid(self):
3418 GeneralizedTime(b"20100102030405Z").todatetime(),
3419 datetime(2010, 1, 2, 3, 4, 5, 0),
3423 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3424 base_klass = UTCTime
3426 min_datetime = datetime(2000, 1, 1)
3427 max_datetime = datetime(2049, 12, 31)
3429 def test_go_vectors_invalid(self):
3455 # These ones are INVALID in *DER*, but accepted
3456 # by Go's encoding/asn1
3457 b"910506164540-0700",
3458 b"910506164540+0730",
3462 with self.assertRaises(DecodeError) as err:
3466 def test_go_vectors_valid(self):
3468 UTCTime(b"910506234540Z").todatetime(),
3469 datetime(1991, 5, 6, 23, 45, 40, 0),
3472 @given(integers(min_value=0, max_value=49))
3473 def test_pre50(self, year):
3475 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3479 @given(integers(min_value=50, max_value=99))
3480 def test_post50(self, year):
3482 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3488 def any_values_strategy(draw, do_expl=False):
3489 value = draw(one_of(none(), binary()))
3492 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3493 optional = draw(one_of(none(), booleans()))
3495 draw(integers(min_value=0)),
3496 draw(integers(min_value=0)),
3497 draw(integers(min_value=0)),
3499 return (value, expl, optional, _decoded)
3502 class AnyInherited(Any):
3506 class TestAny(CommonMixin, TestCase):
3509 def test_invalid_value_type(self):
3510 with self.assertRaises(InvalidValueType) as err:
3515 def test_optional(self, optional):
3516 obj = Any(optional=optional)
3517 self.assertEqual(obj.optional, optional)
3520 def test_ready(self, value):
3522 self.assertFalse(obj.ready)
3525 with self.assertRaises(ObjNotReady) as err:
3529 self.assertTrue(obj.ready)
3534 def test_basic(self, value):
3535 integer_encoded = Integer(value).encode()
3537 Any(integer_encoded),
3538 Any(Integer(value)),
3539 Any(Any(Integer(value))),
3541 self.assertSequenceEqual(bytes(obj), integer_encoded)
3543 obj.decode(obj.encode())[0].vlen,
3544 len(integer_encoded),
3548 self.assertSequenceEqual(obj.encode(), integer_encoded)
3550 @given(binary(), binary())
3551 def test_comparison(self, value1, value2):
3552 for klass in (Any, AnyInherited):
3553 obj1 = klass(value1)
3554 obj2 = klass(value2)
3555 self.assertEqual(obj1 == obj2, value1 == value2)
3556 self.assertEqual(obj1 != obj2, value1 != value2)
3557 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3559 @given(data_strategy())
3560 def test_call(self, d):
3561 for klass in (Any, AnyInherited):
3567 ) = d.draw(any_values_strategy())
3568 obj_initial = klass(
3571 optional_initial or False,
3579 ) = d.draw(any_values_strategy(do_expl=True))
3580 obj = obj_initial(value, expl, optional)
3582 value_expected = None if value is None else value
3583 self.assertEqual(obj, value_expected)
3584 self.assertEqual(obj.expl_tag, expl or expl_initial)
3585 if obj.default is None:
3586 optional = optional_initial if optional is None else optional
3587 optional = False if optional is None else optional
3588 self.assertEqual(obj.optional, optional)
3590 def test_simultaneous_impl_expl(self):
3591 # override it, as Any does not have implicit tag
3594 def test_decoded(self):
3595 # override it, as Any does not have implicit tag
3598 @given(any_values_strategy())
3599 def test_copy(self, values):
3600 for klass in (Any, AnyInherited):
3601 obj = klass(*values)
3602 obj_copied = obj.copy()
3603 self.assert_copied_basic_fields(obj, obj_copied)
3604 self.assertEqual(obj._value, obj_copied._value)
3606 @given(binary().map(OctetString))
3607 def test_stripped(self, value):
3609 with self.assertRaises(NotEnoughData):
3610 obj.decode(obj.encode()[:-1])
3614 integers(min_value=1).map(tag_ctxc),
3616 def test_stripped_expl(self, value, tag_expl):
3617 obj = Any(value, expl=tag_expl)
3618 with self.assertRaises(NotEnoughData):
3619 obj.decode(obj.encode()[:-1])
3622 integers(min_value=31),
3623 integers(min_value=0),
3626 def test_bad_tag(self, tag, offset, decode_path):
3627 with self.assertRaises(DecodeError) as err:
3629 tag_encode(tag)[:-1],
3631 decode_path=decode_path,
3634 self.assertEqual(err.exception.offset, offset)
3635 self.assertEqual(err.exception.decode_path, decode_path)
3638 integers(min_value=128),
3639 integers(min_value=0),
3642 def test_bad_len(self, l, offset, decode_path):
3643 with self.assertRaises(DecodeError) as err:
3645 Any.tag_default + len_encode(l)[:-1],
3647 decode_path=decode_path,
3650 self.assertEqual(err.exception.offset, offset)
3651 self.assertEqual(err.exception.decode_path, decode_path)
3653 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3655 any_values_strategy(),
3656 integers().map(lambda x: Integer(x).encode()),
3657 integers(min_value=1).map(tag_ctxc),
3658 integers(min_value=0),
3661 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3662 for klass in (Any, AnyInherited):
3663 _, _, optional, _decoded = values
3664 obj = klass(value=value, optional=optional, _decoded=_decoded)
3667 self.assertFalse(obj.expled)
3668 obj_encoded = obj.encode()
3669 obj_expled = obj(value, expl=tag_expl)
3670 self.assertTrue(obj_expled.expled)
3673 obj_expled_encoded = obj_expled.encode()
3674 obj_decoded, tail = obj_expled.decode(
3675 obj_expled_encoded + tail_junk,
3680 self.assertEqual(tail, tail_junk)
3681 self.assertEqual(obj_decoded, obj_expled)
3682 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3683 self.assertEqual(bytes(obj_decoded), bytes(obj))
3684 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3685 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3686 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3688 obj_decoded.expl_llen,
3689 len(len_encode(len(obj_encoded))),
3691 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3692 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3695 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3697 self.assertEqual(obj_decoded.expl_offset, offset)
3698 self.assertEqual(obj_decoded.tlen, 0)
3699 self.assertEqual(obj_decoded.llen, 0)
3700 self.assertEqual(obj_decoded.vlen, len(value))
3704 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3706 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3707 tags = [tag_encode(tag) for tag in draw(sets(
3708 integers(min_value=0),
3709 min_size=len(names),
3710 max_size=len(names),
3712 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3714 if value_required or draw(booleans()):
3715 value = draw(tuples(
3716 sampled_from([name for name, _ in schema]),
3717 integers().map(Integer),
3721 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3722 default = draw(one_of(
3724 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3726 optional = draw(one_of(none(), booleans()))
3728 draw(integers(min_value=0)),
3729 draw(integers(min_value=0)),
3730 draw(integers(min_value=0)),
3732 return (schema, value, expl, default, optional, _decoded)
3735 class ChoiceInherited(Choice):
3739 class TestChoice(CommonMixin, TestCase):
3741 schema = (("whatever", Boolean()),)
3744 def test_schema_required(self):
3745 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3748 def test_impl_forbidden(self):
3749 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3750 Choice(impl=b"whatever")
3752 def test_invalid_value_type(self):
3753 with self.assertRaises(InvalidValueType) as err:
3754 self.base_klass(123)
3756 with self.assertRaises(ObjUnknown) as err:
3757 self.base_klass(("whenever", Boolean(False)))
3759 with self.assertRaises(InvalidValueType) as err:
3760 self.base_klass(("whatever", Integer(123)))
3764 def test_optional(self, optional):
3765 obj = self.base_klass(
3766 default=self.base_klass(("whatever", Boolean(False))),
3769 self.assertTrue(obj.optional)
3772 def test_ready(self, value):
3773 obj = self.base_klass()
3774 self.assertFalse(obj.ready)
3777 self.assertIsNone(obj["whatever"])
3778 with self.assertRaises(ObjNotReady) as err:
3781 obj["whatever"] = Boolean()
3782 self.assertFalse(obj.ready)
3785 obj["whatever"] = Boolean(value)
3786 self.assertTrue(obj.ready)
3790 @given(booleans(), booleans())
3791 def test_comparison(self, value1, value2):
3792 class WahlInherited(self.base_klass):
3794 for klass in (self.base_klass, WahlInherited):
3795 obj1 = klass(("whatever", Boolean(value1)))
3796 obj2 = klass(("whatever", Boolean(value2)))
3797 self.assertEqual(obj1 == obj2, value1 == value2)
3798 self.assertEqual(obj1 != obj2, value1 != value2)
3799 self.assertEqual(obj1 == obj2._value, value1 == value2)
3800 self.assertFalse(obj1 == obj2._value[1])
3802 @given(data_strategy())
3803 def test_call(self, d):
3804 for klass in (Choice, ChoiceInherited):
3812 ) = d.draw(choice_values_strategy())
3815 schema = schema_initial
3817 value=value_initial,
3819 default=default_initial,
3820 optional=optional_initial or False,
3821 _decoded=_decoded_initial,
3830 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
3831 obj = obj_initial(value, expl, default, optional)
3833 value_expected = default if value is None else value
3835 default_initial if value_expected is None
3838 self.assertEqual(obj.choice, value_expected[0])
3839 self.assertEqual(obj.value, int(value_expected[1]))
3840 self.assertEqual(obj.expl_tag, expl or expl_initial)
3841 default_expect = default_initial if default is None else default
3842 if default_expect is not None:
3843 self.assertEqual(obj.default.choice, default_expect[0])
3844 self.assertEqual(obj.default.value, int(default_expect[1]))
3845 if obj.default is None:
3846 optional = optional_initial if optional is None else optional
3847 optional = False if optional is None else optional
3850 self.assertEqual(obj.optional, optional)
3851 self.assertEqual(obj.specs, obj_initial.specs)
3853 def test_simultaneous_impl_expl(self):
3854 # override it, as Any does not have implicit tag
3857 def test_decoded(self):
3858 # override it, as Any does not have implicit tag
3861 @given(choice_values_strategy())
3862 def test_copy(self, values):
3863 _schema, value, expl, default, optional, _decoded = values
3865 class Wahl(self.base_klass):
3871 optional=optional or False,
3874 obj_copied = obj.copy()
3875 self.assertIsNone(obj.tag)
3876 self.assertIsNone(obj_copied.tag)
3877 # hack for assert_copied_basic_fields
3878 obj.tag = "whatever"
3879 obj_copied.tag = "whatever"
3880 self.assert_copied_basic_fields(obj, obj_copied)
3881 self.assertEqual(obj._value, obj_copied._value)
3882 self.assertEqual(obj.specs, obj_copied.specs)
3885 def test_stripped(self, value):
3886 obj = self.base_klass(("whatever", Boolean(value)))
3887 with self.assertRaises(NotEnoughData):
3888 obj.decode(obj.encode()[:-1])
3892 integers(min_value=1).map(tag_ctxc),
3894 def test_stripped_expl(self, value, tag_expl):
3895 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3896 with self.assertRaises(NotEnoughData):
3897 obj.decode(obj.encode()[:-1])
3899 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3900 @given(data_strategy())
3901 def test_symmetric(self, d):
3902 _schema, value, _, default, optional, _decoded = d.draw(
3903 choice_values_strategy(value_required=True)
3905 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3906 offset = d.draw(integers(min_value=0))
3907 tail_junk = d.draw(binary(max_size=5))
3909 class Wahl(self.base_klass):
3919 self.assertFalse(obj.expled)
3920 obj_encoded = obj.encode()
3921 obj_expled = obj(value, expl=tag_expl)
3922 self.assertTrue(obj_expled.expled)
3925 obj_expled_encoded = obj_expled.encode()
3926 obj_decoded, tail = obj_expled.decode(
3927 obj_expled_encoded + tail_junk,
3932 self.assertEqual(tail, tail_junk)
3933 self.assertEqual(obj_decoded, obj_expled)
3934 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3935 self.assertEqual(obj_decoded.value, obj_expled.value)
3936 self.assertEqual(obj_decoded.choice, obj.choice)
3937 self.assertEqual(obj_decoded.value, obj.value)
3938 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3939 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3940 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3942 obj_decoded.expl_llen,
3943 len(len_encode(len(obj_encoded))),
3945 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3946 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3949 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3951 self.assertEqual(obj_decoded.expl_offset, offset)
3952 self.assertSequenceEqual(
3954 obj_decoded.value.offset - offset:
3955 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3961 def test_set_get(self, value):
3964 ("erste", Boolean()),
3965 ("zweite", Integer()),
3968 with self.assertRaises(ObjUnknown) as err:
3969 obj["whatever"] = "whenever"
3970 with self.assertRaises(InvalidValueType) as err:
3971 obj["zweite"] = Boolean(False)
3972 obj["zweite"] = Integer(value)
3974 with self.assertRaises(ObjUnknown) as err:
3977 self.assertIsNone(obj["erste"])
3978 self.assertEqual(obj["zweite"], Integer(value))
3980 def test_tag_mismatch(self):
3983 ("erste", Boolean()),
3985 int_encoded = Integer(123).encode()
3986 bool_encoded = Boolean(False).encode()
3988 obj.decode(bool_encoded)
3989 with self.assertRaises(TagMismatch):
3990 obj.decode(int_encoded)
3992 def test_tag_mismatch_underlying(self):
3993 class SeqOfBoolean(SequenceOf):
3996 class SeqOfInteger(SequenceOf):
4001 ("erste", SeqOfBoolean()),
4004 int_encoded = SeqOfInteger((Integer(123),)).encode()
4005 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4007 obj.decode(bool_encoded)
4008 with self.assertRaises(TagMismatch) as err:
4009 obj.decode(int_encoded)
4010 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4014 def seq_values_strategy(draw, seq_klass, do_expl=False):
4016 if draw(booleans()):
4019 k: v for k, v in draw(dictionaries(
4022 booleans().map(Boolean),
4023 integers().map(Integer),
4028 if draw(booleans()):
4029 schema = list(draw(dictionaries(
4032 booleans().map(Boolean),
4033 integers().map(Integer),
4039 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4041 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4043 if draw(booleans()):
4044 default = seq_klass()
4046 k: v for k, v in draw(dictionaries(
4049 booleans().map(Boolean),
4050 integers().map(Integer),
4054 optional = draw(one_of(none(), booleans()))
4056 draw(integers(min_value=0)),
4057 draw(integers(min_value=0)),
4058 draw(integers(min_value=0)),
4060 return (value, schema, impl, expl, default, optional, _decoded)
4064 def sequence_strategy(draw, seq_klass):
4065 inputs = draw(lists(
4067 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4068 tuples(just(Integer), integers(), one_of(none(), integers())),
4073 integers(min_value=1),
4074 min_size=len(inputs),
4075 max_size=len(inputs),
4078 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4079 for tag, expled in zip(tags, draw(lists(
4081 min_size=len(inputs),
4082 max_size=len(inputs),
4086 for i, optional in enumerate(draw(lists(
4087 sampled_from(("required", "optional", "empty")),
4088 min_size=len(inputs),
4089 max_size=len(inputs),
4091 if optional in ("optional", "empty"):
4092 inits[i]["optional"] = True
4093 if optional == "empty":
4095 empties = set(empties)
4096 names = list(draw(sets(
4098 min_size=len(inputs),
4099 max_size=len(inputs),
4102 for i, (klass, value, default) in enumerate(inputs):
4103 schema.append((names[i], klass(default=default, **inits[i])))
4104 seq_name = draw(text_letters())
4105 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4108 for i, (klass, value, default) in enumerate(inputs):
4115 "default_value": None if spec.default is None else default,
4119 expect["optional"] = True
4121 expect["presented"] = True
4122 expect["value"] = value
4124 expect["optional"] = True
4125 if default is not None and default == value:
4126 expect["presented"] = False
4127 seq[name] = klass(value)
4128 expects.append(expect)
4133 def sequences_strategy(draw, seq_klass):
4134 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4136 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4137 for tag, expled in zip(tags, draw(lists(
4144 i for i, is_default in enumerate(draw(lists(
4150 names = list(draw(sets(
4155 seq_expectses = draw(lists(
4156 sequence_strategy(seq_klass=seq_klass),
4160 seqs = [seq for seq, _ in seq_expectses]
4162 for i, (name, seq) in enumerate(zip(names, seqs)):
4165 seq(default=(seq if i in defaulted else None), **inits[i]),
4167 seq_name = draw(text_letters())
4168 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4171 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4174 "expects": expects_inner,
4177 seq_outer[name] = seq_inner
4178 if seq_outer.specs[name].default is None:
4179 expect["presented"] = True
4180 expect_outers.append(expect)
4181 return seq_outer, expect_outers
4184 class SeqMixing(object):
4185 def test_invalid_value_type(self):
4186 with self.assertRaises(InvalidValueType) as err:
4187 self.base_klass(123)
4190 def test_invalid_value_type_set(self):
4191 class Seq(self.base_klass):
4192 schema = (("whatever", Boolean()),)
4194 with self.assertRaises(InvalidValueType) as err:
4195 seq["whatever"] = Integer(123)
4199 def test_optional(self, optional):
4200 obj = self.base_klass(default=self.base_klass(), optional=optional)
4201 self.assertTrue(obj.optional)
4203 @given(data_strategy())
4204 def test_ready(self, d):
4206 str(i): v for i, v in enumerate(d.draw(lists(
4213 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4220 for name in d.draw(permutations(
4221 list(ready.keys()) + list(non_ready.keys()),
4223 schema_input.append((name, Boolean()))
4225 class Seq(self.base_klass):
4226 schema = tuple(schema_input)
4228 for name in ready.keys():
4230 seq[name] = Boolean()
4231 self.assertFalse(seq.ready)
4234 for name, value in ready.items():
4235 seq[name] = Boolean(value)
4236 self.assertFalse(seq.ready)
4239 with self.assertRaises(ObjNotReady) as err:
4242 for name, value in non_ready.items():
4243 seq[name] = Boolean(value)
4244 self.assertTrue(seq.ready)
4248 @given(data_strategy())
4249 def test_call(self, d):
4250 class SeqInherited(self.base_klass):
4252 for klass in (self.base_klass, SeqInherited):
4261 ) = d.draw(seq_values_strategy(seq_klass=klass))
4262 obj_initial = klass(
4268 optional_initial or False,
4279 ) = d.draw(seq_values_strategy(
4281 do_expl=impl_initial is None,
4283 obj = obj_initial(value, impl, expl, default, optional)
4284 value_expected = default if value is None else value
4286 default_initial if value_expected is None
4289 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4290 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4291 self.assertEqual(obj.expl_tag, expl or expl_initial)
4293 {} if obj.default is None else obj.default._value,
4294 getattr(default_initial if default is None else default, "_value", {}),
4296 if obj.default is None:
4297 optional = optional_initial if optional is None else optional
4298 optional = False if optional is None else optional
4301 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4302 self.assertEqual(obj.optional, optional)
4304 @given(data_strategy())
4305 def test_copy(self, d):
4306 class SeqInherited(self.base_klass):
4308 for klass in (self.base_klass, SeqInherited):
4309 values = d.draw(seq_values_strategy(seq_klass=klass))
4310 obj = klass(*values)
4311 obj_copied = obj.copy()
4312 self.assert_copied_basic_fields(obj, obj_copied)
4313 self.assertEqual(obj.specs, obj_copied.specs)
4314 self.assertEqual(obj._value, obj_copied._value)
4316 @given(data_strategy())
4317 def test_stripped(self, d):
4318 value = d.draw(integers())
4319 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4321 class Seq(self.base_klass):
4323 schema = (("whatever", Integer()),)
4325 seq["whatever"] = Integer(value)
4326 with self.assertRaises(NotEnoughData):
4327 seq.decode(seq.encode()[:-1])
4329 @given(data_strategy())
4330 def test_stripped_expl(self, d):
4331 value = d.draw(integers())
4332 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4334 class Seq(self.base_klass):
4336 schema = (("whatever", Integer()),)
4338 seq["whatever"] = Integer(value)
4339 with self.assertRaises(NotEnoughData):
4340 seq.decode(seq.encode()[:-1])
4342 @given(binary(min_size=2))
4343 def test_non_tag_mismatch_raised(self, junk):
4345 _, _, len_encoded = tag_strip(memoryview(junk))
4346 len_decode(len_encoded)
4352 class Seq(self.base_klass):
4354 ("whatever", Integer()),
4356 ("whenever", Integer()),
4359 seq["whatever"] = Integer(123)
4360 seq["junk"] = Any(junk)
4361 seq["whenever"] = Integer(123)
4362 with self.assertRaises(DecodeError):
4363 seq.decode(seq.encode())
4366 integers(min_value=31),
4367 integers(min_value=0),
4370 def test_bad_tag(self, tag, offset, decode_path):
4371 with self.assertRaises(DecodeError) as err:
4372 self.base_klass().decode(
4373 tag_encode(tag)[:-1],
4375 decode_path=decode_path,
4378 self.assertEqual(err.exception.offset, offset)
4379 self.assertEqual(err.exception.decode_path, decode_path)
4382 integers(min_value=128),
4383 integers(min_value=0),
4386 def test_bad_len(self, l, offset, decode_path):
4387 with self.assertRaises(DecodeError) as err:
4388 self.base_klass().decode(
4389 self.base_klass.tag_default + len_encode(l)[:-1],
4391 decode_path=decode_path,
4394 self.assertEqual(err.exception.offset, offset)
4395 self.assertEqual(err.exception.decode_path, decode_path)
4397 def _assert_expects(self, seq, expects):
4398 for expect in expects:
4400 seq.specs[expect["name"]].optional,
4403 if expect["default_value"] is not None:
4405 seq.specs[expect["name"]].default,
4406 expect["default_value"],
4408 if expect["presented"]:
4409 self.assertIn(expect["name"], seq)
4410 self.assertEqual(seq[expect["name"]], expect["value"])
4412 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4413 @given(data_strategy())
4414 def test_symmetric(self, d):
4415 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4416 tail_junk = d.draw(binary(max_size=5))
4417 self.assertTrue(seq.ready)
4418 self.assertFalse(seq.decoded)
4419 self._assert_expects(seq, expects)
4422 seq_encoded = seq.encode()
4423 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4424 self.assertEqual(tail, tail_junk)
4425 self.assertTrue(seq.ready)
4426 self._assert_expects(seq_decoded, expects)
4427 self.assertEqual(seq, seq_decoded)
4428 self.assertEqual(seq_decoded.encode(), seq_encoded)
4429 for expect in expects:
4430 if not expect["presented"]:
4431 self.assertNotIn(expect["name"], seq_decoded)
4433 self.assertIn(expect["name"], seq_decoded)
4434 obj = seq_decoded[expect["name"]]
4435 self.assertTrue(obj.decoded)
4436 offset = obj.expl_offset if obj.expled else obj.offset
4437 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4438 self.assertSequenceEqual(
4439 seq_encoded[offset:offset + tlvlen],
4443 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4444 @given(data_strategy())
4445 def test_symmetric_with_seq(self, d):
4446 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4447 self.assertTrue(seq.ready)
4448 seq_encoded = seq.encode()
4449 seq_decoded, tail = seq.decode(seq_encoded)
4450 self.assertEqual(tail, b"")
4451 self.assertTrue(seq.ready)
4452 self.assertEqual(seq, seq_decoded)
4453 self.assertEqual(seq_decoded.encode(), seq_encoded)
4454 for expect_outer in expect_outers:
4455 if not expect_outer["presented"]:
4456 self.assertNotIn(expect_outer["name"], seq_decoded)
4458 self.assertIn(expect_outer["name"], seq_decoded)
4459 obj = seq_decoded[expect_outer["name"]]
4460 self.assertTrue(obj.decoded)
4461 offset = obj.expl_offset if obj.expled else obj.offset
4462 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4463 self.assertSequenceEqual(
4464 seq_encoded[offset:offset + tlvlen],
4467 self._assert_expects(obj, expect_outer["expects"])
4469 @given(data_strategy())
4470 def test_default_disappears(self, d):
4471 _schema = list(d.draw(dictionaries(
4473 sets(integers(), min_size=2, max_size=2),
4477 class Seq(self.base_klass):
4479 (n, Integer(default=d))
4480 for n, (_, d) in _schema
4483 for name, (value, _) in _schema:
4484 seq[name] = Integer(value)
4485 self.assertEqual(len(seq._value), len(_schema))
4486 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4487 self.assertGreater(len(seq.encode()), len(empty_seq))
4488 for name, (_, default) in _schema:
4489 seq[name] = Integer(default)
4490 self.assertEqual(len(seq._value), 0)
4491 self.assertSequenceEqual(seq.encode(), empty_seq)
4493 @given(data_strategy())
4494 def test_encoded_default_accepted(self, d):
4495 _schema = list(d.draw(dictionaries(
4500 tags = [tag_encode(tag) for tag in d.draw(sets(
4501 integers(min_value=0),
4502 min_size=len(_schema),
4503 max_size=len(_schema),
4506 class SeqWithoutDefault(self.base_klass):
4508 (n, Integer(impl=t))
4509 for (n, _), t in zip(_schema, tags)
4511 seq_without_default = SeqWithoutDefault()
4512 for name, value in _schema:
4513 seq_without_default[name] = Integer(value)
4514 seq_encoded = seq_without_default.encode()
4516 class SeqWithDefault(self.base_klass):
4518 (n, Integer(default=v, impl=t))
4519 for (n, v), t in zip(_schema, tags)
4521 seq_with_default = SeqWithDefault()
4522 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4523 for name, value in _schema:
4524 self.assertEqual(seq_decoded[name], seq_with_default[name])
4525 self.assertEqual(seq_decoded[name], value)
4527 @given(data_strategy())
4528 def test_missing_from_spec(self, d):
4529 names = list(d.draw(sets(text_letters(), min_size=2)))
4530 tags = [tag_encode(tag) for tag in d.draw(sets(
4531 integers(min_value=0),
4532 min_size=len(names),
4533 max_size=len(names),
4535 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4537 class SeqFull(self.base_klass):
4538 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4539 seq_full = SeqFull()
4540 for i, name in enumerate(names):
4541 seq_full[name] = Integer(i)
4542 seq_encoded = seq_full.encode()
4543 altered = names_tags[:-2] + names_tags[-1:]
4545 class SeqMissing(self.base_klass):
4546 schema = [(n, Integer(impl=t)) for n, t in altered]
4547 seq_missing = SeqMissing()
4548 with self.assertRaises(TagMismatch):
4549 seq_missing.decode(seq_encoded)
4552 class TestSequence(SeqMixing, CommonMixin, TestCase):
4553 base_klass = Sequence
4559 def test_remaining(self, value, junk):
4560 class Seq(Sequence):
4562 ("whatever", Integer()),
4564 int_encoded = Integer(value).encode()
4566 Sequence.tag_default,
4567 len_encode(len(int_encoded + junk)),
4570 with assertRaisesRegex(self, DecodeError, "remaining"):
4571 Seq().decode(junked)
4573 @given(sets(text_letters(), min_size=2))
4574 def test_obj_unknown(self, names):
4575 missing = names.pop()
4577 class Seq(Sequence):
4578 schema = [(n, Boolean()) for n in names]
4580 with self.assertRaises(ObjUnknown) as err:
4583 with self.assertRaises(ObjUnknown) as err:
4584 seq[missing] = Boolean()
4587 def test_x690_vector(self):
4588 class Seq(Sequence):
4590 ("name", IA5String()),
4593 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4594 self.assertEqual(seq["name"], "Smith")
4595 self.assertEqual(seq["ok"], True)
4598 class TestSet(SeqMixing, CommonMixin, TestCase):
4601 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4602 @given(data_strategy())
4603 def test_sorted(self, d):
4605 tag_encode(tag) for tag in
4606 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4610 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4612 for name, _ in Seq.schema:
4613 seq[name] = OctetString(b"")
4614 seq_encoded = seq.encode()
4615 seq_decoded, _ = seq.decode(seq_encoded)
4616 self.assertSequenceEqual(
4617 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4618 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4623 def seqof_values_strategy(draw, schema=None, do_expl=False):
4625 schema = draw(sampled_from((Boolean(), Integer())))
4626 bound_min, bound_max = sorted(draw(sets(
4627 integers(min_value=0, max_value=10),
4631 if isinstance(schema, Boolean):
4632 values_generator = booleans().map(Boolean)
4633 elif isinstance(schema, Integer):
4634 values_generator = integers().map(Integer)
4635 values_generator = lists(
4640 values = draw(one_of(none(), values_generator))
4644 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4646 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4647 default = draw(one_of(none(), values_generator))
4648 optional = draw(one_of(none(), booleans()))
4650 draw(integers(min_value=0)),
4651 draw(integers(min_value=0)),
4652 draw(integers(min_value=0)),
4657 (bound_min, bound_max),
4666 class SeqOfMixing(object):
4667 def test_invalid_value_type(self):
4668 with self.assertRaises(InvalidValueType) as err:
4669 self.base_klass(123)
4672 def test_invalid_values_type(self):
4673 class SeqOf(self.base_klass):
4675 with self.assertRaises(InvalidValueType) as err:
4676 SeqOf([Integer(123), Boolean(False), Integer(234)])
4679 def test_schema_required(self):
4680 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4681 self.base_klass.__mro__[1]()
4683 @given(booleans(), booleans(), binary(), binary())
4684 def test_comparison(self, value1, value2, tag1, tag2):
4685 class SeqOf(self.base_klass):
4687 obj1 = SeqOf([Boolean(value1)])
4688 obj2 = SeqOf([Boolean(value2)])
4689 self.assertEqual(obj1 == obj2, value1 == value2)
4690 self.assertEqual(obj1 != obj2, value1 != value2)
4691 self.assertEqual(obj1 == list(obj2), value1 == value2)
4692 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4693 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4694 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4695 self.assertEqual(obj1 == obj2, tag1 == tag2)
4696 self.assertEqual(obj1 != obj2, tag1 != tag2)
4698 @given(lists(booleans()))
4699 def test_iter(self, values):
4700 class SeqOf(self.base_klass):
4702 obj = SeqOf([Boolean(value) for value in values])
4703 self.assertEqual(len(obj), len(values))
4704 for i, value in enumerate(obj):
4705 self.assertEqual(value, values[i])
4707 @given(data_strategy())
4708 def test_ready(self, d):
4709 ready = [Integer(v) for v in d.draw(lists(
4716 range(d.draw(integers(min_value=1, max_value=5)))
4719 class SeqOf(self.base_klass):
4721 values = d.draw(permutations(ready + non_ready))
4723 for value in values:
4725 self.assertFalse(seqof.ready)
4728 with self.assertRaises(ObjNotReady) as err:
4731 for i, value in enumerate(values):
4732 self.assertEqual(seqof[i], value)
4733 if not seqof[i].ready:
4734 seqof[i] = Integer(i)
4735 self.assertTrue(seqof.ready)
4739 def test_spec_mismatch(self):
4740 class SeqOf(self.base_klass):
4743 seqof.append(Integer(123))
4744 with self.assertRaises(ValueError):
4745 seqof.append(Boolean(False))
4746 with self.assertRaises(ValueError):
4747 seqof[0] = Boolean(False)
4749 @given(data_strategy())
4750 def test_bounds_satisfied(self, d):
4751 class SeqOf(self.base_klass):
4753 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4754 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4755 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4756 SeqOf(value=value, bounds=(bound_min, bound_max))
4758 @given(data_strategy())
4759 def test_bounds_unsatisfied(self, d):
4760 class SeqOf(self.base_klass):
4762 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4763 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4764 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4765 with self.assertRaises(BoundsError) as err:
4766 SeqOf(value=value, bounds=(bound_min, bound_max))
4768 value = [Boolean()] * d.draw(integers(
4769 min_value=bound_max + 1,
4770 max_value=bound_max + 10,
4772 with self.assertRaises(BoundsError) as err:
4773 SeqOf(value=value, bounds=(bound_min, bound_max))
4776 @given(integers(min_value=1, max_value=10))
4777 def test_out_of_bounds(self, bound_max):
4778 class SeqOf(self.base_klass):
4780 bounds = (0, bound_max)
4782 for _ in range(bound_max):
4783 seqof.append(Integer(123))
4784 with self.assertRaises(BoundsError):
4785 seqof.append(Integer(123))
4787 @given(data_strategy())
4788 def test_call(self, d):
4798 ) = d.draw(seqof_values_strategy())
4800 class SeqOf(self.base_klass):
4801 schema = schema_initial
4802 obj_initial = SeqOf(
4803 value=value_initial,
4804 bounds=bounds_initial,
4807 default=default_initial,
4808 optional=optional_initial or False,
4809 _decoded=_decoded_initial,
4820 ) = d.draw(seqof_values_strategy(
4821 schema=schema_initial,
4822 do_expl=impl_initial is None,
4824 if (default is None) and (obj_initial.default is not None):
4827 (bounds is None) and
4828 (value is not None) and
4829 (bounds_initial is not None) and
4830 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4834 (bounds is None) and
4835 (default is not None) and
4836 (bounds_initial is not None) and
4837 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4849 value_expected = default if value is None else value
4851 default_initial if value_expected is None
4854 value_expected = () if value_expected is None else value_expected
4855 self.assertEqual(obj, value_expected)
4856 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4857 self.assertEqual(obj.expl_tag, expl or expl_initial)
4860 default_initial if default is None else default,
4862 if obj.default is None:
4863 optional = optional_initial if optional is None else optional
4864 optional = False if optional is None else optional
4867 self.assertEqual(obj.optional, optional)
4869 (obj._bound_min, obj._bound_max),
4870 bounds or bounds_initial or (0, float("+inf")),
4873 @given(seqof_values_strategy())
4874 def test_copy(self, values):
4875 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4877 class SeqOf(self.base_klass):
4885 optional=optional or False,
4888 obj_copied = obj.copy()
4889 self.assert_copied_basic_fields(obj, obj_copied)
4890 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4891 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4892 self.assertEqual(obj._value, obj_copied._value)
4896 integers(min_value=1).map(tag_encode),
4898 def test_stripped(self, values, tag_impl):
4899 class SeqOf(self.base_klass):
4900 schema = OctetString()
4901 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4902 with self.assertRaises(NotEnoughData):
4903 obj.decode(obj.encode()[:-1])
4907 integers(min_value=1).map(tag_ctxc),
4909 def test_stripped_expl(self, values, tag_expl):
4910 class SeqOf(self.base_klass):
4911 schema = OctetString()
4912 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4913 with self.assertRaises(NotEnoughData):
4914 obj.decode(obj.encode()[:-1])
4917 integers(min_value=31),
4918 integers(min_value=0),
4921 def test_bad_tag(self, tag, offset, decode_path):
4922 with self.assertRaises(DecodeError) as err:
4923 self.base_klass().decode(
4924 tag_encode(tag)[:-1],
4926 decode_path=decode_path,
4929 self.assertEqual(err.exception.offset, offset)
4930 self.assertEqual(err.exception.decode_path, decode_path)
4933 integers(min_value=128),
4934 integers(min_value=0),
4937 def test_bad_len(self, l, offset, decode_path):
4938 with self.assertRaises(DecodeError) as err:
4939 self.base_klass().decode(
4940 self.base_klass.tag_default + len_encode(l)[:-1],
4942 decode_path=decode_path,
4945 self.assertEqual(err.exception.offset, offset)
4946 self.assertEqual(err.exception.decode_path, decode_path)
4948 @given(binary(min_size=1))
4949 def test_tag_mismatch(self, impl):
4950 assume(impl != self.base_klass.tag_default)
4951 with self.assertRaises(TagMismatch):
4952 self.base_klass(impl=impl).decode(self.base_klass().encode())
4954 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4956 seqof_values_strategy(schema=Integer()),
4957 lists(integers().map(Integer)),
4958 integers(min_value=1).map(tag_ctxc),
4959 integers(min_value=0),
4962 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4963 _, _, _, _, _, default, optional, _decoded = values
4965 class SeqOf(self.base_klass):
4975 self.assertFalse(obj.expled)
4976 obj_encoded = obj.encode()
4977 obj_expled = obj(value, expl=tag_expl)
4978 self.assertTrue(obj_expled.expled)
4981 obj_expled_encoded = obj_expled.encode()
4982 obj_decoded, tail = obj_expled.decode(
4983 obj_expled_encoded + tail_junk,
4988 self.assertEqual(tail, tail_junk)
4989 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
4990 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4991 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4992 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4994 obj_decoded.expl_llen,
4995 len(len_encode(len(obj_encoded))),
4997 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4998 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5001 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5003 self.assertEqual(obj_decoded.expl_offset, offset)
5004 for obj_inner in obj_decoded:
5005 self.assertIn(obj_inner, obj_decoded)
5006 self.assertSequenceEqual(
5009 obj_inner.offset - offset:
5010 obj_inner.offset + obj_inner.tlvlen - offset
5015 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5016 class SeqOf(SequenceOf):
5020 def _test_symmetric_compare_objs(self, obj1, obj2):
5021 self.assertEqual(obj1, obj2)
5022 self.assertSequenceEqual(list(obj1), list(obj2))
5025 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5030 def _test_symmetric_compare_objs(self, obj1, obj2):
5031 self.assertSetEqual(
5032 set(int(v) for v in obj1),
5033 set(int(v) for v in obj2),
5036 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5037 @given(data_strategy())
5038 def test_sorted(self, d):
5039 values = [OctetString(v) for v in d.draw(lists(binary()))]
5042 schema = OctetString()
5044 seq_encoded = seq.encode()
5045 seq_decoded, _ = seq.decode(seq_encoded)
5046 self.assertSequenceEqual(
5047 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5048 b"".join(sorted([v.encode() for v in values])),
5052 class TestGoMarshalVectors(TestCase):
5054 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5055 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5056 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5057 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5058 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5060 class Seq(Sequence):
5062 ("erste", Integer()),
5063 ("zweite", Integer(optional=True))
5066 seq["erste"] = Integer(64)
5067 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5068 seq["erste"] = Integer(0x123456)
5069 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5070 seq["erste"] = Integer(64)
5071 seq["zweite"] = Integer(65)
5072 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5074 class NestedSeq(Sequence):
5078 seq["erste"] = Integer(127)
5079 seq["zweite"] = None
5080 nested = NestedSeq()
5081 nested["nest"] = seq
5082 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5084 self.assertSequenceEqual(
5085 OctetString(b"\x01\x02\x03").encode(),
5086 hexdec("0403010203"),
5089 class Seq(Sequence):
5091 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5094 seq["erste"] = Integer(64)
5095 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5097 class Seq(Sequence):
5099 ("erste", Integer(expl=tag_ctxc(5))),
5102 seq["erste"] = Integer(64)
5103 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5105 class Seq(Sequence):
5108 impl=tag_encode(0, klass=TagClassContext),
5113 seq["erste"] = Null()
5114 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5116 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5118 self.assertSequenceEqual(
5119 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5120 hexdec("170d3730303130313030303030305a"),
5122 self.assertSequenceEqual(
5123 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5124 hexdec("170d3039313131353232353631365a"),
5126 self.assertSequenceEqual(
5127 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5128 hexdec("180f32313030303430353132303130315a"),
5131 class Seq(Sequence):
5133 ("erste", GeneralizedTime()),
5136 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5137 self.assertSequenceEqual(
5139 hexdec("3011180f32303039313131353232353631365a"),
5142 self.assertSequenceEqual(
5143 BitString((1, b"\x80")).encode(),
5146 self.assertSequenceEqual(
5147 BitString((12, b"\x81\xF0")).encode(),
5148 hexdec("03030481f0"),
5151 self.assertSequenceEqual(
5152 ObjectIdentifier("1.2.3.4").encode(),
5153 hexdec("06032a0304"),
5155 self.assertSequenceEqual(
5156 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5157 hexdec("06092a864888932d010105"),
5159 self.assertSequenceEqual(
5160 ObjectIdentifier("2.100.3").encode(),
5161 hexdec("0603813403"),
5164 self.assertSequenceEqual(
5165 PrintableString("test").encode(),
5166 hexdec("130474657374"),
5168 self.assertSequenceEqual(
5169 PrintableString("x" * 127).encode(),
5170 hexdec("137F" + "78" * 127),
5172 self.assertSequenceEqual(
5173 PrintableString("x" * 128).encode(),
5174 hexdec("138180" + "78" * 128),
5176 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5178 class Seq(Sequence):
5180 ("erste", IA5String()),
5183 seq["erste"] = IA5String("test")
5184 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5186 class Seq(Sequence):
5188 ("erste", PrintableString()),
5191 seq["erste"] = PrintableString("test")
5192 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5193 seq["erste"] = PrintableString("test*")
5194 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5196 class Seq(Sequence):
5198 ("erste", Any(optional=True)),
5199 ("zweite", Integer()),
5202 seq["zweite"] = Integer(64)
5203 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5208 seq.append(Integer(10))
5209 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5211 class _SeqOf(SequenceOf):
5212 schema = PrintableString()
5214 class SeqOf(SequenceOf):
5217 _seqof.append(PrintableString("1"))
5219 seqof.append(_seqof)
5220 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5222 class Seq(Sequence):
5224 ("erste", Integer(default=1)),
5227 seq["erste"] = Integer(0)
5228 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5229 seq["erste"] = Integer(1)
5230 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5231 seq["erste"] = Integer(2)
5232 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5235 class TestPP(TestCase):
5236 @given(data_strategy())
5237 def test_oid_printing(self, d):
5239 str(ObjectIdentifier(k)): v * 2
5240 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5242 chosen = d.draw(sampled_from(sorted(oids)))
5243 chosen_id = oids[chosen]
5244 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5245 self.assertNotIn(chosen_id, pp_console_row(pp))
5246 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5249 class TestAutoAddSlots(TestCase):
5251 class Inher(Integer):
5254 with self.assertRaises(AttributeError):
5256 inher.unexistent = "whatever"
5259 class TestOIDDefines(TestCase):
5260 @given(data_strategy())
5261 def runTest(self, d):
5262 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5263 value_name_chosen = d.draw(sampled_from(value_names))
5265 ObjectIdentifier(oid)
5266 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5268 oid_chosen = d.draw(sampled_from(oids))
5269 values = d.draw(lists(
5271 min_size=len(value_names),
5272 max_size=len(value_names),
5275 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5276 oid: Integer() for oid in oids[:-1]
5279 for i, value_name in enumerate(value_names):
5280 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5282 class Seq(Sequence):
5285 for value_name, value in zip(value_names, values):
5286 seq[value_name] = Any(Integer(value).encode())
5287 seq["type"] = oid_chosen
5288 seq, _ = Seq().decode(seq.encode())
5289 for value_name in value_names:
5290 if value_name == value_name_chosen:
5292 self.assertIsNone(seq[value_name].defined)
5293 if value_name_chosen in oids[:-1]:
5294 self.assertIsNotNone(seq[value_name_chosen].defined)
5295 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5296 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5299 class TestDefinesByPath(TestCase):
5300 def test_generated(self):
5301 class Seq(Sequence):
5303 ("type", ObjectIdentifier()),
5304 ("value", OctetString(expl=tag_ctxc(123))),
5307 class SeqInner(Sequence):
5309 ("typeInner", ObjectIdentifier()),
5310 ("valueInner", Any()),
5313 class PairValue(SetOf):
5316 class Pair(Sequence):
5318 ("type", ObjectIdentifier()),
5319 ("value", PairValue()),
5322 class Pairs(SequenceOf):
5329 type_octet_stringed,
5331 ObjectIdentifier(oid)
5332 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5334 seq_integered = Seq()
5335 seq_integered["type"] = type_integered
5336 seq_integered["value"] = OctetString(Integer(123).encode())
5337 seq_integered_raw = seq_integered.encode()
5341 (type_octet_stringed, OctetString(b"whatever")),
5342 (type_integered, Integer(123)),
5343 (type_octet_stringed, OctetString(b"whenever")),
5344 (type_integered, Integer(234)),
5346 for t, v in pairs_input:
5349 pair["value"] = PairValue((Any(v),))
5351 seq_inner = SeqInner()
5352 seq_inner["typeInner"] = type_innered
5353 seq_inner["valueInner"] = Any(pairs)
5354 seq_sequenced = Seq()
5355 seq_sequenced["type"] = type_sequenced
5356 seq_sequenced["value"] = OctetString(seq_inner.encode())
5357 seq_sequenced_raw = seq_sequenced.encode()
5359 defines_by_path = []
5360 seq_integered, _ = Seq().decode(seq_integered_raw)
5361 self.assertIsNone(seq_integered["value"].defined)
5362 defines_by_path.append(
5363 (("type",), ((("value",), {
5364 type_integered: Integer(),
5365 type_sequenced: SeqInner(),
5368 seq_integered, _ = Seq().decode(
5370 ctx={"defines_by_path": defines_by_path},
5372 self.assertIsNotNone(seq_integered["value"].defined)
5373 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5374 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5375 self.assertTrue(seq_integered_raw[
5376 seq_integered["value"].defined[1].offset:
5377 ].startswith(Integer(123).encode()))
5379 seq_sequenced, _ = Seq().decode(
5381 ctx={"defines_by_path": defines_by_path},
5383 self.assertIsNotNone(seq_sequenced["value"].defined)
5384 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5385 seq_inner = seq_sequenced["value"].defined[1]
5386 self.assertIsNone(seq_inner["valueInner"].defined)
5388 defines_by_path.append((
5389 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5390 ((("valueInner",), {type_innered: Pairs()}),),
5392 seq_sequenced, _ = Seq().decode(
5394 ctx={"defines_by_path": defines_by_path},
5396 self.assertIsNotNone(seq_sequenced["value"].defined)
5397 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5398 seq_inner = seq_sequenced["value"].defined[1]
5399 self.assertIsNotNone(seq_inner["valueInner"].defined)
5400 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5401 pairs = seq_inner["valueInner"].defined[1]
5403 self.assertIsNone(pair["value"][0].defined)
5405 defines_by_path.append((
5408 DecodePathDefBy(type_sequenced),
5410 DecodePathDefBy(type_innered),
5415 type_integered: Integer(),
5416 type_octet_stringed: OctetString(),
5419 seq_sequenced, _ = Seq().decode(
5421 ctx={"defines_by_path": defines_by_path},
5423 self.assertIsNotNone(seq_sequenced["value"].defined)
5424 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5425 seq_inner = seq_sequenced["value"].defined[1]
5426 self.assertIsNotNone(seq_inner["valueInner"].defined)
5427 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5428 pairs_got = seq_inner["valueInner"].defined[1]
5429 for pair_input, pair_got in zip(pairs_input, pairs_got):
5430 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5431 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5433 @given(oid_strategy(), integers())
5434 def test_simple(self, oid, tgt):
5435 class Inner(Sequence):
5437 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5438 ObjectIdentifier(oid): Integer(),
5442 class Outer(Sequence):
5445 ("tgt", OctetString()),
5449 inner["oid"] = ObjectIdentifier(oid)
5451 outer["inner"] = inner
5452 outer["tgt"] = OctetString(Integer(tgt).encode())
5453 decoded, _ = Outer().decode(outer.encode())
5454 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5457 class TestAbsDecodePath(TestCase):
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_concat(self, decode_path, rel_path):
5463 self.assertSequenceEqual(
5464 abs_decode_path(decode_path, rel_path),
5465 decode_path + rel_path,
5469 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5470 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5472 def test_abs(self, decode_path, rel_path):
5473 self.assertSequenceEqual(
5474 abs_decode_path(decode_path, ("/",) + rel_path),
5479 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5480 integers(min_value=1, max_value=3),
5481 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5483 def test_dots(self, decode_path, number_of_dots, rel_path):
5484 self.assertSequenceEqual(
5485 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5486 decode_path[:-number_of_dots] + rel_path,
5490 class TestStrictDefaultExistence(TestCase):
5491 @given(data_strategy())
5492 def runTest(self, d):
5493 count = d.draw(integers(min_value=1, max_value=10))
5494 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5496 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5497 for i in range(count)
5500 class Seq(Sequence):
5503 for i in range(count):
5504 seq["int%d" % i] = Integer(123)
5506 chosen = "int%d" % chosen
5507 seq.specs[chosen] = seq.specs[chosen](default=123)
5509 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5510 seq.decode(raw, ctx={"strict_default_existence": True})
5513 class TestX690PrefixedType(TestCase):
5515 self.assertSequenceEqual(
5516 VisibleString("Jones").encode(),
5517 hexdec("1A054A6F6E6573"),
5519 self.assertSequenceEqual(
5522 impl=tag_encode(3, klass=TagClassApplication),
5524 hexdec("43054A6F6E6573"),
5526 self.assertSequenceEqual(
5530 impl=tag_encode(3, klass=TagClassApplication),
5534 hexdec("A20743054A6F6E6573"),
5536 self.assertSequenceEqual(
5540 impl=tag_encode(3, klass=TagClassApplication),
5542 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5544 hexdec("670743054A6F6E6573"),
5546 self.assertSequenceEqual(
5547 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5548 hexdec("82054A6F6E6573"),