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 LENINDEF
81 from pyderasn import NotEnoughData
82 from pyderasn import Null
83 from pyderasn import NumericString
84 from pyderasn import ObjectIdentifier
85 from pyderasn import ObjNotReady
86 from pyderasn import ObjUnknown
87 from pyderasn import OctetString
88 from pyderasn import pp_console_row
89 from pyderasn import pprint
90 from pyderasn import PrintableString
91 from pyderasn import Sequence
92 from pyderasn import SequenceOf
93 from pyderasn import Set
94 from pyderasn import SetOf
95 from pyderasn import tag_ctxc
96 from pyderasn import tag_ctxp
97 from pyderasn import tag_decode
98 from pyderasn import tag_encode
99 from pyderasn import tag_strip
100 from pyderasn import TagClassApplication
101 from pyderasn import TagClassContext
102 from pyderasn import TagClassPrivate
103 from pyderasn import TagClassUniversal
104 from pyderasn import TagFormConstructed
105 from pyderasn import TagFormPrimitive
106 from pyderasn import TagMismatch
107 from pyderasn import TeletexString
108 from pyderasn import UniversalString
109 from pyderasn import UTCTime
110 from pyderasn import UTF8String
111 from pyderasn import VideotexString
112 from pyderasn import VisibleString
115 settings.register_profile("local", settings(
117 perform_health_check=False,
119 settings.load_profile("local")
120 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
122 tag_classes = sampled_from((
128 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
129 decode_path_strat = lists(integers(), max_size=3).map(
130 lambda decode_path: tuple(str(dp) for dp in decode_path)
134 class TestHex(TestCase):
136 def test_symmetric(self, data):
137 self.assertEqual(hexdec(hexenc(data)), data)
140 class TestTagCoder(TestCase):
141 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
145 integers(min_value=0, max_value=30),
148 def test_short(self, klass, form, num, junk):
149 raw = tag_encode(klass=klass, form=form, num=num)
150 self.assertEqual(tag_decode(raw), (klass, form, num))
151 self.assertEqual(len(raw), 1)
153 byte2int(tag_encode(klass=klass, form=form, num=0)),
154 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
156 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
157 self.assertSequenceEqual(stripped.tobytes(), raw)
158 self.assertEqual(tlen, len(raw))
159 self.assertSequenceEqual(tail, junk)
161 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
165 integers(min_value=31),
168 def test_long(self, klass, form, num, junk):
169 raw = tag_encode(klass=klass, form=form, num=num)
170 self.assertEqual(tag_decode(raw), (klass, form, num))
171 self.assertGreater(len(raw), 1)
173 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
176 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
177 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
178 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
179 self.assertSequenceEqual(stripped.tobytes(), raw)
180 self.assertEqual(tlen, len(raw))
181 self.assertSequenceEqual(tail, junk)
183 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
184 @given(integers(min_value=31))
185 def test_unfinished_tag(self, num):
186 raw = bytearray(tag_encode(num=num))
187 for i in range(1, len(raw)):
189 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
190 tag_strip(bytes(raw))
192 def test_go_vectors_valid(self):
193 for data, (eklass, etag, elen, eform) in (
194 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
195 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
196 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
197 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
198 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
199 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
200 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
201 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
202 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
203 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
205 tag, _, len_encoded = tag_strip(memoryview(data))
206 klass, form, num = tag_decode(tag)
207 _len, _, tail = len_decode(len_encoded)
208 self.assertSequenceEqual(tail, b"")
209 self.assertEqual(klass, eklass)
210 self.assertEqual(num, etag)
211 self.assertEqual(_len, elen)
212 self.assertEqual(form, eform)
214 def test_go_vectors_invalid(self):
222 with self.assertRaises(DecodeError):
223 _, _, len_encoded = tag_strip(memoryview(data))
224 len_decode(len_encoded)
227 integers(min_value=0, max_value=127),
228 integers(min_value=0, max_value=2),
230 def test_long_instead_of_short(self, l, dummy_num):
231 octets = (b"\x00" * dummy_num) + int2byte(l)
232 octets = int2byte((dummy_num + 1) | 0x80) + octets
233 with self.assertRaises(DecodeError):
237 class TestLenCoder(TestCase):
238 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
240 integers(min_value=0, max_value=127),
243 def test_short(self, l, junk):
244 raw = len_encode(l) + junk
245 decoded, llen, tail = len_decode(memoryview(raw))
246 self.assertEqual(decoded, l)
247 self.assertEqual(llen, 1)
248 self.assertEqual(len(raw), 1 + len(junk))
249 self.assertEqual(tail.tobytes(), junk)
251 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
253 integers(min_value=128),
256 def test_long(self, l, junk):
257 raw = len_encode(l) + junk
258 decoded, llen, tail = len_decode(memoryview(raw))
259 self.assertEqual(decoded, l)
260 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
261 self.assertEqual(llen, len(raw) - len(junk))
262 self.assertNotEqual(indexbytes(raw, 1), 0)
263 self.assertSequenceEqual(tail.tobytes(), junk)
265 def test_empty(self):
266 with self.assertRaises(NotEnoughData):
269 @given(integers(min_value=128))
270 def test_stripped(self, _len):
271 with self.assertRaises(NotEnoughData):
272 len_decode(len_encode(_len)[:-1])
275 text_printable = text(alphabet=printable, min_size=1)
279 def text_letters(draw):
280 result = draw(text(alphabet=ascii_letters, min_size=1))
282 result = result.encode("ascii")
286 class CommonMixin(object):
287 def test_tag_default(self):
288 obj = self.base_klass()
289 self.assertEqual(obj.tag, obj.tag_default)
291 def test_simultaneous_impl_expl(self):
292 with self.assertRaises(ValueError):
293 self.base_klass(impl=b"whatever", expl=b"whenever")
295 @given(binary(min_size=1), integers(), integers(), integers())
296 def test_decoded(self, impl, offset, llen, vlen):
297 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
298 self.assertEqual(obj.offset, offset)
299 self.assertEqual(obj.llen, llen)
300 self.assertEqual(obj.vlen, vlen)
301 self.assertEqual(obj.tlen, len(impl))
302 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
304 @given(binary(min_size=1))
305 def test_impl_inherited(self, impl_tag):
306 class Inherited(self.base_klass):
309 self.assertSequenceEqual(obj.impl, impl_tag)
310 self.assertFalse(obj.expled)
313 def test_expl_inherited(self, expl_tag):
314 class Inherited(self.base_klass):
317 self.assertSequenceEqual(obj.expl, expl_tag)
318 self.assertTrue(obj.expled)
320 def assert_copied_basic_fields(self, obj, obj_copied):
321 self.assertEqual(obj, obj_copied)
322 self.assertSequenceEqual(obj.tag, obj_copied.tag)
323 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
324 self.assertEqual(obj.default, obj_copied.default)
325 self.assertEqual(obj.optional, obj_copied.optional)
326 self.assertEqual(obj.offset, obj_copied.offset)
327 self.assertEqual(obj.llen, obj_copied.llen)
328 self.assertEqual(obj.vlen, obj_copied.vlen)
332 def boolean_values_strategy(draw, do_expl=False):
333 value = draw(one_of(none(), booleans()))
337 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
339 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
340 default = draw(one_of(none(), booleans()))
341 optional = draw(one_of(none(), booleans()))
343 draw(integers(min_value=0)),
344 draw(integers(min_value=0)),
345 draw(integers(min_value=0)),
347 return (value, impl, expl, default, optional, _decoded)
350 class BooleanInherited(Boolean):
354 class TestBoolean(CommonMixin, TestCase):
357 def test_invalid_value_type(self):
358 with self.assertRaises(InvalidValueType) as err:
363 def test_optional(self, optional):
364 obj = Boolean(default=Boolean(False), optional=optional)
365 self.assertTrue(obj.optional)
368 def test_ready(self, value):
370 self.assertFalse(obj.ready)
373 with self.assertRaises(ObjNotReady) as err:
377 self.assertTrue(obj.ready)
381 @given(booleans(), booleans(), binary(), binary())
382 def test_comparison(self, value1, value2, tag1, tag2):
383 for klass in (Boolean, BooleanInherited):
386 self.assertEqual(obj1 == obj2, value1 == value2)
387 self.assertEqual(obj1 != obj2, value1 != value2)
388 self.assertEqual(obj1 == bool(obj2), value1 == value2)
389 obj1 = klass(value1, impl=tag1)
390 obj2 = klass(value1, impl=tag2)
391 self.assertEqual(obj1 == obj2, tag1 == tag2)
392 self.assertEqual(obj1 != obj2, tag1 != tag2)
394 @given(data_strategy())
395 def test_call(self, d):
396 for klass in (Boolean, BooleanInherited):
404 ) = d.draw(boolean_values_strategy())
410 optional_initial or False,
420 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
421 obj = obj_initial(value, impl, expl, default, optional)
423 value_expected = default if value is None else value
425 default_initial if value_expected is None
428 self.assertEqual(obj, value_expected)
429 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
430 self.assertEqual(obj.expl_tag, expl or expl_initial)
433 default_initial if default is None else default,
435 if obj.default is None:
436 optional = optional_initial if optional is None else optional
437 optional = False if optional is None else optional
440 self.assertEqual(obj.optional, optional)
442 @given(boolean_values_strategy())
443 def test_copy(self, values):
444 for klass in (Boolean, BooleanInherited):
446 obj_copied = obj.copy()
447 self.assert_copied_basic_fields(obj, obj_copied)
451 integers(min_value=1).map(tag_encode),
453 def test_stripped(self, value, tag_impl):
454 obj = Boolean(value, impl=tag_impl)
455 with self.assertRaises(NotEnoughData):
456 obj.decode(obj.encode()[:-1])
460 integers(min_value=1).map(tag_ctxc),
462 def test_stripped_expl(self, value, tag_expl):
463 obj = Boolean(value, expl=tag_expl)
464 with self.assertRaises(NotEnoughData):
465 obj.decode(obj.encode()[:-1])
468 integers(min_value=31),
469 integers(min_value=0),
472 def test_bad_tag(self, tag, offset, decode_path):
473 with self.assertRaises(DecodeError) as err:
475 tag_encode(tag)[:-1],
477 decode_path=decode_path,
480 self.assertEqual(err.exception.offset, offset)
481 self.assertEqual(err.exception.decode_path, decode_path)
484 integers(min_value=31),
485 integers(min_value=0),
488 def test_bad_expl_tag(self, tag, offset, decode_path):
489 with self.assertRaises(DecodeError) as err:
490 Boolean(expl=Boolean.tag_default).decode(
491 tag_encode(tag)[:-1],
493 decode_path=decode_path,
496 self.assertEqual(err.exception.offset, offset)
497 self.assertEqual(err.exception.decode_path, decode_path)
500 integers(min_value=128),
501 integers(min_value=0),
504 def test_bad_len(self, l, offset, decode_path):
505 with self.assertRaises(DecodeError) as err:
507 Boolean.tag_default + len_encode(l)[:-1],
509 decode_path=decode_path,
512 self.assertEqual(err.exception.offset, offset)
513 self.assertEqual(err.exception.decode_path, decode_path)
516 integers(min_value=128),
517 integers(min_value=0),
520 def test_bad_expl_len(self, l, offset, decode_path):
521 with self.assertRaises(DecodeError) as err:
522 Boolean(expl=Boolean.tag_default).decode(
523 Boolean.tag_default + len_encode(l)[:-1],
525 decode_path=decode_path,
528 self.assertEqual(err.exception.offset, offset)
529 self.assertEqual(err.exception.decode_path, decode_path)
531 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
533 boolean_values_strategy(),
535 integers(min_value=1).map(tag_ctxc),
536 integers(min_value=0),
539 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
540 for klass in (Boolean, BooleanInherited):
541 _, _, _, default, optional, _decoded = values
550 self.assertFalse(obj.expled)
551 obj_encoded = obj.encode()
552 obj_expled = obj(value, expl=tag_expl)
553 self.assertTrue(obj_expled.expled)
556 obj_expled_encoded = obj_expled.encode()
557 obj_decoded, tail = obj_expled.decode(
558 obj_expled_encoded + tail_junk,
563 self.assertEqual(tail, tail_junk)
564 self.assertEqual(obj_decoded, obj_expled)
565 self.assertNotEqual(obj_decoded, obj)
566 self.assertEqual(bool(obj_decoded), bool(obj_expled))
567 self.assertEqual(bool(obj_decoded), bool(obj))
568 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
569 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
570 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
572 obj_decoded.expl_llen,
573 len(len_encode(len(obj_encoded))),
575 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
576 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
579 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
581 self.assertEqual(obj_decoded.expl_offset, offset)
583 @given(integers(min_value=2))
584 def test_invalid_len(self, l):
585 with self.assertRaises(InvalidLength):
586 Boolean().decode(b"".join((
592 @given(integers(min_value=0 + 1, max_value=255 - 1))
593 def test_ber_value(self, value):
594 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
595 Boolean().decode(b"".join((
600 obj, _ = Boolean().decode(
608 self.assertTrue(bool(obj))
609 self.assertTrue(obj.bered)
610 self.assertFalse(obj.lenindef)
613 integers(min_value=1).map(tag_ctxc),
614 binary().filter(lambda x: not x.startswith(EOC)),
616 def test_ber_expl_no_eoc(self, expl, junk):
617 encoded = expl + LENINDEF + Boolean(False).encode()
618 with assertRaisesRegex(self, DecodeError, "no EOC"):
619 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
620 obj, tail = Boolean(expl=expl).decode(
621 encoded + EOC + junk,
624 self.assertTrue(obj.expl_lenindef)
625 self.assertSequenceEqual(tail, junk)
628 integers(min_value=1).map(tag_ctxc),
635 def test_ber_expl(self, expl, values):
641 Boolean(value).encode() +
644 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
646 class SeqOf(SequenceOf):
647 schema = Boolean(expl=expl)
648 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
649 self.assertSequenceEqual(tail, b"")
650 self.assertSequenceEqual([bool(v) for v in seqof], values)
665 len(expl) + 1 + 3 + EOC_LEN,
676 def integer_values_strategy(draw, do_expl=False):
677 bound_min, value, default, bound_max = sorted(draw(sets(
686 _specs = draw(sets(text_letters()))
689 min_size=len(_specs),
690 max_size=len(_specs),
692 _specs = list(zip(_specs, values))
695 bounds = (bound_min, bound_max)
699 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
701 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
704 optional = draw(one_of(none(), booleans()))
706 draw(integers(min_value=0)),
707 draw(integers(min_value=0)),
708 draw(integers(min_value=0)),
710 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
713 class IntegerInherited(Integer):
717 class TestInteger(CommonMixin, TestCase):
720 def test_invalid_value_type(self):
721 with self.assertRaises(InvalidValueType) as err:
725 @given(sets(text_letters(), min_size=2))
726 def test_unknown_name(self, names_input):
727 missing = names_input.pop()
730 schema = [(n, 123) for n in names_input]
731 with self.assertRaises(ObjUnknown) as err:
735 @given(sets(text_letters(), min_size=2))
736 def test_known_name(self, names_input):
738 schema = [(n, 123) for n in names_input]
739 Int(names_input.pop())
742 def test_optional(self, optional):
743 obj = Integer(default=Integer(0), optional=optional)
744 self.assertTrue(obj.optional)
747 def test_ready(self, value):
749 self.assertFalse(obj.ready)
752 with self.assertRaises(ObjNotReady) as err:
756 self.assertTrue(obj.ready)
761 @given(integers(), integers(), binary(), binary())
762 def test_comparison(self, value1, value2, tag1, tag2):
763 for klass in (Integer, IntegerInherited):
766 self.assertEqual(obj1 == obj2, value1 == value2)
767 self.assertEqual(obj1 != obj2, value1 != value2)
768 self.assertEqual(obj1 == int(obj2), value1 == value2)
769 obj1 = klass(value1, impl=tag1)
770 obj2 = klass(value1, impl=tag2)
771 self.assertEqual(obj1 == obj2, tag1 == tag2)
772 self.assertEqual(obj1 != obj2, tag1 != tag2)
774 @given(lists(integers()))
775 def test_sorted_works(self, values):
776 self.assertSequenceEqual(
777 [int(v) for v in sorted(Integer(v) for v in values)],
781 @given(data_strategy())
782 def test_named(self, d):
783 names_input = list(d.draw(sets(text_letters(), min_size=1)))
784 values_input = list(d.draw(sets(
786 min_size=len(names_input),
787 max_size=len(names_input),
789 chosen_name = d.draw(sampled_from(names_input))
790 names_input = dict(zip(names_input, values_input))
794 _int = Int(chosen_name)
795 self.assertEqual(_int.named, chosen_name)
796 self.assertEqual(int(_int), names_input[chosen_name])
798 @given(integers(), integers(min_value=0), integers(min_value=0))
799 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
800 value = bound_min + value_delta
801 bound_max = value + bound_delta
802 Integer(value=value, bounds=(bound_min, bound_max))
804 @given(sets(integers(), min_size=3, max_size=3))
805 def test_bounds_unsatisfied(self, values):
806 values = sorted(values)
807 with self.assertRaises(BoundsError) as err:
808 Integer(value=values[0], bounds=(values[1], values[2]))
810 with self.assertRaises(BoundsError) as err:
811 Integer(value=values[2], bounds=(values[0], values[1]))
814 @given(data_strategy())
815 def test_call(self, d):
816 for klass in (Integer, IntegerInherited):
826 ) = d.draw(integer_values_strategy())
833 optional_initial or False,
846 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
847 if (default is None) and (obj_initial.default is not None):
851 (value is not None) and
852 (bounds_initial is not None) and
853 not (bounds_initial[0] <= value <= bounds_initial[1])
858 (default is not None) and
859 (bounds_initial is not None) and
860 not (bounds_initial[0] <= default <= bounds_initial[1])
863 obj = obj_initial(value, bounds, impl, expl, default, optional)
865 value_expected = default if value is None else value
867 default_initial if value_expected is None
870 self.assertEqual(obj, value_expected)
871 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
872 self.assertEqual(obj.expl_tag, expl or expl_initial)
875 default_initial if default is None else default,
877 if obj.default is None:
878 optional = optional_initial if optional is None else optional
879 optional = False if optional is None else optional
882 self.assertEqual(obj.optional, optional)
884 (obj._bound_min, obj._bound_max),
885 bounds or bounds_initial or (float("-inf"), float("+inf")),
889 {} if _specs_initial is None else dict(_specs_initial),
892 @given(integer_values_strategy())
893 def test_copy(self, values):
894 for klass in (Integer, IntegerInherited):
896 obj_copied = obj.copy()
897 self.assert_copied_basic_fields(obj, obj_copied)
898 self.assertEqual(obj.specs, obj_copied.specs)
899 self.assertEqual(obj._bound_min, obj_copied._bound_min)
900 self.assertEqual(obj._bound_max, obj_copied._bound_max)
901 self.assertEqual(obj._value, obj_copied._value)
905 integers(min_value=1).map(tag_encode),
907 def test_stripped(self, value, tag_impl):
908 obj = Integer(value, impl=tag_impl)
909 with self.assertRaises(NotEnoughData):
910 obj.decode(obj.encode()[:-1])
914 integers(min_value=1).map(tag_ctxc),
916 def test_stripped_expl(self, value, tag_expl):
917 obj = Integer(value, expl=tag_expl)
918 with self.assertRaises(NotEnoughData):
919 obj.decode(obj.encode()[:-1])
921 def test_zero_len(self):
922 with self.assertRaises(NotEnoughData):
923 Integer().decode(b"".join((
929 integers(min_value=31),
930 integers(min_value=0),
933 def test_bad_tag(self, tag, offset, decode_path):
934 with self.assertRaises(DecodeError) as err:
936 tag_encode(tag)[:-1],
938 decode_path=decode_path,
941 self.assertEqual(err.exception.offset, offset)
942 self.assertEqual(err.exception.decode_path, decode_path)
945 integers(min_value=128),
946 integers(min_value=0),
949 def test_bad_len(self, l, offset, decode_path):
950 with self.assertRaises(DecodeError) as err:
952 Integer.tag_default + len_encode(l)[:-1],
954 decode_path=decode_path,
957 self.assertEqual(err.exception.offset, offset)
958 self.assertEqual(err.exception.decode_path, decode_path)
961 sets(integers(), min_size=2, max_size=2),
962 integers(min_value=0),
965 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
966 value, bound_min = list(sorted(ints))
969 bounds = (bound_min, bound_min)
970 with self.assertRaises(DecodeError) as err:
972 Integer(value).encode(),
974 decode_path=decode_path,
977 self.assertEqual(err.exception.offset, offset)
978 self.assertEqual(err.exception.decode_path, decode_path)
980 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
982 integer_values_strategy(),
984 integers(min_value=1).map(tag_ctxc),
985 integers(min_value=0),
988 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
989 for klass in (Integer, IntegerInherited):
990 _, _, _, _, default, optional, _, _decoded = values
999 self.assertFalse(obj.expled)
1000 obj_encoded = obj.encode()
1001 obj_expled = obj(value, expl=tag_expl)
1002 self.assertTrue(obj_expled.expled)
1005 obj_expled_encoded = obj_expled.encode()
1006 obj_decoded, tail = obj_expled.decode(
1007 obj_expled_encoded + tail_junk,
1012 self.assertEqual(tail, tail_junk)
1013 self.assertEqual(obj_decoded, obj_expled)
1014 self.assertNotEqual(obj_decoded, obj)
1015 self.assertEqual(int(obj_decoded), int(obj_expled))
1016 self.assertEqual(int(obj_decoded), int(obj))
1017 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1018 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1019 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1021 obj_decoded.expl_llen,
1022 len(len_encode(len(obj_encoded))),
1024 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1025 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1028 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1030 self.assertEqual(obj_decoded.expl_offset, offset)
1032 def test_go_vectors_valid(self):
1033 for data, expect in ((
1037 (b"\xff\x7f", -129),
1041 (b"\xff\x00", -256),
1045 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1046 (b"\x80\x00\x00\x00", -2147483648),
1049 Integer().decode(b"".join((
1050 Integer.tag_default,
1051 len_encode(len(data)),
1057 def test_go_vectors_invalid(self):
1062 with self.assertRaises(DecodeError):
1063 Integer().decode(b"".join((
1064 Integer.tag_default,
1065 len_encode(len(data)),
1071 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1074 if draw(booleans()):
1075 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1077 integers(min_value=0, max_value=255),
1078 min_size=len(schema),
1079 max_size=len(schema),
1081 schema = list(zip(schema, bits))
1083 def _value(value_required):
1084 if not value_required and draw(booleans()):
1086 generation_choice = 0
1088 generation_choice = draw(sampled_from((1, 2, 3)))
1089 if generation_choice == 1 or draw(booleans()):
1090 return "'%s'B" % "".join(draw(lists(
1091 sampled_from(("0", "1")),
1092 max_size=len(schema),
1094 elif generation_choice == 2 or draw(booleans()):
1095 return draw(binary(max_size=len(schema) // 8))
1096 elif generation_choice == 3 or draw(booleans()):
1097 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1099 value = _value(value_required)
1100 default = _value(value_required=False)
1104 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1106 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1107 optional = draw(one_of(none(), booleans()))
1109 draw(integers(min_value=0)),
1110 draw(integers(min_value=0)),
1111 draw(integers(min_value=0)),
1113 return (schema, value, impl, expl, default, optional, _decoded)
1116 class BitStringInherited(BitString):
1120 class TestBitString(CommonMixin, TestCase):
1121 base_klass = BitString
1123 @given(lists(booleans()))
1124 def test_b_encoding(self, bits):
1125 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1126 self.assertEqual(obj.bit_len, len(bits))
1127 self.assertSequenceEqual(list(obj), bits)
1128 for i, bit in enumerate(bits):
1129 self.assertEqual(obj[i], bit)
1131 @given(lists(booleans()))
1132 def test_out_of_bounds_bits(self, bits):
1133 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1134 for i in range(len(bits), len(bits) * 2):
1135 self.assertFalse(obj[i])
1137 def test_bad_b_encoding(self):
1138 with self.assertRaises(ValueError):
1139 BitString("'010120101'B")
1142 integers(min_value=1, max_value=255),
1143 integers(min_value=1, max_value=255),
1145 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1146 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1147 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1148 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1150 class BS(BitString):
1151 schema = (("whatever", 0),)
1152 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1153 self.assertEqual(obj.bit_len, leading_zeros + 1)
1154 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1156 def test_zero_len(self):
1157 with self.assertRaises(NotEnoughData):
1158 BitString().decode(b"".join((
1159 BitString.tag_default,
1163 def test_invalid_value_type(self):
1164 with self.assertRaises(InvalidValueType) as err:
1167 with self.assertRaises(InvalidValueType) as err:
1171 def test_obj_unknown(self):
1172 with self.assertRaises(ObjUnknown) as err:
1173 BitString(b"whatever")["whenever"]
1176 def test_get_invalid_type(self):
1177 with self.assertRaises(InvalidValueType) as err:
1178 BitString(b"whatever")[(1, 2, 3)]
1181 @given(data_strategy())
1182 def test_unknown_name(self, d):
1183 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1184 missing = _schema.pop()
1186 class BS(BitString):
1187 schema = [(n, i) for i, n in enumerate(_schema)]
1188 with self.assertRaises(ObjUnknown) as err:
1193 def test_optional(self, optional):
1194 obj = BitString(default=BitString(b""), optional=optional)
1195 self.assertTrue(obj.optional)
1198 def test_ready(self, value):
1200 self.assertFalse(obj.ready)
1203 with self.assertRaises(ObjNotReady) as err:
1206 obj = BitString(value)
1207 self.assertTrue(obj.ready)
1212 tuples(integers(min_value=0), binary()),
1213 tuples(integers(min_value=0), binary()),
1217 def test_comparison(self, value1, value2, tag1, tag2):
1218 for klass in (BitString, BitStringInherited):
1219 obj1 = klass(value1)
1220 obj2 = klass(value2)
1221 self.assertEqual(obj1 == obj2, value1 == value2)
1222 self.assertEqual(obj1 != obj2, value1 != value2)
1223 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1224 obj1 = klass(value1, impl=tag1)
1225 obj2 = klass(value1, impl=tag2)
1226 self.assertEqual(obj1 == obj2, tag1 == tag2)
1227 self.assertEqual(obj1 != obj2, tag1 != tag2)
1229 @given(data_strategy())
1230 def test_call(self, d):
1231 for klass in (BitString, BitStringInherited):
1240 ) = d.draw(bit_string_values_strategy())
1243 schema = schema_initial
1245 value=value_initial,
1248 default=default_initial,
1249 optional=optional_initial or False,
1250 _decoded=_decoded_initial,
1260 ) = d.draw(bit_string_values_strategy(
1261 schema=schema_initial,
1262 do_expl=impl_initial is None,
1271 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1272 self.assertEqual(obj.expl_tag, expl or expl_initial)
1273 if obj.default is None:
1274 optional = optional_initial if optional is None else optional
1275 optional = False if optional is None else optional
1278 self.assertEqual(obj.optional, optional)
1279 self.assertEqual(obj.specs, obj_initial.specs)
1281 @given(bit_string_values_strategy())
1282 def test_copy(self, values):
1283 for klass in (BitString, BitStringInherited):
1284 _schema, value, impl, expl, default, optional, _decoded = values
1293 optional=optional or False,
1296 obj_copied = obj.copy()
1297 self.assert_copied_basic_fields(obj, obj_copied)
1298 self.assertEqual(obj.specs, obj_copied.specs)
1299 self.assertEqual(obj._value, obj_copied._value)
1303 integers(min_value=1).map(tag_encode),
1305 def test_stripped(self, value, tag_impl):
1306 obj = BitString(value, impl=tag_impl)
1307 with self.assertRaises(NotEnoughData):
1308 obj.decode(obj.encode()[:-1])
1312 integers(min_value=1).map(tag_ctxc),
1314 def test_stripped_expl(self, value, tag_expl):
1315 obj = BitString(value, expl=tag_expl)
1316 with self.assertRaises(NotEnoughData):
1317 obj.decode(obj.encode()[:-1])
1320 integers(min_value=31),
1321 integers(min_value=0),
1324 def test_bad_tag(self, tag, offset, decode_path):
1325 with self.assertRaises(DecodeError) as err:
1327 tag_encode(tag)[:-1],
1329 decode_path=decode_path,
1332 self.assertEqual(err.exception.offset, offset)
1333 self.assertEqual(err.exception.decode_path, decode_path)
1336 integers(min_value=128),
1337 integers(min_value=0),
1340 def test_bad_len(self, l, offset, decode_path):
1341 with self.assertRaises(DecodeError) as err:
1343 BitString.tag_default + len_encode(l)[:-1],
1345 decode_path=decode_path,
1348 self.assertEqual(err.exception.offset, offset)
1349 self.assertEqual(err.exception.decode_path, decode_path)
1351 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1352 @given(data_strategy())
1353 def test_symmetric(self, d):
1362 ) = d.draw(bit_string_values_strategy(value_required=True))
1363 tail_junk = d.draw(binary(max_size=5))
1364 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1365 offset = d.draw(integers(min_value=0))
1366 for klass in (BitString, BitStringInherited):
1377 self.assertFalse(obj.expled)
1378 obj_encoded = obj.encode()
1379 obj_expled = obj(value, expl=tag_expl)
1380 self.assertTrue(obj_expled.expled)
1383 obj_expled_encoded = obj_expled.encode()
1384 obj_decoded, tail = obj_expled.decode(
1385 obj_expled_encoded + tail_junk,
1390 self.assertEqual(tail, tail_junk)
1391 self.assertEqual(obj_decoded, obj_expled)
1392 self.assertNotEqual(obj_decoded, obj)
1393 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1394 self.assertEqual(bytes(obj_decoded), bytes(obj))
1395 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1396 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1397 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1399 obj_decoded.expl_llen,
1400 len(len_encode(len(obj_encoded))),
1402 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1403 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1406 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1408 self.assertEqual(obj_decoded.expl_offset, offset)
1409 if isinstance(value, tuple):
1410 self.assertSetEqual(set(value), set(obj_decoded.named))
1414 @given(integers(min_value=1, max_value=255))
1415 def test_bad_zero_value(self, pad_size):
1416 with self.assertRaises(DecodeError):
1417 BitString().decode(b"".join((
1418 BitString.tag_default,
1423 def test_go_vectors_invalid(self):
1429 with self.assertRaises(DecodeError):
1430 BitString().decode(b"".join((
1431 BitString.tag_default,
1436 def test_go_vectors_valid(self):
1437 obj, _ = BitString().decode(b"".join((
1438 BitString.tag_default,
1442 self.assertEqual(bytes(obj), b"")
1443 self.assertEqual(obj.bit_len, 0)
1445 obj, _ = BitString().decode(b"".join((
1446 BitString.tag_default,
1450 self.assertEqual(bytes(obj), b"\x00")
1451 self.assertEqual(obj.bit_len, 1)
1453 obj = BitString((16, b"\x82\x40"))
1454 self.assertTrue(obj[0])
1455 self.assertFalse(obj[1])
1456 self.assertTrue(obj[6])
1457 self.assertTrue(obj[9])
1458 self.assertFalse(obj[17])
1461 integers(min_value=1, max_value=30),
1464 binary(min_size=1, max_size=5),
1466 binary(min_size=1, max_size=5),
1474 lists(booleans(), min_size=1),
1477 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1478 def chunk_constructed(contents):
1480 tag_encode(form=TagFormConstructed, num=3) +
1482 b"".join(BitString(content).encode() for content in contents) +
1486 payload_expected = b""
1487 bit_len_expected = 0
1488 for chunk_input in chunk_inputs:
1489 if isinstance(chunk_input, binary_type):
1490 chunks.append(BitString(chunk_input).encode())
1491 payload_expected += chunk_input
1492 bit_len_expected += len(chunk_input) * 8
1494 chunks.append(chunk_constructed(chunk_input))
1495 payload = b"".join(chunk_input)
1496 payload_expected += payload
1497 bit_len_expected += len(payload) * 8
1498 chunk_last = BitString("'%s'B" % "".join(
1499 "1" if bit else "0" for bit in chunk_last_bits
1501 payload_expected += bytes(chunk_last)
1502 bit_len_expected += chunk_last.bit_len
1503 encoded_indefinite = (
1504 tag_encode(form=TagFormConstructed, num=impl) +
1507 chunk_last.encode() +
1510 encoded_definite = (
1511 tag_encode(form=TagFormConstructed, num=impl) +
1512 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1516 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1517 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1518 for lenindef_expected, encoded in (
1519 (True, encoded_indefinite),
1520 (False, encoded_definite),
1522 obj, tail = BitString(impl=tag_encode(impl)).decode(
1524 ctx={"bered": True},
1526 self.assertSequenceEqual(tail, junk)
1527 self.assertEqual(obj.bit_len, bit_len_expected)
1528 self.assertSequenceEqual(bytes(obj), payload_expected)
1529 self.assertTrue(obj.bered)
1530 self.assertEqual(obj.lenindef, lenindef_expected)
1531 self.assertEqual(len(encoded), obj.tlvlen)
1534 integers(min_value=0),
1537 def test_ber_definite_too_short(self, offset, decode_path):
1538 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1540 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1542 decode_path=decode_path,
1543 ctx={"bered": True},
1545 self.assertEqual(err.exception.decode_path, decode_path)
1546 self.assertEqual(err.exception.offset, offset)
1549 integers(min_value=0),
1552 def test_ber_definite_no_data(self, offset, decode_path):
1553 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1555 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1557 decode_path=decode_path,
1558 ctx={"bered": True},
1560 self.assertEqual(err.exception.decode_path, decode_path)
1561 self.assertEqual(err.exception.offset, offset)
1564 integers(min_value=0),
1566 integers(min_value=1, max_value=3),
1568 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1569 bs = BitString(b"data").encode()
1570 with self.assertRaises(NotEnoughData) as err:
1572 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1574 decode_path=decode_path,
1575 ctx={"bered": True},
1577 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1578 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1581 integers(min_value=0),
1583 integers(min_value=1, max_value=3),
1585 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1586 bs = BitString(b"data").encode()
1587 bs_longer = BitString(b"data-longer").encode()
1588 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1591 tag_encode(3, form=TagFormConstructed) +
1592 len_encode((chunks + 1) * len(bs)) +
1597 decode_path=decode_path,
1598 ctx={"bered": True},
1600 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1601 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1604 integers(min_value=0),
1607 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1608 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1610 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1612 decode_path=decode_path,
1613 ctx={"bered": True},
1615 self.assertEqual(err.exception.decode_path, decode_path)
1616 self.assertEqual(err.exception.offset, offset)
1618 @given(data_strategy())
1619 def test_ber_indefinite_not_multiple(self, d):
1620 bs_short = BitString("'A'H").encode()
1621 bs_full = BitString("'AA'H").encode()
1622 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1623 chunks.append(bs_short)
1624 d.draw(permutations(chunks))
1625 chunks.append(bs_short)
1626 offset = d.draw(integers(min_value=0))
1627 decode_path = d.draw(decode_path_strat)
1628 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1631 tag_encode(3, form=TagFormConstructed) +
1637 decode_path=decode_path,
1638 ctx={"bered": True},
1641 err.exception.decode_path,
1642 decode_path + (str(chunks.index(bs_short)),),
1645 err.exception.offset,
1646 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1649 def test_x690_vector(self):
1650 vector = BitString("'0A3B5F291CD'H")
1651 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1652 self.assertSequenceEqual(tail, b"")
1653 self.assertEqual(obj, vector)
1654 obj, tail = BitString().decode(
1655 hexdec("23800303000A3B0305045F291CD00000"),
1656 ctx={"bered": True},
1658 self.assertSequenceEqual(tail, b"")
1659 self.assertEqual(obj, vector)
1660 self.assertTrue(obj.bered)
1661 self.assertTrue(obj.lenindef)
1665 def octet_string_values_strategy(draw, do_expl=False):
1666 bound_min, bound_max = sorted(draw(sets(
1667 integers(min_value=0, max_value=1 << 7),
1671 value = draw(one_of(
1673 binary(min_size=bound_min, max_size=bound_max),
1675 default = draw(one_of(
1677 binary(min_size=bound_min, max_size=bound_max),
1680 if draw(booleans()):
1681 bounds = (bound_min, bound_max)
1685 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1687 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1688 optional = draw(one_of(none(), booleans()))
1690 draw(integers(min_value=0)),
1691 draw(integers(min_value=0)),
1692 draw(integers(min_value=0)),
1694 return (value, bounds, impl, expl, default, optional, _decoded)
1697 class OctetStringInherited(OctetString):
1701 class TestOctetString(CommonMixin, TestCase):
1702 base_klass = OctetString
1704 def test_invalid_value_type(self):
1705 with self.assertRaises(InvalidValueType) as err:
1706 OctetString(text_type(123))
1710 def test_optional(self, optional):
1711 obj = OctetString(default=OctetString(b""), optional=optional)
1712 self.assertTrue(obj.optional)
1715 def test_ready(self, value):
1717 self.assertFalse(obj.ready)
1720 with self.assertRaises(ObjNotReady) as err:
1723 obj = OctetString(value)
1724 self.assertTrue(obj.ready)
1728 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1729 def test_comparison(self, value1, value2, tag1, tag2):
1730 for klass in (OctetString, OctetStringInherited):
1731 obj1 = klass(value1)
1732 obj2 = klass(value2)
1733 self.assertEqual(obj1 == obj2, value1 == value2)
1734 self.assertEqual(obj1 != obj2, value1 != value2)
1735 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1736 obj1 = klass(value1, impl=tag1)
1737 obj2 = klass(value1, impl=tag2)
1738 self.assertEqual(obj1 == obj2, tag1 == tag2)
1739 self.assertEqual(obj1 != obj2, tag1 != tag2)
1741 @given(lists(binary()))
1742 def test_sorted_works(self, values):
1743 self.assertSequenceEqual(
1744 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1748 @given(data_strategy())
1749 def test_bounds_satisfied(self, d):
1750 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1751 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1752 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1753 OctetString(value=value, bounds=(bound_min, bound_max))
1755 @given(data_strategy())
1756 def test_bounds_unsatisfied(self, d):
1757 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1758 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1759 value = d.draw(binary(max_size=bound_min - 1))
1760 with self.assertRaises(BoundsError) as err:
1761 OctetString(value=value, bounds=(bound_min, bound_max))
1763 value = d.draw(binary(min_size=bound_max + 1))
1764 with self.assertRaises(BoundsError) as err:
1765 OctetString(value=value, bounds=(bound_min, bound_max))
1768 @given(data_strategy())
1769 def test_call(self, d):
1770 for klass in (OctetString, OctetStringInherited):
1779 ) = d.draw(octet_string_values_strategy())
1780 obj_initial = klass(
1786 optional_initial or False,
1797 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1798 if (default is None) and (obj_initial.default is not None):
1801 (bounds is None) and
1802 (value is not None) and
1803 (bounds_initial is not None) and
1804 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1808 (bounds is None) and
1809 (default is not None) and
1810 (bounds_initial is not None) and
1811 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1814 obj = obj_initial(value, bounds, impl, expl, default, optional)
1816 value_expected = default if value is None else value
1818 default_initial if value_expected is None
1821 self.assertEqual(obj, value_expected)
1822 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1823 self.assertEqual(obj.expl_tag, expl or expl_initial)
1826 default_initial if default is None else default,
1828 if obj.default is None:
1829 optional = optional_initial if optional is None else optional
1830 optional = False if optional is None else optional
1833 self.assertEqual(obj.optional, optional)
1835 (obj._bound_min, obj._bound_max),
1836 bounds or bounds_initial or (0, float("+inf")),
1839 @given(octet_string_values_strategy())
1840 def test_copy(self, values):
1841 for klass in (OctetString, OctetStringInherited):
1842 obj = klass(*values)
1843 obj_copied = obj.copy()
1844 self.assert_copied_basic_fields(obj, obj_copied)
1845 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1846 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1847 self.assertEqual(obj._value, obj_copied._value)
1851 integers(min_value=1).map(tag_encode),
1853 def test_stripped(self, value, tag_impl):
1854 obj = OctetString(value, impl=tag_impl)
1855 with self.assertRaises(NotEnoughData):
1856 obj.decode(obj.encode()[:-1])
1860 integers(min_value=1).map(tag_ctxc),
1862 def test_stripped_expl(self, value, tag_expl):
1863 obj = OctetString(value, expl=tag_expl)
1864 with self.assertRaises(NotEnoughData):
1865 obj.decode(obj.encode()[:-1])
1868 integers(min_value=31),
1869 integers(min_value=0),
1872 def test_bad_tag(self, tag, offset, decode_path):
1873 with self.assertRaises(DecodeError) as err:
1874 OctetString().decode(
1875 tag_encode(tag)[:-1],
1877 decode_path=decode_path,
1880 self.assertEqual(err.exception.offset, offset)
1881 self.assertEqual(err.exception.decode_path, decode_path)
1884 integers(min_value=128),
1885 integers(min_value=0),
1888 def test_bad_len(self, l, offset, decode_path):
1889 with self.assertRaises(DecodeError) as err:
1890 OctetString().decode(
1891 OctetString.tag_default + len_encode(l)[:-1],
1893 decode_path=decode_path,
1896 self.assertEqual(err.exception.offset, offset)
1897 self.assertEqual(err.exception.decode_path, decode_path)
1900 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1901 integers(min_value=0),
1904 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1905 value, bound_min = list(sorted(ints))
1907 class String(OctetString):
1908 bounds = (bound_min, bound_min)
1909 with self.assertRaises(DecodeError) as err:
1911 OctetString(b"\x00" * value).encode(),
1913 decode_path=decode_path,
1916 self.assertEqual(err.exception.offset, offset)
1917 self.assertEqual(err.exception.decode_path, decode_path)
1919 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1921 octet_string_values_strategy(),
1923 integers(min_value=1).map(tag_ctxc),
1924 integers(min_value=0),
1927 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1928 for klass in (OctetString, OctetStringInherited):
1929 _, _, _, _, default, optional, _decoded = values
1938 self.assertFalse(obj.expled)
1939 obj_encoded = obj.encode()
1940 obj_expled = obj(value, expl=tag_expl)
1941 self.assertTrue(obj_expled.expled)
1944 obj_expled_encoded = obj_expled.encode()
1945 obj_decoded, tail = obj_expled.decode(
1946 obj_expled_encoded + tail_junk,
1951 self.assertEqual(tail, tail_junk)
1952 self.assertEqual(obj_decoded, obj_expled)
1953 self.assertNotEqual(obj_decoded, obj)
1954 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1955 self.assertEqual(bytes(obj_decoded), bytes(obj))
1956 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1957 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1958 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1960 obj_decoded.expl_llen,
1961 len(len_encode(len(obj_encoded))),
1963 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1964 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1967 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1969 self.assertEqual(obj_decoded.expl_offset, offset)
1972 integers(min_value=1, max_value=30),
1975 binary(min_size=1, max_size=5),
1977 binary(min_size=1, max_size=5),
1987 def test_constructed(self, impl, chunk_inputs, junk):
1988 def chunk_constructed(contents):
1990 tag_encode(form=TagFormConstructed, num=4) +
1992 b"".join(OctetString(content).encode() for content in contents) +
1996 payload_expected = b""
1997 for chunk_input in chunk_inputs:
1998 if isinstance(chunk_input, binary_type):
1999 chunks.append(OctetString(chunk_input).encode())
2000 payload_expected += chunk_input
2002 chunks.append(chunk_constructed(chunk_input))
2003 payload = b"".join(chunk_input)
2004 payload_expected += payload
2005 encoded_indefinite = (
2006 tag_encode(form=TagFormConstructed, num=impl) +
2011 encoded_definite = (
2012 tag_encode(form=TagFormConstructed, num=impl) +
2013 len_encode(len(b"".join(chunks))) +
2016 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2017 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2018 for lenindef_expected, encoded in (
2019 (True, encoded_indefinite),
2020 (False, encoded_definite),
2022 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2024 ctx={"bered": True},
2026 self.assertSequenceEqual(tail, junk)
2027 self.assertSequenceEqual(bytes(obj), payload_expected)
2028 self.assertTrue(obj.bered)
2029 self.assertEqual(obj.lenindef, lenindef_expected)
2030 self.assertEqual(len(encoded), obj.tlvlen)
2033 integers(min_value=0),
2036 def test_ber_definite_too_short(self, offset, decode_path):
2037 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2038 OctetString().decode(
2039 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2041 decode_path=decode_path,
2042 ctx={"bered": True},
2044 self.assertEqual(err.exception.decode_path, decode_path)
2045 self.assertEqual(err.exception.offset, offset)
2048 integers(min_value=0),
2050 integers(min_value=1, max_value=3),
2052 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2053 bs = OctetString(b"data").encode()
2054 with self.assertRaises(NotEnoughData) as err:
2055 OctetString().decode(
2056 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2058 decode_path=decode_path,
2059 ctx={"bered": True},
2061 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2062 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2065 integers(min_value=0),
2067 integers(min_value=1, max_value=3),
2069 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2070 bs = OctetString(b"data").encode()
2071 bs_longer = OctetString(b"data-longer").encode()
2072 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2073 OctetString().decode(
2075 tag_encode(4, form=TagFormConstructed) +
2076 len_encode((chunks + 1) * len(bs)) +
2081 decode_path=decode_path,
2082 ctx={"bered": True},
2084 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2085 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2089 def null_values_strategy(draw, do_expl=False):
2093 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2095 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2096 optional = draw(one_of(none(), booleans()))
2098 draw(integers(min_value=0)),
2099 draw(integers(min_value=0)),
2100 draw(integers(min_value=0)),
2102 return (impl, expl, optional, _decoded)
2105 class NullInherited(Null):
2109 class TestNull(CommonMixin, TestCase):
2112 def test_ready(self):
2114 self.assertTrue(obj.ready)
2118 @given(binary(), binary())
2119 def test_comparison(self, tag1, tag2):
2120 for klass in (Null, NullInherited):
2121 obj1 = klass(impl=tag1)
2122 obj2 = klass(impl=tag2)
2123 self.assertEqual(obj1 == obj2, tag1 == tag2)
2124 self.assertEqual(obj1 != obj2, tag1 != tag2)
2125 self.assertNotEqual(obj1, tag2)
2127 @given(data_strategy())
2128 def test_call(self, d):
2129 for klass in (Null, NullInherited):
2135 ) = d.draw(null_values_strategy())
2136 obj_initial = klass(
2139 optional=optional_initial or False,
2140 _decoded=_decoded_initial,
2147 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2148 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2149 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2150 self.assertEqual(obj.expl_tag, expl or expl_initial)
2151 optional = optional_initial if optional is None else optional
2152 optional = False if optional is None else optional
2153 self.assertEqual(obj.optional, optional)
2155 @given(null_values_strategy())
2156 def test_copy(self, values):
2157 for klass in (Null, NullInherited):
2158 impl, expl, optional, _decoded = values
2162 optional=optional or False,
2165 obj_copied = obj.copy()
2166 self.assert_copied_basic_fields(obj, obj_copied)
2168 @given(integers(min_value=1).map(tag_encode))
2169 def test_stripped(self, tag_impl):
2170 obj = Null(impl=tag_impl)
2171 with self.assertRaises(NotEnoughData):
2172 obj.decode(obj.encode()[:-1])
2174 @given(integers(min_value=1).map(tag_ctxc))
2175 def test_stripped_expl(self, tag_expl):
2176 obj = Null(expl=tag_expl)
2177 with self.assertRaises(NotEnoughData):
2178 obj.decode(obj.encode()[:-1])
2181 integers(min_value=31),
2182 integers(min_value=0),
2185 def test_bad_tag(self, tag, offset, decode_path):
2186 with self.assertRaises(DecodeError) as err:
2188 tag_encode(tag)[:-1],
2190 decode_path=decode_path,
2193 self.assertEqual(err.exception.offset, offset)
2194 self.assertEqual(err.exception.decode_path, decode_path)
2197 integers(min_value=128),
2198 integers(min_value=0),
2201 def test_bad_len(self, l, offset, decode_path):
2202 with self.assertRaises(DecodeError) as err:
2204 Null.tag_default + len_encode(l)[:-1],
2206 decode_path=decode_path,
2209 self.assertEqual(err.exception.offset, offset)
2210 self.assertEqual(err.exception.decode_path, decode_path)
2212 @given(binary(min_size=1))
2213 def test_tag_mismatch(self, impl):
2214 assume(impl != Null.tag_default)
2215 with self.assertRaises(TagMismatch):
2216 Null(impl=impl).decode(Null().encode())
2219 null_values_strategy(),
2220 integers(min_value=1).map(tag_ctxc),
2221 integers(min_value=0),
2224 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2225 for klass in (Null, NullInherited):
2226 _, _, optional, _decoded = values
2227 obj = klass(optional=optional, _decoded=_decoded)
2230 self.assertFalse(obj.expled)
2231 obj_encoded = obj.encode()
2232 obj_expled = obj(expl=tag_expl)
2233 self.assertTrue(obj_expled.expled)
2236 obj_expled_encoded = obj_expled.encode()
2237 obj_decoded, tail = obj_expled.decode(
2238 obj_expled_encoded + tail_junk,
2243 self.assertEqual(tail, tail_junk)
2244 self.assertEqual(obj_decoded, obj_expled)
2245 self.assertNotEqual(obj_decoded, obj)
2246 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2247 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2248 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2250 obj_decoded.expl_llen,
2251 len(len_encode(len(obj_encoded))),
2253 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2254 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2257 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2259 self.assertEqual(obj_decoded.expl_offset, offset)
2261 @given(integers(min_value=1))
2262 def test_invalid_len(self, l):
2263 with self.assertRaises(InvalidLength):
2264 Null().decode(b"".join((
2271 def oid_strategy(draw):
2272 first_arc = draw(integers(min_value=0, max_value=2))
2274 if first_arc in (0, 1):
2275 second_arc = draw(integers(min_value=0, max_value=39))
2277 second_arc = draw(integers(min_value=0))
2278 other_arcs = draw(lists(integers(min_value=0)))
2279 return tuple([first_arc, second_arc] + other_arcs)
2283 def oid_values_strategy(draw, do_expl=False):
2284 value = draw(one_of(none(), oid_strategy()))
2288 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2290 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2291 default = draw(one_of(none(), oid_strategy()))
2292 optional = draw(one_of(none(), booleans()))
2294 draw(integers(min_value=0)),
2295 draw(integers(min_value=0)),
2296 draw(integers(min_value=0)),
2298 return (value, impl, expl, default, optional, _decoded)
2301 class ObjectIdentifierInherited(ObjectIdentifier):
2305 class TestObjectIdentifier(CommonMixin, TestCase):
2306 base_klass = ObjectIdentifier
2308 def test_invalid_value_type(self):
2309 with self.assertRaises(InvalidValueType) as err:
2310 ObjectIdentifier(123)
2314 def test_optional(self, optional):
2315 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2316 self.assertTrue(obj.optional)
2318 @given(oid_strategy())
2319 def test_ready(self, value):
2320 obj = ObjectIdentifier()
2321 self.assertFalse(obj.ready)
2324 with self.assertRaises(ObjNotReady) as err:
2327 obj = ObjectIdentifier(value)
2328 self.assertTrue(obj.ready)
2333 @given(oid_strategy(), oid_strategy(), binary(), binary())
2334 def test_comparison(self, value1, value2, tag1, tag2):
2335 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2336 obj1 = klass(value1)
2337 obj2 = klass(value2)
2338 self.assertEqual(obj1 == obj2, value1 == value2)
2339 self.assertEqual(obj1 != obj2, value1 != value2)
2340 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2341 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2342 obj1 = klass(value1, impl=tag1)
2343 obj2 = klass(value1, impl=tag2)
2344 self.assertEqual(obj1 == obj2, tag1 == tag2)
2345 self.assertEqual(obj1 != obj2, tag1 != tag2)
2347 @given(lists(oid_strategy()))
2348 def test_sorted_works(self, values):
2349 self.assertSequenceEqual(
2350 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2354 @given(data_strategy())
2355 def test_call(self, d):
2356 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2364 ) = d.draw(oid_values_strategy())
2365 obj_initial = klass(
2366 value=value_initial,
2369 default=default_initial,
2370 optional=optional_initial or False,
2371 _decoded=_decoded_initial,
2380 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2389 value_expected = default if value is None else value
2391 default_initial if value_expected is None
2394 self.assertEqual(obj, value_expected)
2395 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2396 self.assertEqual(obj.expl_tag, expl or expl_initial)
2399 default_initial if default is None else default,
2401 if obj.default is None:
2402 optional = optional_initial if optional is None else optional
2403 optional = False if optional is None else optional
2406 self.assertEqual(obj.optional, optional)
2408 @given(oid_values_strategy())
2409 def test_copy(self, values):
2410 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2427 obj_copied = obj.copy()
2428 self.assert_copied_basic_fields(obj, obj_copied)
2429 self.assertEqual(obj._value, obj_copied._value)
2431 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2434 integers(min_value=1).map(tag_encode),
2436 def test_stripped(self, value, tag_impl):
2437 obj = ObjectIdentifier(value, impl=tag_impl)
2438 with self.assertRaises(NotEnoughData):
2439 obj.decode(obj.encode()[:-1])
2443 integers(min_value=1).map(tag_ctxc),
2445 def test_stripped_expl(self, value, tag_expl):
2446 obj = ObjectIdentifier(value, expl=tag_expl)
2447 with self.assertRaises(NotEnoughData):
2448 obj.decode(obj.encode()[:-1])
2451 integers(min_value=31),
2452 integers(min_value=0),
2455 def test_bad_tag(self, tag, offset, decode_path):
2456 with self.assertRaises(DecodeError) as err:
2457 ObjectIdentifier().decode(
2458 tag_encode(tag)[:-1],
2460 decode_path=decode_path,
2463 self.assertEqual(err.exception.offset, offset)
2464 self.assertEqual(err.exception.decode_path, decode_path)
2467 integers(min_value=128),
2468 integers(min_value=0),
2471 def test_bad_len(self, l, offset, decode_path):
2472 with self.assertRaises(DecodeError) as err:
2473 ObjectIdentifier().decode(
2474 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2476 decode_path=decode_path,
2479 self.assertEqual(err.exception.offset, offset)
2480 self.assertEqual(err.exception.decode_path, decode_path)
2482 def test_zero_oid(self):
2483 with self.assertRaises(NotEnoughData):
2484 ObjectIdentifier().decode(
2485 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2488 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2489 @given(oid_strategy())
2490 def test_unfinished_oid(self, value):
2491 assume(list(value)[-1] > 255)
2492 obj_encoded = ObjectIdentifier(value).encode()
2493 obj, _ = ObjectIdentifier().decode(obj_encoded)
2494 data = obj_encoded[obj.tlen + obj.llen:-1]
2496 ObjectIdentifier.tag_default,
2497 len_encode(len(data)),
2500 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2503 @given(integers(min_value=0))
2504 def test_invalid_short(self, value):
2505 with self.assertRaises(InvalidOID):
2506 ObjectIdentifier((value,))
2507 with self.assertRaises(InvalidOID):
2508 ObjectIdentifier("%d" % value)
2510 @given(integers(min_value=3), integers(min_value=0))
2511 def test_invalid_first_arc(self, first_arc, second_arc):
2512 with self.assertRaises(InvalidOID):
2513 ObjectIdentifier((first_arc, second_arc))
2514 with self.assertRaises(InvalidOID):
2515 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2517 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2518 def test_invalid_second_arc(self, first_arc, second_arc):
2519 with self.assertRaises(InvalidOID):
2520 ObjectIdentifier((first_arc, second_arc))
2521 with self.assertRaises(InvalidOID):
2522 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2524 @given(text(alphabet=ascii_letters + ".", min_size=1))
2525 def test_junk(self, oid):
2526 with self.assertRaises(InvalidOID):
2527 ObjectIdentifier(oid)
2529 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2530 @given(oid_strategy())
2531 def test_validness(self, oid):
2532 obj = ObjectIdentifier(oid)
2533 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2538 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2540 oid_values_strategy(),
2542 integers(min_value=1).map(tag_ctxc),
2543 integers(min_value=0),
2546 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2547 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2548 _, _, _, default, optional, _decoded = values
2557 self.assertFalse(obj.expled)
2558 obj_encoded = obj.encode()
2559 obj_expled = obj(value, expl=tag_expl)
2560 self.assertTrue(obj_expled.expled)
2563 obj_expled_encoded = obj_expled.encode()
2564 obj_decoded, tail = obj_expled.decode(
2565 obj_expled_encoded + tail_junk,
2570 self.assertEqual(tail, tail_junk)
2571 self.assertEqual(obj_decoded, obj_expled)
2572 self.assertNotEqual(obj_decoded, obj)
2573 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2574 self.assertEqual(tuple(obj_decoded), tuple(obj))
2575 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2576 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2577 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2579 obj_decoded.expl_llen,
2580 len(len_encode(len(obj_encoded))),
2582 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2583 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2586 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2588 self.assertEqual(obj_decoded.expl_offset, offset)
2591 oid_strategy().map(ObjectIdentifier),
2592 oid_strategy().map(ObjectIdentifier),
2594 def test_add(self, oid1, oid2):
2595 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2596 for oid_to_add in (oid2, tuple(oid2)):
2597 self.assertEqual(oid1 + oid_to_add, oid_expect)
2598 with self.assertRaises(InvalidValueType):
2601 def test_go_vectors_valid(self):
2602 for data, expect in (
2604 (b"\x55\x02", (2, 5, 2)),
2605 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2606 (b"\x81\x34\x03", (2, 100, 3)),
2609 ObjectIdentifier().decode(b"".join((
2610 ObjectIdentifier.tag_default,
2611 len_encode(len(data)),
2617 def test_go_vectors_invalid(self):
2618 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2619 with self.assertRaises(DecodeError):
2620 ObjectIdentifier().decode(b"".join((
2621 Integer.tag_default,
2622 len_encode(len(data)),
2626 def test_x690_vector(self):
2628 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2629 ObjectIdentifier((2, 999, 3)),
2634 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2636 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2637 values = list(draw(sets(
2639 min_size=len(schema),
2640 max_size=len(schema),
2642 schema = list(zip(schema, values))
2643 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2647 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2649 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2650 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2651 optional = draw(one_of(none(), booleans()))
2653 draw(integers(min_value=0)),
2654 draw(integers(min_value=0)),
2655 draw(integers(min_value=0)),
2657 return (schema, value, impl, expl, default, optional, _decoded)
2660 class TestEnumerated(CommonMixin, TestCase):
2661 class EWhatever(Enumerated):
2662 schema = (("whatever", 0),)
2664 base_klass = EWhatever
2666 def test_schema_required(self):
2667 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2670 def test_invalid_value_type(self):
2671 with self.assertRaises(InvalidValueType) as err:
2672 self.base_klass((1, 2))
2675 @given(sets(text_letters(), min_size=2))
2676 def test_unknown_name(self, schema_input):
2677 missing = schema_input.pop()
2679 class E(Enumerated):
2680 schema = [(n, 123) for n in schema_input]
2681 with self.assertRaises(ObjUnknown) as err:
2686 sets(text_letters(), min_size=2),
2687 sets(integers(), min_size=2),
2689 def test_unknown_value(self, schema_input, values_input):
2691 missing_value = values_input.pop()
2692 _input = list(zip(schema_input, values_input))
2694 class E(Enumerated):
2696 with self.assertRaises(DecodeError) as err:
2701 def test_optional(self, optional):
2702 obj = self.base_klass(default="whatever", optional=optional)
2703 self.assertTrue(obj.optional)
2705 def test_ready(self):
2706 obj = self.base_klass()
2707 self.assertFalse(obj.ready)
2710 with self.assertRaises(ObjNotReady) as err:
2713 obj = self.base_klass("whatever")
2714 self.assertTrue(obj.ready)
2718 @given(integers(), integers(), binary(), binary())
2719 def test_comparison(self, value1, value2, tag1, tag2):
2720 class E(Enumerated):
2722 ("whatever0", value1),
2723 ("whatever1", value2),
2726 class EInherited(E):
2728 for klass in (E, EInherited):
2729 obj1 = klass(value1)
2730 obj2 = klass(value2)
2731 self.assertEqual(obj1 == obj2, value1 == value2)
2732 self.assertEqual(obj1 != obj2, value1 != value2)
2733 self.assertEqual(obj1 == int(obj2), value1 == value2)
2734 obj1 = klass(value1, impl=tag1)
2735 obj2 = klass(value1, impl=tag2)
2736 self.assertEqual(obj1 == obj2, tag1 == tag2)
2737 self.assertEqual(obj1 != obj2, tag1 != tag2)
2739 @given(data_strategy())
2740 def test_call(self, d):
2749 ) = d.draw(enumerated_values_strategy())
2751 class E(Enumerated):
2752 schema = schema_initial
2754 value=value_initial,
2757 default=default_initial,
2758 optional=optional_initial or False,
2759 _decoded=_decoded_initial,
2769 ) = d.draw(enumerated_values_strategy(
2770 schema=schema_initial,
2771 do_expl=impl_initial is None,
2781 value_expected = default if value is None else value
2783 default_initial if value_expected is None
2788 dict(schema_initial).get(value_expected, value_expected),
2790 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2791 self.assertEqual(obj.expl_tag, expl or expl_initial)
2794 default_initial if default is None else default,
2796 if obj.default is None:
2797 optional = optional_initial if optional is None else optional
2798 optional = False if optional is None else optional
2801 self.assertEqual(obj.optional, optional)
2802 self.assertEqual(obj.specs, dict(schema_initial))
2804 @given(enumerated_values_strategy())
2805 def test_copy(self, values):
2806 schema_input, value, impl, expl, default, optional, _decoded = values
2808 class E(Enumerated):
2809 schema = schema_input
2818 obj_copied = obj.copy()
2819 self.assert_copied_basic_fields(obj, obj_copied)
2820 self.assertEqual(obj.specs, obj_copied.specs)
2822 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2823 @given(data_strategy())
2824 def test_symmetric(self, d):
2825 schema_input, _, _, _, default, optional, _decoded = d.draw(
2826 enumerated_values_strategy(),
2828 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2829 offset = d.draw(integers(min_value=0))
2830 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2831 tail_junk = d.draw(binary(max_size=5))
2833 class E(Enumerated):
2834 schema = schema_input
2843 self.assertFalse(obj.expled)
2844 obj_encoded = obj.encode()
2845 obj_expled = obj(value, expl=tag_expl)
2846 self.assertTrue(obj_expled.expled)
2849 obj_expled_encoded = obj_expled.encode()
2850 obj_decoded, tail = obj_expled.decode(
2851 obj_expled_encoded + tail_junk,
2856 self.assertEqual(tail, tail_junk)
2857 self.assertEqual(obj_decoded, obj_expled)
2858 self.assertNotEqual(obj_decoded, obj)
2859 self.assertEqual(int(obj_decoded), int(obj_expled))
2860 self.assertEqual(int(obj_decoded), int(obj))
2861 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2862 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2863 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2865 obj_decoded.expl_llen,
2866 len(len_encode(len(obj_encoded))),
2868 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2869 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2872 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2874 self.assertEqual(obj_decoded.expl_offset, offset)
2878 def string_values_strategy(draw, alphabet, do_expl=False):
2879 bound_min, bound_max = sorted(draw(sets(
2880 integers(min_value=0, max_value=1 << 7),
2884 value = draw(one_of(
2886 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2888 default = draw(one_of(
2890 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2893 if draw(booleans()):
2894 bounds = (bound_min, bound_max)
2898 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2900 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2901 optional = draw(one_of(none(), booleans()))
2903 draw(integers(min_value=0)),
2904 draw(integers(min_value=0)),
2905 draw(integers(min_value=0)),
2907 return (value, bounds, impl, expl, default, optional, _decoded)
2910 class StringMixin(object):
2911 def test_invalid_value_type(self):
2912 with self.assertRaises(InvalidValueType) as err:
2913 self.base_klass((1, 2))
2916 def text_alphabet(self):
2917 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2918 return printable + whitespace
2922 def test_optional(self, optional):
2923 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2924 self.assertTrue(obj.optional)
2926 @given(data_strategy())
2927 def test_ready(self, d):
2928 obj = self.base_klass()
2929 self.assertFalse(obj.ready)
2933 with self.assertRaises(ObjNotReady) as err:
2936 value = d.draw(text(alphabet=self.text_alphabet()))
2937 obj = self.base_klass(value)
2938 self.assertTrue(obj.ready)
2943 @given(data_strategy())
2944 def test_comparison(self, d):
2945 value1 = d.draw(text(alphabet=self.text_alphabet()))
2946 value2 = d.draw(text(alphabet=self.text_alphabet()))
2947 tag1 = d.draw(binary(min_size=1))
2948 tag2 = d.draw(binary(min_size=1))
2949 obj1 = self.base_klass(value1)
2950 obj2 = self.base_klass(value2)
2951 self.assertEqual(obj1 == obj2, value1 == value2)
2952 self.assertEqual(obj1 != obj2, value1 != value2)
2953 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2954 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2955 obj1 = self.base_klass(value1, impl=tag1)
2956 obj2 = self.base_klass(value1, impl=tag2)
2957 self.assertEqual(obj1 == obj2, tag1 == tag2)
2958 self.assertEqual(obj1 != obj2, tag1 != tag2)
2960 @given(data_strategy())
2961 def test_bounds_satisfied(self, d):
2962 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2963 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2964 value = d.draw(text(
2965 alphabet=self.text_alphabet(),
2969 self.base_klass(value=value, bounds=(bound_min, bound_max))
2971 @given(data_strategy())
2972 def test_bounds_unsatisfied(self, d):
2973 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2974 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2975 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2976 with self.assertRaises(BoundsError) as err:
2977 self.base_klass(value=value, bounds=(bound_min, bound_max))
2979 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2980 with self.assertRaises(BoundsError) as err:
2981 self.base_klass(value=value, bounds=(bound_min, bound_max))
2984 @given(data_strategy())
2985 def test_call(self, d):
2994 ) = d.draw(string_values_strategy(self.text_alphabet()))
2995 obj_initial = self.base_klass(
3001 optional_initial or False,
3012 ) = d.draw(string_values_strategy(
3013 self.text_alphabet(),
3014 do_expl=impl_initial is None,
3016 if (default is None) and (obj_initial.default is not None):
3019 (bounds is None) and
3020 (value is not None) and
3021 (bounds_initial is not None) and
3022 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3026 (bounds is None) and
3027 (default is not None) and
3028 (bounds_initial is not None) and
3029 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3032 obj = obj_initial(value, bounds, impl, expl, default, optional)
3034 value_expected = default if value is None else value
3036 default_initial if value_expected is None
3039 self.assertEqual(obj, value_expected)
3040 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3041 self.assertEqual(obj.expl_tag, expl or expl_initial)
3044 default_initial if default is None else default,
3046 if obj.default is None:
3047 optional = optional_initial if optional is None else optional
3048 optional = False if optional is None else optional
3051 self.assertEqual(obj.optional, optional)
3053 (obj._bound_min, obj._bound_max),
3054 bounds or bounds_initial or (0, float("+inf")),
3057 @given(data_strategy())
3058 def test_copy(self, d):
3059 values = d.draw(string_values_strategy(self.text_alphabet()))
3060 obj = self.base_klass(*values)
3061 obj_copied = obj.copy()
3062 self.assert_copied_basic_fields(obj, obj_copied)
3063 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3064 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3065 self.assertEqual(obj._value, obj_copied._value)
3067 @given(data_strategy())
3068 def test_stripped(self, d):
3069 value = d.draw(text(alphabet=self.text_alphabet()))
3070 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3071 obj = self.base_klass(value, impl=tag_impl)
3072 with self.assertRaises(NotEnoughData):
3073 obj.decode(obj.encode()[:-1])
3075 @given(data_strategy())
3076 def test_stripped_expl(self, d):
3077 value = d.draw(text(alphabet=self.text_alphabet()))
3078 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3079 obj = self.base_klass(value, expl=tag_expl)
3080 with self.assertRaises(NotEnoughData):
3081 obj.decode(obj.encode()[:-1])
3084 integers(min_value=31),
3085 integers(min_value=0),
3088 def test_bad_tag(self, tag, offset, decode_path):
3089 with self.assertRaises(DecodeError) as err:
3090 self.base_klass().decode(
3091 tag_encode(tag)[:-1],
3093 decode_path=decode_path,
3096 self.assertEqual(err.exception.offset, offset)
3097 self.assertEqual(err.exception.decode_path, decode_path)
3100 integers(min_value=128),
3101 integers(min_value=0),
3104 def test_bad_len(self, l, offset, decode_path):
3105 with self.assertRaises(DecodeError) as err:
3106 self.base_klass().decode(
3107 self.base_klass.tag_default + len_encode(l)[:-1],
3109 decode_path=decode_path,
3112 self.assertEqual(err.exception.offset, offset)
3113 self.assertEqual(err.exception.decode_path, decode_path)
3116 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3117 integers(min_value=0),
3120 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3121 value, bound_min = list(sorted(ints))
3123 class String(self.base_klass):
3124 # Multiply this value by four, to satisfy UTF-32 bounds
3125 # (4 bytes per character) validation
3126 bounds = (bound_min * 4, bound_min * 4)
3127 with self.assertRaises(DecodeError) as err:
3129 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3131 decode_path=decode_path,
3134 self.assertEqual(err.exception.offset, offset)
3135 self.assertEqual(err.exception.decode_path, decode_path)
3137 @given(data_strategy())
3138 def test_symmetric(self, d):
3139 values = d.draw(string_values_strategy(self.text_alphabet()))
3140 value = d.draw(text(alphabet=self.text_alphabet()))
3141 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3142 offset = d.draw(integers(min_value=0))
3143 tail_junk = d.draw(binary(max_size=5))
3144 _, _, _, _, default, optional, _decoded = values
3145 obj = self.base_klass(
3153 self.assertFalse(obj.expled)
3154 obj_encoded = obj.encode()
3155 obj_expled = obj(value, expl=tag_expl)
3156 self.assertTrue(obj_expled.expled)
3159 obj_expled_encoded = obj_expled.encode()
3160 obj_decoded, tail = obj_expled.decode(
3161 obj_expled_encoded + tail_junk,
3166 self.assertEqual(tail, tail_junk)
3167 self.assertEqual(obj_decoded, obj_expled)
3168 self.assertNotEqual(obj_decoded, obj)
3169 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3170 self.assertEqual(bytes(obj_decoded), bytes(obj))
3171 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3172 self.assertEqual(text_type(obj_decoded), text_type(obj))
3173 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3174 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3175 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3177 obj_decoded.expl_llen,
3178 len(len_encode(len(obj_encoded))),
3180 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3181 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3184 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3186 self.assertEqual(obj_decoded.expl_offset, offset)
3189 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3190 base_klass = UTF8String
3193 class UnicodeDecodeErrorMixin(object):
3195 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3199 def test_unicode_decode_error(self, cyrillic_text):
3200 with self.assertRaises(DecodeError):
3201 self.base_klass(cyrillic_text)
3204 class TestNumericString(StringMixin, CommonMixin, TestCase):
3205 base_klass = NumericString
3207 def text_alphabet(self):
3210 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3211 def test_non_numeric(self, cyrillic_text):
3212 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3213 self.base_klass(cyrillic_text)
3216 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3217 integers(min_value=0),
3220 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3221 value, bound_min = list(sorted(ints))
3223 class String(self.base_klass):
3224 bounds = (bound_min, bound_min)
3225 with self.assertRaises(DecodeError) as err:
3227 self.base_klass(b"1" * value).encode(),
3229 decode_path=decode_path,
3232 self.assertEqual(err.exception.offset, offset)
3233 self.assertEqual(err.exception.decode_path, decode_path)
3236 class TestPrintableString(
3237 UnicodeDecodeErrorMixin,
3242 base_klass = PrintableString
3245 class TestTeletexString(
3246 UnicodeDecodeErrorMixin,
3251 base_klass = TeletexString
3254 class TestVideotexString(
3255 UnicodeDecodeErrorMixin,
3260 base_klass = VideotexString
3263 class TestIA5String(
3264 UnicodeDecodeErrorMixin,
3269 base_klass = IA5String
3272 class TestGraphicString(
3273 UnicodeDecodeErrorMixin,
3278 base_klass = GraphicString
3281 class TestVisibleString(
3282 UnicodeDecodeErrorMixin,
3287 base_klass = VisibleString
3289 def test_x690_vector(self):
3290 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3291 self.assertSequenceEqual(tail, b"")
3292 self.assertEqual(str(obj), "Jones")
3293 self.assertFalse(obj.bered)
3294 self.assertFalse(obj.lenindef)
3296 obj, tail = VisibleString().decode(
3297 hexdec("3A0904034A6F6E04026573"),
3298 ctx={"bered": True},
3300 self.assertSequenceEqual(tail, b"")
3301 self.assertEqual(str(obj), "Jones")
3302 self.assertTrue(obj.bered)
3303 self.assertFalse(obj.lenindef)
3305 obj, tail = VisibleString().decode(
3306 hexdec("3A8004034A6F6E040265730000"),
3307 ctx={"bered": True},
3309 self.assertSequenceEqual(tail, b"")
3310 self.assertEqual(str(obj), "Jones")
3311 self.assertTrue(obj.bered)
3312 self.assertTrue(obj.lenindef)
3315 class TestGeneralString(
3316 UnicodeDecodeErrorMixin,
3321 base_klass = GeneralString
3324 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3325 base_klass = UniversalString
3328 class TestBMPString(StringMixin, CommonMixin, TestCase):
3329 base_klass = BMPString
3333 def generalized_time_values_strategy(
3341 if draw(booleans()):
3342 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3344 value = value.replace(microsecond=0)
3346 if draw(booleans()):
3347 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3349 default = default.replace(microsecond=0)
3353 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3355 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3356 optional = draw(one_of(none(), booleans()))
3358 draw(integers(min_value=0)),
3359 draw(integers(min_value=0)),
3360 draw(integers(min_value=0)),
3362 return (value, impl, expl, default, optional, _decoded)
3365 class TimeMixin(object):
3366 def test_invalid_value_type(self):
3367 with self.assertRaises(InvalidValueType) as err:
3368 self.base_klass(datetime.now().timetuple())
3371 @given(data_strategy())
3372 def test_optional(self, d):
3373 default = d.draw(datetimes(
3374 min_value=self.min_datetime,
3375 max_value=self.max_datetime,
3377 optional = d.draw(booleans())
3378 obj = self.base_klass(default=default, optional=optional)
3379 self.assertTrue(obj.optional)
3381 @given(data_strategy())
3382 def test_ready(self, d):
3383 obj = self.base_klass()
3384 self.assertFalse(obj.ready)
3387 with self.assertRaises(ObjNotReady) as err:
3390 value = d.draw(datetimes(min_value=self.min_datetime))
3391 obj = self.base_klass(value)
3392 self.assertTrue(obj.ready)
3396 @given(data_strategy())
3397 def test_comparison(self, d):
3398 value1 = d.draw(datetimes(
3399 min_value=self.min_datetime,
3400 max_value=self.max_datetime,
3402 value2 = d.draw(datetimes(
3403 min_value=self.min_datetime,
3404 max_value=self.max_datetime,
3406 tag1 = d.draw(binary(min_size=1))
3407 tag2 = d.draw(binary(min_size=1))
3409 value1 = value1.replace(microsecond=0)
3410 value2 = value2.replace(microsecond=0)
3411 obj1 = self.base_klass(value1)
3412 obj2 = self.base_klass(value2)
3413 self.assertEqual(obj1 == obj2, value1 == value2)
3414 self.assertEqual(obj1 != obj2, value1 != value2)
3415 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3416 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3417 obj1 = self.base_klass(value1, impl=tag1)
3418 obj2 = self.base_klass(value1, impl=tag2)
3419 self.assertEqual(obj1 == obj2, tag1 == tag2)
3420 self.assertEqual(obj1 != obj2, tag1 != tag2)
3422 @given(data_strategy())
3423 def test_call(self, d):
3431 ) = d.draw(generalized_time_values_strategy(
3432 min_datetime=self.min_datetime,
3433 max_datetime=self.max_datetime,
3434 omit_ms=self.omit_ms,
3436 obj_initial = self.base_klass(
3437 value=value_initial,
3440 default=default_initial,
3441 optional=optional_initial or False,
3442 _decoded=_decoded_initial,
3451 ) = d.draw(generalized_time_values_strategy(
3452 min_datetime=self.min_datetime,
3453 max_datetime=self.max_datetime,
3454 omit_ms=self.omit_ms,
3455 do_expl=impl_initial is None,
3465 value_expected = default if value is None else value
3467 default_initial if value_expected is None
3470 self.assertEqual(obj, value_expected)
3471 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3472 self.assertEqual(obj.expl_tag, expl or expl_initial)
3475 default_initial if default is None else default,
3477 if obj.default is None:
3478 optional = optional_initial if optional is None else optional
3479 optional = False if optional is None else optional
3482 self.assertEqual(obj.optional, optional)
3484 @given(data_strategy())
3485 def test_copy(self, d):
3486 values = d.draw(generalized_time_values_strategy(
3487 min_datetime=self.min_datetime,
3488 max_datetime=self.max_datetime,
3490 obj = self.base_klass(*values)
3491 obj_copied = obj.copy()
3492 self.assert_copied_basic_fields(obj, obj_copied)
3493 self.assertEqual(obj._value, obj_copied._value)
3495 @given(data_strategy())
3496 def test_stripped(self, d):
3497 value = d.draw(datetimes(
3498 min_value=self.min_datetime,
3499 max_value=self.max_datetime,
3501 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3502 obj = self.base_klass(value, impl=tag_impl)
3503 with self.assertRaises(NotEnoughData):
3504 obj.decode(obj.encode()[:-1])
3506 @given(data_strategy())
3507 def test_stripped_expl(self, d):
3508 value = d.draw(datetimes(
3509 min_value=self.min_datetime,
3510 max_value=self.max_datetime,
3512 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3513 obj = self.base_klass(value, expl=tag_expl)
3514 with self.assertRaises(NotEnoughData):
3515 obj.decode(obj.encode()[:-1])
3517 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3518 @given(data_strategy())
3519 def test_symmetric(self, d):
3520 values = d.draw(generalized_time_values_strategy(
3521 min_datetime=self.min_datetime,
3522 max_datetime=self.max_datetime,
3524 value = d.draw(datetimes(
3525 min_value=self.min_datetime,
3526 max_value=self.max_datetime,
3528 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3529 offset = d.draw(integers(min_value=0))
3530 tail_junk = d.draw(binary(max_size=5))
3531 _, _, _, default, optional, _decoded = values
3532 obj = self.base_klass(
3540 self.assertFalse(obj.expled)
3541 obj_encoded = obj.encode()
3542 obj_expled = obj(value, expl=tag_expl)
3543 self.assertTrue(obj_expled.expled)
3546 obj_expled_encoded = obj_expled.encode()
3547 obj_decoded, tail = obj_expled.decode(
3548 obj_expled_encoded + tail_junk,
3553 self.assertEqual(tail, tail_junk)
3554 self.assertEqual(obj_decoded, obj_expled)
3555 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3556 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3557 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3558 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3559 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3561 obj_decoded.expl_llen,
3562 len(len_encode(len(obj_encoded))),
3564 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3565 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3568 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3570 self.assertEqual(obj_decoded.expl_offset, offset)
3573 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3574 base_klass = GeneralizedTime
3576 min_datetime = datetime(1900, 1, 1)
3577 max_datetime = datetime(9999, 12, 31)
3579 def test_go_vectors_invalid(self):
3591 b"-20100102030410Z",
3592 b"2010-0102030410Z",
3593 b"2010-0002030410Z",
3594 b"201001-02030410Z",
3595 b"20100102-030410Z",
3596 b"2010010203-0410Z",
3597 b"201001020304-10Z",
3598 # These ones are INVALID in *DER*, but accepted
3599 # by Go's encoding/asn1
3600 b"20100102030405+0607",
3601 b"20100102030405-0607",
3603 with self.assertRaises(DecodeError) as err:
3604 GeneralizedTime(data)
3607 def test_go_vectors_valid(self):
3609 GeneralizedTime(b"20100102030405Z").todatetime(),
3610 datetime(2010, 1, 2, 3, 4, 5, 0),
3614 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3615 base_klass = UTCTime
3617 min_datetime = datetime(2000, 1, 1)
3618 max_datetime = datetime(2049, 12, 31)
3620 def test_go_vectors_invalid(self):
3646 # These ones are INVALID in *DER*, but accepted
3647 # by Go's encoding/asn1
3648 b"910506164540-0700",
3649 b"910506164540+0730",
3653 with self.assertRaises(DecodeError) as err:
3657 def test_go_vectors_valid(self):
3659 UTCTime(b"910506234540Z").todatetime(),
3660 datetime(1991, 5, 6, 23, 45, 40, 0),
3663 @given(integers(min_value=0, max_value=49))
3664 def test_pre50(self, year):
3666 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3670 @given(integers(min_value=50, max_value=99))
3671 def test_post50(self, year):
3673 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3679 def any_values_strategy(draw, do_expl=False):
3680 value = draw(one_of(none(), binary()))
3683 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3684 optional = draw(one_of(none(), booleans()))
3686 draw(integers(min_value=0)),
3687 draw(integers(min_value=0)),
3688 draw(integers(min_value=0)),
3690 return (value, expl, optional, _decoded)
3693 class AnyInherited(Any):
3697 class TestAny(CommonMixin, TestCase):
3700 def test_invalid_value_type(self):
3701 with self.assertRaises(InvalidValueType) as err:
3706 def test_optional(self, optional):
3707 obj = Any(optional=optional)
3708 self.assertEqual(obj.optional, optional)
3711 def test_ready(self, value):
3713 self.assertFalse(obj.ready)
3716 with self.assertRaises(ObjNotReady) as err:
3720 self.assertTrue(obj.ready)
3725 def test_basic(self, value):
3726 integer_encoded = Integer(value).encode()
3728 Any(integer_encoded),
3729 Any(Integer(value)),
3730 Any(Any(Integer(value))),
3732 self.assertSequenceEqual(bytes(obj), integer_encoded)
3734 obj.decode(obj.encode())[0].vlen,
3735 len(integer_encoded),
3739 self.assertSequenceEqual(obj.encode(), integer_encoded)
3741 @given(binary(), binary())
3742 def test_comparison(self, value1, value2):
3743 for klass in (Any, AnyInherited):
3744 obj1 = klass(value1)
3745 obj2 = klass(value2)
3746 self.assertEqual(obj1 == obj2, value1 == value2)
3747 self.assertEqual(obj1 != obj2, value1 != value2)
3748 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3750 @given(data_strategy())
3751 def test_call(self, d):
3752 for klass in (Any, AnyInherited):
3758 ) = d.draw(any_values_strategy())
3759 obj_initial = klass(
3762 optional_initial or False,
3770 ) = d.draw(any_values_strategy(do_expl=True))
3771 obj = obj_initial(value, expl, optional)
3773 value_expected = None if value is None else value
3774 self.assertEqual(obj, value_expected)
3775 self.assertEqual(obj.expl_tag, expl or expl_initial)
3776 if obj.default is None:
3777 optional = optional_initial if optional is None else optional
3778 optional = False if optional is None else optional
3779 self.assertEqual(obj.optional, optional)
3781 def test_simultaneous_impl_expl(self):
3782 # override it, as Any does not have implicit tag
3785 def test_decoded(self):
3786 # override it, as Any does not have implicit tag
3789 @given(any_values_strategy())
3790 def test_copy(self, values):
3791 for klass in (Any, AnyInherited):
3792 obj = klass(*values)
3793 obj_copied = obj.copy()
3794 self.assert_copied_basic_fields(obj, obj_copied)
3795 self.assertEqual(obj._value, obj_copied._value)
3797 @given(binary().map(OctetString))
3798 def test_stripped(self, value):
3800 with self.assertRaises(NotEnoughData):
3801 obj.decode(obj.encode()[:-1])
3805 integers(min_value=1).map(tag_ctxc),
3807 def test_stripped_expl(self, value, tag_expl):
3808 obj = Any(value, expl=tag_expl)
3809 with self.assertRaises(NotEnoughData):
3810 obj.decode(obj.encode()[:-1])
3813 integers(min_value=31),
3814 integers(min_value=0),
3817 def test_bad_tag(self, tag, offset, decode_path):
3818 with self.assertRaises(DecodeError) as err:
3820 tag_encode(tag)[:-1],
3822 decode_path=decode_path,
3825 self.assertEqual(err.exception.offset, offset)
3826 self.assertEqual(err.exception.decode_path, decode_path)
3829 integers(min_value=128),
3830 integers(min_value=0),
3833 def test_bad_len(self, l, offset, decode_path):
3834 with self.assertRaises(DecodeError) as err:
3836 Any.tag_default + len_encode(l)[:-1],
3838 decode_path=decode_path,
3841 self.assertEqual(err.exception.offset, offset)
3842 self.assertEqual(err.exception.decode_path, decode_path)
3844 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3846 any_values_strategy(),
3847 integers().map(lambda x: Integer(x).encode()),
3848 integers(min_value=1).map(tag_ctxc),
3849 integers(min_value=0),
3852 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3853 for klass in (Any, AnyInherited):
3854 _, _, optional, _decoded = values
3855 obj = klass(value=value, optional=optional, _decoded=_decoded)
3858 self.assertFalse(obj.expled)
3859 obj_encoded = obj.encode()
3860 obj_expled = obj(value, expl=tag_expl)
3861 self.assertTrue(obj_expled.expled)
3864 obj_expled_encoded = obj_expled.encode()
3865 obj_decoded, tail = obj_expled.decode(
3866 obj_expled_encoded + tail_junk,
3871 self.assertEqual(tail, tail_junk)
3872 self.assertEqual(obj_decoded, obj_expled)
3873 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3874 self.assertEqual(bytes(obj_decoded), bytes(obj))
3875 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3876 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3877 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3879 obj_decoded.expl_llen,
3880 len(len_encode(len(obj_encoded))),
3882 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3883 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3886 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3888 self.assertEqual(obj_decoded.expl_offset, offset)
3889 self.assertEqual(obj_decoded.tlen, 0)
3890 self.assertEqual(obj_decoded.llen, 0)
3891 self.assertEqual(obj_decoded.vlen, len(value))
3894 integers(min_value=1).map(tag_ctxc),
3895 integers(min_value=0, max_value=3),
3896 integers(min_value=0),
3900 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
3901 chunk = Boolean(False, expl=expl).encode()
3903 OctetString.tag_default +
3905 b"".join([chunk] * chunks) +
3908 obj, tail = Any().decode(
3911 decode_path=decode_path,
3912 ctx={"bered": True},
3914 self.assertSequenceEqual(tail, junk)
3915 self.assertEqual(obj.offset, offset)
3916 self.assertEqual(obj.tlvlen, len(encoded))
3917 with self.assertRaises(NotEnoughData) as err:
3921 decode_path=decode_path,
3922 ctx={"bered": True},
3924 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
3925 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
3929 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3931 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3932 tags = [tag_encode(tag) for tag in draw(sets(
3933 integers(min_value=0),
3934 min_size=len(names),
3935 max_size=len(names),
3937 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3939 if value_required or draw(booleans()):
3940 value = draw(tuples(
3941 sampled_from([name for name, _ in schema]),
3942 integers().map(Integer),
3946 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3947 default = draw(one_of(
3949 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3951 optional = draw(one_of(none(), booleans()))
3953 draw(integers(min_value=0)),
3954 draw(integers(min_value=0)),
3955 draw(integers(min_value=0)),
3957 return (schema, value, expl, default, optional, _decoded)
3960 class ChoiceInherited(Choice):
3964 class TestChoice(CommonMixin, TestCase):
3966 schema = (("whatever", Boolean()),)
3969 def test_schema_required(self):
3970 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3973 def test_impl_forbidden(self):
3974 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3975 Choice(impl=b"whatever")
3977 def test_invalid_value_type(self):
3978 with self.assertRaises(InvalidValueType) as err:
3979 self.base_klass(123)
3981 with self.assertRaises(ObjUnknown) as err:
3982 self.base_klass(("whenever", Boolean(False)))
3984 with self.assertRaises(InvalidValueType) as err:
3985 self.base_klass(("whatever", Integer(123)))
3989 def test_optional(self, optional):
3990 obj = self.base_klass(
3991 default=self.base_klass(("whatever", Boolean(False))),
3994 self.assertTrue(obj.optional)
3997 def test_ready(self, value):
3998 obj = self.base_klass()
3999 self.assertFalse(obj.ready)
4002 self.assertIsNone(obj["whatever"])
4003 with self.assertRaises(ObjNotReady) as err:
4006 obj["whatever"] = Boolean()
4007 self.assertFalse(obj.ready)
4010 obj["whatever"] = Boolean(value)
4011 self.assertTrue(obj.ready)
4015 @given(booleans(), booleans())
4016 def test_comparison(self, value1, value2):
4017 class WahlInherited(self.base_klass):
4019 for klass in (self.base_klass, WahlInherited):
4020 obj1 = klass(("whatever", Boolean(value1)))
4021 obj2 = klass(("whatever", Boolean(value2)))
4022 self.assertEqual(obj1 == obj2, value1 == value2)
4023 self.assertEqual(obj1 != obj2, value1 != value2)
4024 self.assertEqual(obj1 == obj2._value, value1 == value2)
4025 self.assertFalse(obj1 == obj2._value[1])
4027 @given(data_strategy())
4028 def test_call(self, d):
4029 for klass in (Choice, ChoiceInherited):
4037 ) = d.draw(choice_values_strategy())
4040 schema = schema_initial
4042 value=value_initial,
4044 default=default_initial,
4045 optional=optional_initial or False,
4046 _decoded=_decoded_initial,
4055 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4056 obj = obj_initial(value, expl, default, optional)
4058 value_expected = default if value is None else value
4060 default_initial if value_expected is None
4063 self.assertEqual(obj.choice, value_expected[0])
4064 self.assertEqual(obj.value, int(value_expected[1]))
4065 self.assertEqual(obj.expl_tag, expl or expl_initial)
4066 default_expect = default_initial if default is None else default
4067 if default_expect is not None:
4068 self.assertEqual(obj.default.choice, default_expect[0])
4069 self.assertEqual(obj.default.value, int(default_expect[1]))
4070 if obj.default is None:
4071 optional = optional_initial if optional is None else optional
4072 optional = False if optional is None else optional
4075 self.assertEqual(obj.optional, optional)
4076 self.assertEqual(obj.specs, obj_initial.specs)
4078 def test_simultaneous_impl_expl(self):
4079 # override it, as Any does not have implicit tag
4082 def test_decoded(self):
4083 # override it, as Any does not have implicit tag
4086 @given(choice_values_strategy())
4087 def test_copy(self, values):
4088 _schema, value, expl, default, optional, _decoded = values
4090 class Wahl(self.base_klass):
4096 optional=optional or False,
4099 obj_copied = obj.copy()
4100 self.assertIsNone(obj.tag)
4101 self.assertIsNone(obj_copied.tag)
4102 # hack for assert_copied_basic_fields
4103 obj.tag = "whatever"
4104 obj_copied.tag = "whatever"
4105 self.assert_copied_basic_fields(obj, obj_copied)
4106 self.assertEqual(obj._value, obj_copied._value)
4107 self.assertEqual(obj.specs, obj_copied.specs)
4110 def test_stripped(self, value):
4111 obj = self.base_klass(("whatever", Boolean(value)))
4112 with self.assertRaises(NotEnoughData):
4113 obj.decode(obj.encode()[:-1])
4117 integers(min_value=1).map(tag_ctxc),
4119 def test_stripped_expl(self, value, tag_expl):
4120 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4121 with self.assertRaises(NotEnoughData):
4122 obj.decode(obj.encode()[:-1])
4124 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4125 @given(data_strategy())
4126 def test_symmetric(self, d):
4127 _schema, value, _, default, optional, _decoded = d.draw(
4128 choice_values_strategy(value_required=True)
4130 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4131 offset = d.draw(integers(min_value=0))
4132 tail_junk = d.draw(binary(max_size=5))
4134 class Wahl(self.base_klass):
4144 self.assertFalse(obj.expled)
4145 obj_encoded = obj.encode()
4146 obj_expled = obj(value, expl=tag_expl)
4147 self.assertTrue(obj_expled.expled)
4150 obj_expled_encoded = obj_expled.encode()
4151 obj_decoded, tail = obj_expled.decode(
4152 obj_expled_encoded + tail_junk,
4157 self.assertEqual(tail, tail_junk)
4158 self.assertEqual(obj_decoded, obj_expled)
4159 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4160 self.assertEqual(obj_decoded.value, obj_expled.value)
4161 self.assertEqual(obj_decoded.choice, obj.choice)
4162 self.assertEqual(obj_decoded.value, obj.value)
4163 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4164 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4165 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4167 obj_decoded.expl_llen,
4168 len(len_encode(len(obj_encoded))),
4170 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4171 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4174 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4176 self.assertEqual(obj_decoded.expl_offset, offset)
4177 self.assertSequenceEqual(
4179 obj_decoded.value.offset - offset:
4180 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
4186 def test_set_get(self, value):
4189 ("erste", Boolean()),
4190 ("zweite", Integer()),
4193 with self.assertRaises(ObjUnknown) as err:
4194 obj["whatever"] = "whenever"
4195 with self.assertRaises(InvalidValueType) as err:
4196 obj["zweite"] = Boolean(False)
4197 obj["zweite"] = Integer(value)
4199 with self.assertRaises(ObjUnknown) as err:
4202 self.assertIsNone(obj["erste"])
4203 self.assertEqual(obj["zweite"], Integer(value))
4205 def test_tag_mismatch(self):
4208 ("erste", Boolean()),
4210 int_encoded = Integer(123).encode()
4211 bool_encoded = Boolean(False).encode()
4213 obj.decode(bool_encoded)
4214 with self.assertRaises(TagMismatch):
4215 obj.decode(int_encoded)
4217 def test_tag_mismatch_underlying(self):
4218 class SeqOfBoolean(SequenceOf):
4221 class SeqOfInteger(SequenceOf):
4226 ("erste", SeqOfBoolean()),
4229 int_encoded = SeqOfInteger((Integer(123),)).encode()
4230 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4232 obj.decode(bool_encoded)
4233 with self.assertRaises(TagMismatch) as err:
4234 obj.decode(int_encoded)
4235 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4239 def seq_values_strategy(draw, seq_klass, do_expl=False):
4241 if draw(booleans()):
4244 k: v for k, v in draw(dictionaries(
4247 booleans().map(Boolean),
4248 integers().map(Integer),
4253 if draw(booleans()):
4254 schema = list(draw(dictionaries(
4257 booleans().map(Boolean),
4258 integers().map(Integer),
4264 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4266 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4268 if draw(booleans()):
4269 default = seq_klass()
4271 k: v for k, v in draw(dictionaries(
4274 booleans().map(Boolean),
4275 integers().map(Integer),
4279 optional = draw(one_of(none(), booleans()))
4281 draw(integers(min_value=0)),
4282 draw(integers(min_value=0)),
4283 draw(integers(min_value=0)),
4285 return (value, schema, impl, expl, default, optional, _decoded)
4289 def sequence_strategy(draw, seq_klass):
4290 inputs = draw(lists(
4292 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4293 tuples(just(Integer), integers(), one_of(none(), integers())),
4298 integers(min_value=1),
4299 min_size=len(inputs),
4300 max_size=len(inputs),
4303 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4304 for tag, expled in zip(tags, draw(lists(
4306 min_size=len(inputs),
4307 max_size=len(inputs),
4311 for i, optional in enumerate(draw(lists(
4312 sampled_from(("required", "optional", "empty")),
4313 min_size=len(inputs),
4314 max_size=len(inputs),
4316 if optional in ("optional", "empty"):
4317 inits[i]["optional"] = True
4318 if optional == "empty":
4320 empties = set(empties)
4321 names = list(draw(sets(
4323 min_size=len(inputs),
4324 max_size=len(inputs),
4327 for i, (klass, value, default) in enumerate(inputs):
4328 schema.append((names[i], klass(default=default, **inits[i])))
4329 seq_name = draw(text_letters())
4330 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4333 for i, (klass, value, default) in enumerate(inputs):
4340 "default_value": None if spec.default is None else default,
4344 expect["optional"] = True
4346 expect["presented"] = True
4347 expect["value"] = value
4349 expect["optional"] = True
4350 if default is not None and default == value:
4351 expect["presented"] = False
4352 seq[name] = klass(value)
4353 expects.append(expect)
4358 def sequences_strategy(draw, seq_klass):
4359 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4361 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4362 for tag, expled in zip(tags, draw(lists(
4369 i for i, is_default in enumerate(draw(lists(
4375 names = list(draw(sets(
4380 seq_expectses = draw(lists(
4381 sequence_strategy(seq_klass=seq_klass),
4385 seqs = [seq for seq, _ in seq_expectses]
4387 for i, (name, seq) in enumerate(zip(names, seqs)):
4390 seq(default=(seq if i in defaulted else None), **inits[i]),
4392 seq_name = draw(text_letters())
4393 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4396 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4399 "expects": expects_inner,
4402 seq_outer[name] = seq_inner
4403 if seq_outer.specs[name].default is None:
4404 expect["presented"] = True
4405 expect_outers.append(expect)
4406 return seq_outer, expect_outers
4409 class SeqMixing(object):
4410 def test_invalid_value_type(self):
4411 with self.assertRaises(InvalidValueType) as err:
4412 self.base_klass(123)
4415 def test_invalid_value_type_set(self):
4416 class Seq(self.base_klass):
4417 schema = (("whatever", Boolean()),)
4419 with self.assertRaises(InvalidValueType) as err:
4420 seq["whatever"] = Integer(123)
4424 def test_optional(self, optional):
4425 obj = self.base_klass(default=self.base_klass(), optional=optional)
4426 self.assertTrue(obj.optional)
4428 @given(data_strategy())
4429 def test_ready(self, d):
4431 str(i): v for i, v in enumerate(d.draw(lists(
4438 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4445 for name in d.draw(permutations(
4446 list(ready.keys()) + list(non_ready.keys()),
4448 schema_input.append((name, Boolean()))
4450 class Seq(self.base_klass):
4451 schema = tuple(schema_input)
4453 for name in ready.keys():
4455 seq[name] = Boolean()
4456 self.assertFalse(seq.ready)
4459 for name, value in ready.items():
4460 seq[name] = Boolean(value)
4461 self.assertFalse(seq.ready)
4464 with self.assertRaises(ObjNotReady) as err:
4467 for name, value in non_ready.items():
4468 seq[name] = Boolean(value)
4469 self.assertTrue(seq.ready)
4473 @given(data_strategy())
4474 def test_call(self, d):
4475 class SeqInherited(self.base_klass):
4477 for klass in (self.base_klass, SeqInherited):
4486 ) = d.draw(seq_values_strategy(seq_klass=klass))
4487 obj_initial = klass(
4493 optional_initial or False,
4504 ) = d.draw(seq_values_strategy(
4506 do_expl=impl_initial is None,
4508 obj = obj_initial(value, impl, expl, default, optional)
4509 value_expected = default if value is None else value
4511 default_initial if value_expected is None
4514 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4515 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4516 self.assertEqual(obj.expl_tag, expl or expl_initial)
4518 {} if obj.default is None else obj.default._value,
4519 getattr(default_initial if default is None else default, "_value", {}),
4521 if obj.default is None:
4522 optional = optional_initial if optional is None else optional
4523 optional = False if optional is None else optional
4526 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4527 self.assertEqual(obj.optional, optional)
4529 @given(data_strategy())
4530 def test_copy(self, d):
4531 class SeqInherited(self.base_klass):
4533 for klass in (self.base_klass, SeqInherited):
4534 values = d.draw(seq_values_strategy(seq_klass=klass))
4535 obj = klass(*values)
4536 obj_copied = obj.copy()
4537 self.assert_copied_basic_fields(obj, obj_copied)
4538 self.assertEqual(obj.specs, obj_copied.specs)
4539 self.assertEqual(obj._value, obj_copied._value)
4541 @given(data_strategy())
4542 def test_stripped(self, d):
4543 value = d.draw(integers())
4544 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4546 class Seq(self.base_klass):
4548 schema = (("whatever", Integer()),)
4550 seq["whatever"] = Integer(value)
4551 with self.assertRaises(NotEnoughData):
4552 seq.decode(seq.encode()[:-1])
4554 @given(data_strategy())
4555 def test_stripped_expl(self, d):
4556 value = d.draw(integers())
4557 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4559 class Seq(self.base_klass):
4561 schema = (("whatever", Integer()),)
4563 seq["whatever"] = Integer(value)
4564 with self.assertRaises(NotEnoughData):
4565 seq.decode(seq.encode()[:-1])
4567 @given(binary(min_size=2))
4568 def test_non_tag_mismatch_raised(self, junk):
4570 _, _, len_encoded = tag_strip(memoryview(junk))
4571 len_decode(len_encoded)
4577 class Seq(self.base_klass):
4579 ("whatever", Integer()),
4581 ("whenever", Integer()),
4584 seq["whatever"] = Integer(123)
4585 seq["junk"] = Any(junk)
4586 seq["whenever"] = Integer(123)
4587 with self.assertRaises(DecodeError):
4588 seq.decode(seq.encode())
4591 integers(min_value=31),
4592 integers(min_value=0),
4595 def test_bad_tag(self, tag, offset, decode_path):
4596 with self.assertRaises(DecodeError) as err:
4597 self.base_klass().decode(
4598 tag_encode(tag)[:-1],
4600 decode_path=decode_path,
4603 self.assertEqual(err.exception.offset, offset)
4604 self.assertEqual(err.exception.decode_path, decode_path)
4607 integers(min_value=128),
4608 integers(min_value=0),
4611 def test_bad_len(self, l, offset, decode_path):
4612 with self.assertRaises(DecodeError) as err:
4613 self.base_klass().decode(
4614 self.base_klass.tag_default + len_encode(l)[:-1],
4616 decode_path=decode_path,
4619 self.assertEqual(err.exception.offset, offset)
4620 self.assertEqual(err.exception.decode_path, decode_path)
4622 def _assert_expects(self, seq, expects):
4623 for expect in expects:
4625 seq.specs[expect["name"]].optional,
4628 if expect["default_value"] is not None:
4630 seq.specs[expect["name"]].default,
4631 expect["default_value"],
4633 if expect["presented"]:
4634 self.assertIn(expect["name"], seq)
4635 self.assertEqual(seq[expect["name"]], expect["value"])
4637 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4638 @given(data_strategy())
4639 def test_symmetric(self, d):
4640 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4641 tail_junk = d.draw(binary(max_size=5))
4642 self.assertTrue(seq.ready)
4643 self.assertFalse(seq.decoded)
4644 self._assert_expects(seq, expects)
4647 self.assertTrue(seq.ready)
4648 seq_encoded = seq.encode()
4649 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4650 self.assertFalse(seq_decoded.lenindef)
4652 t, _, lv = tag_strip(seq_encoded)
4653 _, _, v = len_decode(lv)
4654 seq_encoded_lenindef = t + LENINDEF + v + EOC
4655 seq_decoded_lenindef, tail_lenindef = seq.decode(
4656 seq_encoded_lenindef + tail_junk,
4657 ctx={"bered": True},
4659 self.assertTrue(seq_decoded_lenindef.lenindef)
4660 with self.assertRaises(DecodeError):
4661 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4662 with self.assertRaises(DecodeError):
4663 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4664 repr(seq_decoded_lenindef)
4665 pprint(seq_decoded_lenindef)
4666 self.assertTrue(seq_decoded_lenindef.ready)
4668 for decoded, decoded_tail, encoded in (
4669 (seq_decoded, tail, seq_encoded),
4670 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4672 self.assertEqual(decoded_tail, tail_junk)
4673 self._assert_expects(decoded, expects)
4674 self.assertEqual(seq, decoded)
4675 self.assertEqual(decoded.encode(), seq_encoded)
4676 self.assertEqual(decoded.tlvlen, len(encoded))
4677 for expect in expects:
4678 if not expect["presented"]:
4679 self.assertNotIn(expect["name"], decoded)
4681 self.assertIn(expect["name"], decoded)
4682 obj = decoded[expect["name"]]
4683 self.assertTrue(obj.decoded)
4684 offset = obj.expl_offset if obj.expled else obj.offset
4685 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4686 self.assertSequenceEqual(
4687 seq_encoded[offset:offset + tlvlen],
4691 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4692 @given(data_strategy())
4693 def test_symmetric_with_seq(self, d):
4694 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4695 self.assertTrue(seq.ready)
4696 seq_encoded = seq.encode()
4697 seq_decoded, tail = seq.decode(seq_encoded)
4698 self.assertEqual(tail, b"")
4699 self.assertTrue(seq.ready)
4700 self.assertEqual(seq, seq_decoded)
4701 self.assertEqual(seq_decoded.encode(), seq_encoded)
4702 for expect_outer in expect_outers:
4703 if not expect_outer["presented"]:
4704 self.assertNotIn(expect_outer["name"], seq_decoded)
4706 self.assertIn(expect_outer["name"], seq_decoded)
4707 obj = seq_decoded[expect_outer["name"]]
4708 self.assertTrue(obj.decoded)
4709 offset = obj.expl_offset if obj.expled else obj.offset
4710 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4711 self.assertSequenceEqual(
4712 seq_encoded[offset:offset + tlvlen],
4715 self._assert_expects(obj, expect_outer["expects"])
4717 @given(data_strategy())
4718 def test_default_disappears(self, d):
4719 _schema = list(d.draw(dictionaries(
4721 sets(integers(), min_size=2, max_size=2),
4725 class Seq(self.base_klass):
4727 (n, Integer(default=d))
4728 for n, (_, d) in _schema
4731 for name, (value, _) in _schema:
4732 seq[name] = Integer(value)
4733 self.assertEqual(len(seq._value), len(_schema))
4734 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4735 self.assertGreater(len(seq.encode()), len(empty_seq))
4736 for name, (_, default) in _schema:
4737 seq[name] = Integer(default)
4738 self.assertEqual(len(seq._value), 0)
4739 self.assertSequenceEqual(seq.encode(), empty_seq)
4741 @given(data_strategy())
4742 def test_encoded_default_accepted(self, d):
4743 _schema = list(d.draw(dictionaries(
4748 tags = [tag_encode(tag) for tag in d.draw(sets(
4749 integers(min_value=0),
4750 min_size=len(_schema),
4751 max_size=len(_schema),
4754 class SeqWithoutDefault(self.base_klass):
4756 (n, Integer(impl=t))
4757 for (n, _), t in zip(_schema, tags)
4759 seq_without_default = SeqWithoutDefault()
4760 for name, value in _schema:
4761 seq_without_default[name] = Integer(value)
4762 seq_encoded = seq_without_default.encode()
4764 class SeqWithDefault(self.base_klass):
4766 (n, Integer(default=v, impl=t))
4767 for (n, v), t in zip(_schema, tags)
4769 seq_with_default = SeqWithDefault()
4770 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4771 for name, value in _schema:
4772 self.assertEqual(seq_decoded[name], seq_with_default[name])
4773 self.assertEqual(seq_decoded[name], value)
4775 @given(data_strategy())
4776 def test_missing_from_spec(self, d):
4777 names = list(d.draw(sets(text_letters(), min_size=2)))
4778 tags = [tag_encode(tag) for tag in d.draw(sets(
4779 integers(min_value=0),
4780 min_size=len(names),
4781 max_size=len(names),
4783 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4785 class SeqFull(self.base_klass):
4786 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4787 seq_full = SeqFull()
4788 for i, name in enumerate(names):
4789 seq_full[name] = Integer(i)
4790 seq_encoded = seq_full.encode()
4791 altered = names_tags[:-2] + names_tags[-1:]
4793 class SeqMissing(self.base_klass):
4794 schema = [(n, Integer(impl=t)) for n, t in altered]
4795 seq_missing = SeqMissing()
4796 with self.assertRaises(TagMismatch):
4797 seq_missing.decode(seq_encoded)
4800 class TestSequence(SeqMixing, CommonMixin, TestCase):
4801 base_klass = Sequence
4807 def test_remaining(self, value, junk):
4808 class Seq(Sequence):
4810 ("whatever", Integer()),
4812 int_encoded = Integer(value).encode()
4814 Sequence.tag_default,
4815 len_encode(len(int_encoded + junk)),
4818 with assertRaisesRegex(self, DecodeError, "remaining"):
4819 Seq().decode(junked)
4821 @given(sets(text_letters(), min_size=2))
4822 def test_obj_unknown(self, names):
4823 missing = names.pop()
4825 class Seq(Sequence):
4826 schema = [(n, Boolean()) for n in names]
4828 with self.assertRaises(ObjUnknown) as err:
4831 with self.assertRaises(ObjUnknown) as err:
4832 seq[missing] = Boolean()
4835 def test_x690_vector(self):
4836 class Seq(Sequence):
4838 ("name", IA5String()),
4841 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4842 self.assertEqual(seq["name"], "Smith")
4843 self.assertEqual(seq["ok"], True)
4846 class TestSet(SeqMixing, CommonMixin, TestCase):
4849 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4850 @given(data_strategy())
4851 def test_sorted(self, d):
4853 tag_encode(tag) for tag in
4854 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4858 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4860 for name, _ in Seq.schema:
4861 seq[name] = OctetString(b"")
4862 seq_encoded = seq.encode()
4863 seq_decoded, _ = seq.decode(seq_encoded)
4864 self.assertSequenceEqual(
4865 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4866 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4871 def seqof_values_strategy(draw, schema=None, do_expl=False):
4873 schema = draw(sampled_from((Boolean(), Integer())))
4874 bound_min, bound_max = sorted(draw(sets(
4875 integers(min_value=0, max_value=10),
4879 if isinstance(schema, Boolean):
4880 values_generator = booleans().map(Boolean)
4881 elif isinstance(schema, Integer):
4882 values_generator = integers().map(Integer)
4883 values_generator = lists(
4888 values = draw(one_of(none(), values_generator))
4892 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4894 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4895 default = draw(one_of(none(), values_generator))
4896 optional = draw(one_of(none(), booleans()))
4898 draw(integers(min_value=0)),
4899 draw(integers(min_value=0)),
4900 draw(integers(min_value=0)),
4905 (bound_min, bound_max),
4914 class SeqOfMixing(object):
4915 def test_invalid_value_type(self):
4916 with self.assertRaises(InvalidValueType) as err:
4917 self.base_klass(123)
4920 def test_invalid_values_type(self):
4921 class SeqOf(self.base_klass):
4923 with self.assertRaises(InvalidValueType) as err:
4924 SeqOf([Integer(123), Boolean(False), Integer(234)])
4927 def test_schema_required(self):
4928 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4929 self.base_klass.__mro__[1]()
4931 @given(booleans(), booleans(), binary(), binary())
4932 def test_comparison(self, value1, value2, tag1, tag2):
4933 class SeqOf(self.base_klass):
4935 obj1 = SeqOf([Boolean(value1)])
4936 obj2 = SeqOf([Boolean(value2)])
4937 self.assertEqual(obj1 == obj2, value1 == value2)
4938 self.assertEqual(obj1 != obj2, value1 != value2)
4939 self.assertEqual(obj1 == list(obj2), value1 == value2)
4940 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4941 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4942 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4943 self.assertEqual(obj1 == obj2, tag1 == tag2)
4944 self.assertEqual(obj1 != obj2, tag1 != tag2)
4946 @given(lists(booleans()))
4947 def test_iter(self, values):
4948 class SeqOf(self.base_klass):
4950 obj = SeqOf([Boolean(value) for value in values])
4951 self.assertEqual(len(obj), len(values))
4952 for i, value in enumerate(obj):
4953 self.assertEqual(value, values[i])
4955 @given(data_strategy())
4956 def test_ready(self, d):
4957 ready = [Integer(v) for v in d.draw(lists(
4964 range(d.draw(integers(min_value=1, max_value=5)))
4967 class SeqOf(self.base_klass):
4969 values = d.draw(permutations(ready + non_ready))
4971 for value in values:
4973 self.assertFalse(seqof.ready)
4976 with self.assertRaises(ObjNotReady) as err:
4979 for i, value in enumerate(values):
4980 self.assertEqual(seqof[i], value)
4981 if not seqof[i].ready:
4982 seqof[i] = Integer(i)
4983 self.assertTrue(seqof.ready)
4987 def test_spec_mismatch(self):
4988 class SeqOf(self.base_klass):
4991 seqof.append(Integer(123))
4992 with self.assertRaises(ValueError):
4993 seqof.append(Boolean(False))
4994 with self.assertRaises(ValueError):
4995 seqof[0] = Boolean(False)
4997 @given(data_strategy())
4998 def test_bounds_satisfied(self, d):
4999 class SeqOf(self.base_klass):
5001 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5002 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5003 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5004 SeqOf(value=value, bounds=(bound_min, bound_max))
5006 @given(data_strategy())
5007 def test_bounds_unsatisfied(self, d):
5008 class SeqOf(self.base_klass):
5010 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5011 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5012 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
5013 with self.assertRaises(BoundsError) as err:
5014 SeqOf(value=value, bounds=(bound_min, bound_max))
5016 value = [Boolean()] * d.draw(integers(
5017 min_value=bound_max + 1,
5018 max_value=bound_max + 10,
5020 with self.assertRaises(BoundsError) as err:
5021 SeqOf(value=value, bounds=(bound_min, bound_max))
5024 @given(integers(min_value=1, max_value=10))
5025 def test_out_of_bounds(self, bound_max):
5026 class SeqOf(self.base_klass):
5028 bounds = (0, bound_max)
5030 for _ in range(bound_max):
5031 seqof.append(Integer(123))
5032 with self.assertRaises(BoundsError):
5033 seqof.append(Integer(123))
5035 @given(data_strategy())
5036 def test_call(self, d):
5046 ) = d.draw(seqof_values_strategy())
5048 class SeqOf(self.base_klass):
5049 schema = schema_initial
5050 obj_initial = SeqOf(
5051 value=value_initial,
5052 bounds=bounds_initial,
5055 default=default_initial,
5056 optional=optional_initial or False,
5057 _decoded=_decoded_initial,
5068 ) = d.draw(seqof_values_strategy(
5069 schema=schema_initial,
5070 do_expl=impl_initial is None,
5072 if (default is None) and (obj_initial.default is not None):
5075 (bounds is None) and
5076 (value is not None) and
5077 (bounds_initial is not None) and
5078 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5082 (bounds is None) and
5083 (default is not None) and
5084 (bounds_initial is not None) and
5085 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5097 value_expected = default if value is None else value
5099 default_initial if value_expected is None
5102 value_expected = () if value_expected is None else value_expected
5103 self.assertEqual(obj, value_expected)
5104 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5105 self.assertEqual(obj.expl_tag, expl or expl_initial)
5108 default_initial if default is None else default,
5110 if obj.default is None:
5111 optional = optional_initial if optional is None else optional
5112 optional = False if optional is None else optional
5115 self.assertEqual(obj.optional, optional)
5117 (obj._bound_min, obj._bound_max),
5118 bounds or bounds_initial or (0, float("+inf")),
5121 @given(seqof_values_strategy())
5122 def test_copy(self, values):
5123 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5125 class SeqOf(self.base_klass):
5133 optional=optional or False,
5136 obj_copied = obj.copy()
5137 self.assert_copied_basic_fields(obj, obj_copied)
5138 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5139 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5140 self.assertEqual(obj._value, obj_copied._value)
5144 integers(min_value=1).map(tag_encode),
5146 def test_stripped(self, values, tag_impl):
5147 class SeqOf(self.base_klass):
5148 schema = OctetString()
5149 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5150 with self.assertRaises(NotEnoughData):
5151 obj.decode(obj.encode()[:-1])
5155 integers(min_value=1).map(tag_ctxc),
5157 def test_stripped_expl(self, values, tag_expl):
5158 class SeqOf(self.base_klass):
5159 schema = OctetString()
5160 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5161 with self.assertRaises(NotEnoughData):
5162 obj.decode(obj.encode()[:-1])
5165 integers(min_value=31),
5166 integers(min_value=0),
5169 def test_bad_tag(self, tag, offset, decode_path):
5170 with self.assertRaises(DecodeError) as err:
5171 self.base_klass().decode(
5172 tag_encode(tag)[:-1],
5174 decode_path=decode_path,
5177 self.assertEqual(err.exception.offset, offset)
5178 self.assertEqual(err.exception.decode_path, decode_path)
5181 integers(min_value=128),
5182 integers(min_value=0),
5185 def test_bad_len(self, l, offset, decode_path):
5186 with self.assertRaises(DecodeError) as err:
5187 self.base_klass().decode(
5188 self.base_klass.tag_default + len_encode(l)[:-1],
5190 decode_path=decode_path,
5193 self.assertEqual(err.exception.offset, offset)
5194 self.assertEqual(err.exception.decode_path, decode_path)
5196 @given(binary(min_size=1))
5197 def test_tag_mismatch(self, impl):
5198 assume(impl != self.base_klass.tag_default)
5199 with self.assertRaises(TagMismatch):
5200 self.base_klass(impl=impl).decode(self.base_klass().encode())
5202 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5204 seqof_values_strategy(schema=Integer()),
5205 lists(integers().map(Integer)),
5206 integers(min_value=1).map(tag_ctxc),
5207 integers(min_value=0),
5210 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5211 _, _, _, _, _, default, optional, _decoded = values
5213 class SeqOf(self.base_klass):
5223 self.assertFalse(obj.expled)
5224 obj_encoded = obj.encode()
5225 obj_expled = obj(value, expl=tag_expl)
5226 self.assertTrue(obj_expled.expled)
5229 obj_expled_encoded = obj_expled.encode()
5230 obj_decoded, tail = obj_expled.decode(
5231 obj_expled_encoded + tail_junk,
5236 self.assertEqual(tail, tail_junk)
5237 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5238 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5239 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5240 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5242 obj_decoded.expl_llen,
5243 len(len_encode(len(obj_encoded))),
5245 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5246 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5249 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5251 self.assertEqual(obj_decoded.expl_offset, offset)
5252 for obj_inner in obj_decoded:
5253 self.assertIn(obj_inner, obj_decoded)
5254 self.assertSequenceEqual(
5257 obj_inner.offset - offset:
5258 obj_inner.offset + obj_inner.tlvlen - offset
5262 t, _, lv = tag_strip(obj_encoded)
5263 _, _, v = len_decode(lv)
5264 obj_encoded_lenindef = t + LENINDEF + v + EOC
5265 obj_decoded_lenindef, tail_lenindef = obj.decode(
5266 obj_encoded_lenindef + tail_junk,
5267 ctx={"bered": True},
5269 self.assertTrue(obj_decoded_lenindef.lenindef)
5270 repr(obj_decoded_lenindef)
5271 pprint(obj_decoded_lenindef)
5272 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5273 with self.assertRaises(DecodeError):
5274 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5275 with self.assertRaises(DecodeError):
5276 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5279 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5280 class SeqOf(SequenceOf):
5284 def _test_symmetric_compare_objs(self, obj1, obj2):
5285 self.assertEqual(obj1, obj2)
5286 self.assertSequenceEqual(list(obj1), list(obj2))
5289 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5294 def _test_symmetric_compare_objs(self, obj1, obj2):
5295 self.assertSetEqual(
5296 set(int(v) for v in obj1),
5297 set(int(v) for v in obj2),
5300 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5301 @given(data_strategy())
5302 def test_sorted(self, d):
5303 values = [OctetString(v) for v in d.draw(lists(binary()))]
5306 schema = OctetString()
5308 seq_encoded = seq.encode()
5309 seq_decoded, _ = seq.decode(seq_encoded)
5310 self.assertSequenceEqual(
5311 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5312 b"".join(sorted([v.encode() for v in values])),
5316 class TestGoMarshalVectors(TestCase):
5318 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5319 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5320 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5321 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5322 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5324 class Seq(Sequence):
5326 ("erste", Integer()),
5327 ("zweite", Integer(optional=True))
5330 seq["erste"] = Integer(64)
5331 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5332 seq["erste"] = Integer(0x123456)
5333 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5334 seq["erste"] = Integer(64)
5335 seq["zweite"] = Integer(65)
5336 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5338 class NestedSeq(Sequence):
5342 seq["erste"] = Integer(127)
5343 seq["zweite"] = None
5344 nested = NestedSeq()
5345 nested["nest"] = seq
5346 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5348 self.assertSequenceEqual(
5349 OctetString(b"\x01\x02\x03").encode(),
5350 hexdec("0403010203"),
5353 class Seq(Sequence):
5355 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5358 seq["erste"] = Integer(64)
5359 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5361 class Seq(Sequence):
5363 ("erste", Integer(expl=tag_ctxc(5))),
5366 seq["erste"] = Integer(64)
5367 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5369 class Seq(Sequence):
5372 impl=tag_encode(0, klass=TagClassContext),
5377 seq["erste"] = Null()
5378 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5380 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5382 self.assertSequenceEqual(
5383 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5384 hexdec("170d3730303130313030303030305a"),
5386 self.assertSequenceEqual(
5387 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5388 hexdec("170d3039313131353232353631365a"),
5390 self.assertSequenceEqual(
5391 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5392 hexdec("180f32313030303430353132303130315a"),
5395 class Seq(Sequence):
5397 ("erste", GeneralizedTime()),
5400 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5401 self.assertSequenceEqual(
5403 hexdec("3011180f32303039313131353232353631365a"),
5406 self.assertSequenceEqual(
5407 BitString((1, b"\x80")).encode(),
5410 self.assertSequenceEqual(
5411 BitString((12, b"\x81\xF0")).encode(),
5412 hexdec("03030481f0"),
5415 self.assertSequenceEqual(
5416 ObjectIdentifier("1.2.3.4").encode(),
5417 hexdec("06032a0304"),
5419 self.assertSequenceEqual(
5420 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5421 hexdec("06092a864888932d010105"),
5423 self.assertSequenceEqual(
5424 ObjectIdentifier("2.100.3").encode(),
5425 hexdec("0603813403"),
5428 self.assertSequenceEqual(
5429 PrintableString("test").encode(),
5430 hexdec("130474657374"),
5432 self.assertSequenceEqual(
5433 PrintableString("x" * 127).encode(),
5434 hexdec("137F" + "78" * 127),
5436 self.assertSequenceEqual(
5437 PrintableString("x" * 128).encode(),
5438 hexdec("138180" + "78" * 128),
5440 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5442 class Seq(Sequence):
5444 ("erste", IA5String()),
5447 seq["erste"] = IA5String("test")
5448 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5450 class Seq(Sequence):
5452 ("erste", PrintableString()),
5455 seq["erste"] = PrintableString("test")
5456 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5457 seq["erste"] = PrintableString("test*")
5458 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5460 class Seq(Sequence):
5462 ("erste", Any(optional=True)),
5463 ("zweite", Integer()),
5466 seq["zweite"] = Integer(64)
5467 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5472 seq.append(Integer(10))
5473 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5475 class _SeqOf(SequenceOf):
5476 schema = PrintableString()
5478 class SeqOf(SequenceOf):
5481 _seqof.append(PrintableString("1"))
5483 seqof.append(_seqof)
5484 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5486 class Seq(Sequence):
5488 ("erste", Integer(default=1)),
5491 seq["erste"] = Integer(0)
5492 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5493 seq["erste"] = Integer(1)
5494 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5495 seq["erste"] = Integer(2)
5496 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5499 class TestPP(TestCase):
5500 @given(data_strategy())
5501 def test_oid_printing(self, d):
5503 str(ObjectIdentifier(k)): v * 2
5504 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5506 chosen = d.draw(sampled_from(sorted(oids)))
5507 chosen_id = oids[chosen]
5508 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5509 self.assertNotIn(chosen_id, pp_console_row(pp))
5510 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5513 class TestAutoAddSlots(TestCase):
5515 class Inher(Integer):
5518 with self.assertRaises(AttributeError):
5520 inher.unexistent = "whatever"
5523 class TestOIDDefines(TestCase):
5524 @given(data_strategy())
5525 def runTest(self, d):
5526 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5527 value_name_chosen = d.draw(sampled_from(value_names))
5529 ObjectIdentifier(oid)
5530 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5532 oid_chosen = d.draw(sampled_from(oids))
5533 values = d.draw(lists(
5535 min_size=len(value_names),
5536 max_size=len(value_names),
5539 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5540 oid: Integer() for oid in oids[:-1]
5543 for i, value_name in enumerate(value_names):
5544 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5546 class Seq(Sequence):
5549 for value_name, value in zip(value_names, values):
5550 seq[value_name] = Any(Integer(value).encode())
5551 seq["type"] = oid_chosen
5552 seq, _ = Seq().decode(seq.encode())
5553 for value_name in value_names:
5554 if value_name == value_name_chosen:
5556 self.assertIsNone(seq[value_name].defined)
5557 if value_name_chosen in oids[:-1]:
5558 self.assertIsNotNone(seq[value_name_chosen].defined)
5559 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5560 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5563 class TestDefinesByPath(TestCase):
5564 def test_generated(self):
5565 class Seq(Sequence):
5567 ("type", ObjectIdentifier()),
5568 ("value", OctetString(expl=tag_ctxc(123))),
5571 class SeqInner(Sequence):
5573 ("typeInner", ObjectIdentifier()),
5574 ("valueInner", Any()),
5577 class PairValue(SetOf):
5580 class Pair(Sequence):
5582 ("type", ObjectIdentifier()),
5583 ("value", PairValue()),
5586 class Pairs(SequenceOf):
5593 type_octet_stringed,
5595 ObjectIdentifier(oid)
5596 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5598 seq_integered = Seq()
5599 seq_integered["type"] = type_integered
5600 seq_integered["value"] = OctetString(Integer(123).encode())
5601 seq_integered_raw = seq_integered.encode()
5605 (type_octet_stringed, OctetString(b"whatever")),
5606 (type_integered, Integer(123)),
5607 (type_octet_stringed, OctetString(b"whenever")),
5608 (type_integered, Integer(234)),
5610 for t, v in pairs_input:
5613 pair["value"] = PairValue((Any(v),))
5615 seq_inner = SeqInner()
5616 seq_inner["typeInner"] = type_innered
5617 seq_inner["valueInner"] = Any(pairs)
5618 seq_sequenced = Seq()
5619 seq_sequenced["type"] = type_sequenced
5620 seq_sequenced["value"] = OctetString(seq_inner.encode())
5621 seq_sequenced_raw = seq_sequenced.encode()
5623 defines_by_path = []
5624 seq_integered, _ = Seq().decode(seq_integered_raw)
5625 self.assertIsNone(seq_integered["value"].defined)
5626 defines_by_path.append(
5627 (("type",), ((("value",), {
5628 type_integered: Integer(),
5629 type_sequenced: SeqInner(),
5632 seq_integered, _ = Seq().decode(
5634 ctx={"defines_by_path": defines_by_path},
5636 self.assertIsNotNone(seq_integered["value"].defined)
5637 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5638 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5639 self.assertTrue(seq_integered_raw[
5640 seq_integered["value"].defined[1].offset:
5641 ].startswith(Integer(123).encode()))
5643 seq_sequenced, _ = Seq().decode(
5645 ctx={"defines_by_path": defines_by_path},
5647 self.assertIsNotNone(seq_sequenced["value"].defined)
5648 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5649 seq_inner = seq_sequenced["value"].defined[1]
5650 self.assertIsNone(seq_inner["valueInner"].defined)
5652 defines_by_path.append((
5653 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5654 ((("valueInner",), {type_innered: Pairs()}),),
5656 seq_sequenced, _ = Seq().decode(
5658 ctx={"defines_by_path": defines_by_path},
5660 self.assertIsNotNone(seq_sequenced["value"].defined)
5661 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5662 seq_inner = seq_sequenced["value"].defined[1]
5663 self.assertIsNotNone(seq_inner["valueInner"].defined)
5664 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5665 pairs = seq_inner["valueInner"].defined[1]
5667 self.assertIsNone(pair["value"][0].defined)
5669 defines_by_path.append((
5672 DecodePathDefBy(type_sequenced),
5674 DecodePathDefBy(type_innered),
5679 type_integered: Integer(),
5680 type_octet_stringed: OctetString(),
5683 seq_sequenced, _ = Seq().decode(
5685 ctx={"defines_by_path": defines_by_path},
5687 self.assertIsNotNone(seq_sequenced["value"].defined)
5688 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5689 seq_inner = seq_sequenced["value"].defined[1]
5690 self.assertIsNotNone(seq_inner["valueInner"].defined)
5691 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5692 pairs_got = seq_inner["valueInner"].defined[1]
5693 for pair_input, pair_got in zip(pairs_input, pairs_got):
5694 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5695 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5697 @given(oid_strategy(), integers())
5698 def test_simple(self, oid, tgt):
5699 class Inner(Sequence):
5701 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5702 ObjectIdentifier(oid): Integer(),
5706 class Outer(Sequence):
5709 ("tgt", OctetString()),
5713 inner["oid"] = ObjectIdentifier(oid)
5715 outer["inner"] = inner
5716 outer["tgt"] = OctetString(Integer(tgt).encode())
5717 decoded, _ = Outer().decode(outer.encode())
5718 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5721 class TestAbsDecodePath(TestCase):
5723 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5724 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5726 def test_concat(self, decode_path, rel_path):
5727 self.assertSequenceEqual(
5728 abs_decode_path(decode_path, rel_path),
5729 decode_path + rel_path,
5733 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5734 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5736 def test_abs(self, decode_path, rel_path):
5737 self.assertSequenceEqual(
5738 abs_decode_path(decode_path, ("/",) + rel_path),
5743 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5744 integers(min_value=1, max_value=3),
5745 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5747 def test_dots(self, decode_path, number_of_dots, rel_path):
5748 self.assertSequenceEqual(
5749 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5750 decode_path[:-number_of_dots] + rel_path,
5754 class TestStrictDefaultExistence(TestCase):
5755 @given(data_strategy())
5756 def runTest(self, d):
5757 count = d.draw(integers(min_value=1, max_value=10))
5758 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5760 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5761 for i in range(count)
5764 class Seq(Sequence):
5767 for i in range(count):
5768 seq["int%d" % i] = Integer(123)
5770 chosen = "int%d" % chosen
5771 seq.specs[chosen] = seq.specs[chosen](default=123)
5773 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5774 seq.decode(raw, ctx={"strict_default_existence": True})
5777 class TestX690PrefixedType(TestCase):
5779 self.assertSequenceEqual(
5780 VisibleString("Jones").encode(),
5781 hexdec("1A054A6F6E6573"),
5783 self.assertSequenceEqual(
5786 impl=tag_encode(3, klass=TagClassApplication),
5788 hexdec("43054A6F6E6573"),
5790 self.assertSequenceEqual(
5794 impl=tag_encode(3, klass=TagClassApplication),
5798 hexdec("A20743054A6F6E6573"),
5800 self.assertSequenceEqual(
5804 impl=tag_encode(3, klass=TagClassApplication),
5806 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5808 hexdec("670743054A6F6E6573"),
5810 self.assertSequenceEqual(
5811 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5812 hexdec("82054A6F6E6573"),