2 # PyDERASN -- Python ASN.1 DER codec with abstract structures
3 # Copyright (C) 2017 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 printable
22 from string import whitespace
23 from unittest import TestCase
25 from hypothesis import assume
26 from hypothesis import given
27 from hypothesis import settings
28 from hypothesis.strategies import binary
29 from hypothesis.strategies import booleans
30 from hypothesis.strategies import composite
31 from hypothesis.strategies import data as data_strategy
32 from hypothesis.strategies import datetimes
33 from hypothesis.strategies import dictionaries
34 from hypothesis.strategies import integers
35 from hypothesis.strategies import just
36 from hypothesis.strategies import lists
37 from hypothesis.strategies import none
38 from hypothesis.strategies import one_of
39 from hypothesis.strategies import permutations
40 from hypothesis.strategies import sampled_from
41 from hypothesis.strategies import sets
42 from hypothesis.strategies import text
43 from hypothesis.strategies import tuples
44 from six import assertRaisesRegex
45 from six import byte2int
46 from six import indexbytes
47 from six import int2byte
48 from six import iterbytes
50 from six import text_type
52 from pyderasn import _pp
53 from pyderasn import Any
54 from pyderasn import BitString
55 from pyderasn import BMPString
56 from pyderasn import Boolean
57 from pyderasn import BoundsError
58 from pyderasn import Choice
59 from pyderasn import DecodeError
60 from pyderasn import Enumerated
61 from pyderasn import GeneralizedTime
62 from pyderasn import GeneralString
63 from pyderasn import GraphicString
64 from pyderasn import hexdec
65 from pyderasn import hexenc
66 from pyderasn import IA5String
67 from pyderasn import Integer
68 from pyderasn import InvalidLength
69 from pyderasn import InvalidOID
70 from pyderasn import InvalidValueType
71 from pyderasn import len_decode
72 from pyderasn import len_encode
73 from pyderasn import NotEnoughData
74 from pyderasn import Null
75 from pyderasn import NumericString
76 from pyderasn import ObjectIdentifier
77 from pyderasn import ObjNotReady
78 from pyderasn import ObjUnknown
79 from pyderasn import OctetString
80 from pyderasn import pp_console_row
81 from pyderasn import pprint
82 from pyderasn import PrintableString
83 from pyderasn import Sequence
84 from pyderasn import SequenceOf
85 from pyderasn import Set
86 from pyderasn import SetOf
87 from pyderasn import tag_ctxc
88 from pyderasn import tag_decode
89 from pyderasn import tag_encode
90 from pyderasn import tag_strip
91 from pyderasn import TagClassApplication
92 from pyderasn import TagClassContext
93 from pyderasn import TagClassPrivate
94 from pyderasn import TagClassUniversal
95 from pyderasn import TagFormConstructed
96 from pyderasn import TagFormPrimitive
97 from pyderasn import TagMismatch
98 from pyderasn import TeletexString
99 from pyderasn import UniversalString
100 from pyderasn import UTCTime
101 from pyderasn import UTF8String
102 from pyderasn import VideotexString
103 from pyderasn import VisibleString
106 settings.register_profile('local', settings(
108 perform_health_check=False,
110 settings.load_profile('local')
111 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
113 tag_classes = sampled_from((
119 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
122 class TestHex(TestCase):
124 def test_symmetric(self, data):
125 self.assertEqual(hexdec(hexenc(data)), data)
128 class TestTagCoder(TestCase):
129 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
133 integers(min_value=0, max_value=30),
136 def test_short(self, klass, form, num, junk):
137 raw = tag_encode(klass=klass, form=form, num=num)
138 self.assertEqual(tag_decode(raw), (klass, form, num))
139 self.assertEqual(len(raw), 1)
141 byte2int(tag_encode(klass=klass, form=form, num=0)),
142 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
144 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
145 self.assertSequenceEqual(stripped.tobytes(), raw)
146 self.assertEqual(tlen, len(raw))
147 self.assertSequenceEqual(tail, junk)
149 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
153 integers(min_value=31),
156 def test_long(self, klass, form, num, junk):
157 raw = tag_encode(klass=klass, form=form, num=num)
158 self.assertEqual(tag_decode(raw), (klass, form, num))
159 self.assertGreater(len(raw), 1)
161 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
164 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
165 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
166 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
167 self.assertSequenceEqual(stripped.tobytes(), raw)
168 self.assertEqual(tlen, len(raw))
169 self.assertSequenceEqual(tail, junk)
171 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
172 @given(integers(min_value=31))
173 def test_unfinished_tag(self, num):
174 raw = bytearray(tag_encode(num=num))
175 for i in range(1, len(raw)):
177 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
178 tag_strip(bytes(raw))
180 def test_go_vectors_valid(self):
181 for data, (eklass, etag, elen, eform) in (
182 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
183 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
184 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
185 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
186 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
187 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
188 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
189 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
190 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
191 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
193 tag, _, len_encoded = tag_strip(memoryview(data))
194 klass, form, num = tag_decode(tag)
195 _len, _, tail = len_decode(len_encoded)
196 self.assertSequenceEqual(tail, b"")
197 self.assertEqual(klass, eklass)
198 self.assertEqual(num, etag)
199 self.assertEqual(_len, elen)
200 self.assertEqual(form, eform)
202 def test_go_vectors_invalid(self):
210 with self.assertRaises(DecodeError):
211 _, _, len_encoded = tag_strip(memoryview(data))
212 len_decode(len_encoded)
215 integers(min_value=0, max_value=127),
216 integers(min_value=0, max_value=2),
218 def test_long_instead_of_short(self, l, dummy_num):
219 octets = (b"\x00" * dummy_num) + int2byte(l)
220 octets = int2byte((dummy_num + 1) | 0x80) + octets
221 with self.assertRaises(DecodeError):
225 class TestLenCoder(TestCase):
226 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
228 integers(min_value=0, max_value=127),
231 def test_short(self, l, junk):
232 raw = len_encode(l) + junk
233 decoded, llen, tail = len_decode(memoryview(raw))
234 self.assertEqual(decoded, l)
235 self.assertEqual(llen, 1)
236 self.assertEqual(len(raw), 1 + len(junk))
237 self.assertEqual(tail.tobytes(), junk)
239 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
241 integers(min_value=128),
244 def test_long(self, l, junk):
245 raw = len_encode(l) + junk
246 decoded, llen, tail = len_decode(memoryview(raw))
247 self.assertEqual(decoded, l)
248 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
249 self.assertEqual(llen, len(raw) - len(junk))
250 self.assertNotEqual(indexbytes(raw, 1), 0)
251 self.assertSequenceEqual(tail.tobytes(), junk)
253 def test_empty(self):
254 with self.assertRaises(NotEnoughData):
257 @given(integers(min_value=128))
258 def test_stripped(self, _len):
259 with self.assertRaises(NotEnoughData):
260 len_decode(len_encode(_len)[:-1])
263 text_printable = text(alphabet=printable, min_size=1)
267 def text_letters(draw):
268 result = draw(text(alphabet=ascii_letters, min_size=1))
270 result = result.encode("ascii")
274 class CommonMixin(object):
275 def test_tag_default(self):
276 obj = self.base_klass()
277 self.assertEqual(obj.tag, obj.tag_default)
279 def test_simultaneous_impl_expl(self):
280 with self.assertRaises(ValueError):
281 self.base_klass(impl=b"whatever", expl=b"whenever")
283 @given(binary(), integers(), integers(), integers())
284 def test_decoded(self, impl, offset, llen, vlen):
285 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
286 self.assertEqual(obj.offset, offset)
287 self.assertEqual(obj.llen, llen)
288 self.assertEqual(obj.vlen, vlen)
289 self.assertEqual(obj.tlen, len(impl))
290 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
293 def test_impl_inherited(self, impl_tag):
294 class Inherited(self.base_klass):
297 self.assertSequenceEqual(obj.impl, impl_tag)
298 self.assertFalse(obj.expled)
301 def test_expl_inherited(self, expl_tag):
302 class Inherited(self.base_klass):
305 self.assertSequenceEqual(obj.expl, expl_tag)
306 self.assertTrue(obj.expled)
308 def assert_copied_basic_fields(self, obj, obj_copied):
309 self.assertEqual(obj, obj_copied)
310 self.assertSequenceEqual(obj.tag, obj_copied.tag)
311 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
312 self.assertEqual(obj.default, obj_copied.default)
313 self.assertEqual(obj.optional, obj_copied.optional)
314 self.assertEqual(obj.offset, obj_copied.offset)
315 self.assertEqual(obj.llen, obj_copied.llen)
316 self.assertEqual(obj.vlen, obj_copied.vlen)
320 def boolean_values_strat(draw, do_expl=False):
321 value = draw(one_of(none(), booleans()))
325 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
327 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
328 default = draw(one_of(none(), booleans()))
329 optional = draw(one_of(none(), booleans()))
331 draw(integers(min_value=0)),
332 draw(integers(min_value=0)),
333 draw(integers(min_value=0)),
335 return (value, impl, expl, default, optional, _decoded)
338 class BooleanInherited(Boolean):
342 class TestBoolean(CommonMixin, TestCase):
345 def test_invalid_value_type(self):
346 with self.assertRaises(InvalidValueType) as err:
351 def test_optional(self, optional):
352 obj = Boolean(default=Boolean(False), optional=optional)
353 self.assertTrue(obj.optional)
356 def test_ready(self, value):
358 self.assertFalse(obj.ready)
361 with self.assertRaises(ObjNotReady) as err:
365 self.assertTrue(obj.ready)
369 @given(booleans(), booleans(), binary(), binary())
370 def test_comparison(self, value1, value2, tag1, tag2):
371 for klass in (Boolean, BooleanInherited):
374 self.assertEqual(obj1 == obj2, value1 == value2)
375 self.assertEqual(obj1 == bool(obj2), value1 == value2)
376 obj1 = klass(value1, impl=tag1)
377 obj2 = klass(value1, impl=tag2)
378 self.assertEqual(obj1 == obj2, tag1 == tag2)
380 @given(data_strategy())
381 def test_call(self, d):
382 for klass in (Boolean, BooleanInherited):
390 ) = d.draw(boolean_values_strat())
396 optional_initial or False,
406 ) = d.draw(boolean_values_strat(do_expl=impl_initial is None))
407 obj = obj_initial(value, impl, expl, default, optional)
409 value_expected = default if value is None else value
411 default_initial if value_expected is None
414 self.assertEqual(obj, value_expected)
415 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
416 self.assertEqual(obj.expl_tag, expl or expl_initial)
419 default_initial if default is None else default,
421 if obj.default is None:
422 optional = optional_initial if optional is None else optional
423 optional = False if optional is None else optional
426 self.assertEqual(obj.optional, optional)
428 @given(boolean_values_strat())
429 def test_copy(self, values):
430 for klass in (Boolean, BooleanInherited):
432 obj_copied = obj.copy()
433 self.assert_copied_basic_fields(obj, obj_copied)
437 integers(min_value=1).map(tag_encode),
439 def test_stripped(self, value, tag_impl):
440 obj = Boolean(value, impl=tag_impl)
441 with self.assertRaises(NotEnoughData):
442 obj.decode(obj.encode()[:-1])
446 integers(min_value=1).map(tag_ctxc),
448 def test_stripped_expl(self, value, tag_expl):
449 obj = Boolean(value, expl=tag_expl)
450 with self.assertRaises(NotEnoughData):
451 obj.decode(obj.encode()[:-1])
454 integers(min_value=31),
455 integers(min_value=0),
458 def test_bad_tag(self, tag, offset, decode_path):
459 decode_path = tuple(str(i) for i in decode_path)
460 with self.assertRaises(DecodeError) as err:
462 tag_encode(tag)[:-1],
464 decode_path=decode_path,
467 self.assertEqual(err.exception.offset, offset)
468 self.assertEqual(err.exception.decode_path, decode_path)
471 integers(min_value=31),
472 integers(min_value=0),
475 def test_bad_expl_tag(self, tag, offset, decode_path):
476 decode_path = tuple(str(i) for i in decode_path)
477 with self.assertRaises(DecodeError) as err:
478 Boolean(expl=Boolean.tag_default).decode(
479 tag_encode(tag)[:-1],
481 decode_path=decode_path,
484 self.assertEqual(err.exception.offset, offset)
485 self.assertEqual(err.exception.decode_path, decode_path)
488 integers(min_value=128),
489 integers(min_value=0),
492 def test_bad_len(self, l, offset, decode_path):
493 decode_path = tuple(str(i) for i in decode_path)
494 with self.assertRaises(DecodeError) as err:
496 Boolean.tag_default + len_encode(l)[:-1],
498 decode_path=decode_path,
501 self.assertEqual(err.exception.offset, offset)
502 self.assertEqual(err.exception.decode_path, decode_path)
505 integers(min_value=128),
506 integers(min_value=0),
509 def test_bad_expl_len(self, l, offset, decode_path):
510 decode_path = tuple(str(i) for i in decode_path)
511 with self.assertRaises(DecodeError) as err:
512 Boolean(expl=Boolean.tag_default).decode(
513 Boolean.tag_default + len_encode(l)[:-1],
515 decode_path=decode_path,
518 self.assertEqual(err.exception.offset, offset)
519 self.assertEqual(err.exception.decode_path, decode_path)
521 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
523 boolean_values_strat(),
525 integers(min_value=1).map(tag_ctxc),
526 integers(min_value=0),
528 def test_symmetric(self, values, value, tag_expl, offset):
529 for klass in (Boolean, BooleanInherited):
530 _, _, _, default, optional, _decoded = values
539 self.assertFalse(obj.expled)
540 obj_encoded = obj.encode()
541 obj_expled = obj(value, expl=tag_expl)
542 self.assertTrue(obj_expled.expled)
545 obj_expled_encoded = obj_expled.encode()
546 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
549 self.assertEqual(tail, b"")
550 self.assertEqual(obj_decoded, obj_expled)
551 self.assertNotEqual(obj_decoded, obj)
552 self.assertEqual(bool(obj_decoded), bool(obj_expled))
553 self.assertEqual(bool(obj_decoded), bool(obj))
554 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
555 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
556 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
558 obj_decoded.expl_llen,
559 len(len_encode(len(obj_encoded))),
561 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
562 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
565 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
567 self.assertEqual(obj_decoded.expl_offset, offset)
569 @given(integers(min_value=2))
570 def test_invalid_len(self, l):
571 with self.assertRaises(InvalidLength):
572 Boolean().decode(b"".join((
578 @given(integers(min_value=0 + 1, max_value=255 - 1))
579 def test_invalid_value(self, value):
580 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
581 Boolean().decode(b"".join((
589 def integer_values_strat(draw, do_expl=False):
590 bound_min, value, default, bound_max = sorted(draw(sets(
599 _specs = draw(sets(text_letters()))
602 min_size=len(_specs),
603 max_size=len(_specs),
605 _specs = list(zip(_specs, values))
608 bounds = (bound_min, bound_max)
612 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
614 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
617 optional = draw(one_of(none(), booleans()))
619 draw(integers(min_value=0)),
620 draw(integers(min_value=0)),
621 draw(integers(min_value=0)),
623 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
626 class IntegerInherited(Integer):
630 class TestInteger(CommonMixin, TestCase):
633 def test_invalid_value_type(self):
634 with self.assertRaises(InvalidValueType) as err:
638 @given(sets(text_letters(), min_size=2))
639 def test_unknown_name(self, names_input):
640 missing = names_input.pop()
643 schema = [(n, 123) for n in names_input]
644 with self.assertRaises(ObjUnknown) as err:
648 @given(sets(text_letters(), min_size=2))
649 def test_known_name(self, names_input):
651 schema = [(n, 123) for n in names_input]
652 Int(names_input.pop())
655 def test_optional(self, optional):
656 obj = Integer(default=Integer(0), optional=optional)
657 self.assertTrue(obj.optional)
660 def test_ready(self, value):
662 self.assertFalse(obj.ready)
665 with self.assertRaises(ObjNotReady) as err:
669 self.assertTrue(obj.ready)
674 @given(integers(), integers(), binary(), binary())
675 def test_comparison(self, value1, value2, tag1, tag2):
676 for klass in (Integer, IntegerInherited):
679 self.assertEqual(obj1 == obj2, value1 == value2)
680 self.assertEqual(obj1 == int(obj2), value1 == value2)
681 obj1 = klass(value1, impl=tag1)
682 obj2 = klass(value1, impl=tag2)
683 self.assertEqual(obj1 == obj2, tag1 == tag2)
685 @given(lists(integers()))
686 def test_sorted_works(self, values):
687 self.assertSequenceEqual(
688 [int(v) for v in sorted(Integer(v) for v in values)],
692 @given(data_strategy())
693 def test_named(self, d):
694 names_input = list(d.draw(sets(text_letters(), min_size=1)))
695 values_input = list(d.draw(sets(
697 min_size=len(names_input),
698 max_size=len(names_input),
700 chosen_name = d.draw(sampled_from(names_input))
701 names_input = dict(zip(names_input, values_input))
705 _int = Int(chosen_name)
706 self.assertEqual(_int.named, chosen_name)
707 self.assertEqual(int(_int), names_input[chosen_name])
709 @given(integers(), integers(min_value=0), integers(min_value=0))
710 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
711 value = bound_min + value_delta
712 bound_max = value + bound_delta
713 Integer(value=value, bounds=(bound_min, bound_max))
715 @given(sets(integers(), min_size=3, max_size=3))
716 def test_bounds_unsatisfied(self, values):
717 values = sorted(values)
718 with self.assertRaises(BoundsError) as err:
719 Integer(value=values[0], bounds=(values[1], values[2]))
721 with self.assertRaises(BoundsError) as err:
722 Integer(value=values[2], bounds=(values[0], values[1]))
725 @given(data_strategy())
726 def test_call(self, d):
727 for klass in (Integer, IntegerInherited):
737 ) = d.draw(integer_values_strat())
744 optional_initial or False,
757 ) = d.draw(integer_values_strat(do_expl=impl_initial is None))
758 if (default is None) and (obj_initial.default is not None):
762 (value is not None) and
763 (bounds_initial is not None) and
764 not (bounds_initial[0] <= value <= bounds_initial[1])
769 (default is not None) and
770 (bounds_initial is not None) and
771 not (bounds_initial[0] <= default <= bounds_initial[1])
774 obj = obj_initial(value, bounds, impl, expl, default, optional)
776 value_expected = default if value is None else value
778 default_initial if value_expected is None
781 self.assertEqual(obj, value_expected)
782 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
783 self.assertEqual(obj.expl_tag, expl or expl_initial)
786 default_initial if default is None else default,
788 if obj.default is None:
789 optional = optional_initial if optional is None else optional
790 optional = False if optional is None else optional
793 self.assertEqual(obj.optional, optional)
795 (obj._bound_min, obj._bound_max),
796 bounds or bounds_initial or (float("-inf"), float("+inf")),
800 {} if _specs_initial is None else dict(_specs_initial),
803 @given(integer_values_strat())
804 def test_copy(self, values):
805 for klass in (Integer, IntegerInherited):
807 obj_copied = obj.copy()
808 self.assert_copied_basic_fields(obj, obj_copied)
809 self.assertEqual(obj.specs, obj_copied.specs)
810 self.assertEqual(obj._bound_min, obj_copied._bound_min)
811 self.assertEqual(obj._bound_max, obj_copied._bound_max)
812 self.assertEqual(obj._value, obj_copied._value)
816 integers(min_value=1).map(tag_encode),
818 def test_stripped(self, value, tag_impl):
819 obj = Integer(value, impl=tag_impl)
820 with self.assertRaises(NotEnoughData):
821 obj.decode(obj.encode()[:-1])
825 integers(min_value=1).map(tag_ctxc),
827 def test_stripped_expl(self, value, tag_expl):
828 obj = Integer(value, expl=tag_expl)
829 with self.assertRaises(NotEnoughData):
830 obj.decode(obj.encode()[:-1])
832 def test_zero_len(self):
833 with self.assertRaises(NotEnoughData):
834 Integer().decode(b"".join((
840 integers(min_value=31),
841 integers(min_value=0),
844 def test_bad_tag(self, tag, offset, decode_path):
845 decode_path = tuple(str(i) for i in decode_path)
846 with self.assertRaises(DecodeError) as err:
848 tag_encode(tag)[:-1],
850 decode_path=decode_path,
853 self.assertEqual(err.exception.offset, offset)
854 self.assertEqual(err.exception.decode_path, decode_path)
857 integers(min_value=128),
858 integers(min_value=0),
861 def test_bad_len(self, l, offset, decode_path):
862 decode_path = tuple(str(i) for i in decode_path)
863 with self.assertRaises(DecodeError) as err:
865 Integer.tag_default + len_encode(l)[:-1],
867 decode_path=decode_path,
870 self.assertEqual(err.exception.offset, offset)
871 self.assertEqual(err.exception.decode_path, decode_path)
874 sets(integers(), min_size=2, max_size=2),
875 integers(min_value=0),
878 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
879 decode_path = tuple(str(i) for i in decode_path)
880 value, bound_min = list(sorted(ints))
883 bounds = (bound_min, bound_min)
884 with self.assertRaises(DecodeError) as err:
886 Integer(value).encode(),
888 decode_path=decode_path,
891 self.assertEqual(err.exception.offset, offset)
892 self.assertEqual(err.exception.decode_path, decode_path)
894 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
896 integer_values_strat(),
898 integers(min_value=1).map(tag_ctxc),
899 integers(min_value=0),
901 def test_symmetric(self, values, value, tag_expl, offset):
902 for klass in (Integer, IntegerInherited):
903 _, _, _, _, default, optional, _, _decoded = values
912 self.assertFalse(obj.expled)
913 obj_encoded = obj.encode()
914 obj_expled = obj(value, expl=tag_expl)
915 self.assertTrue(obj_expled.expled)
918 obj_expled_encoded = obj_expled.encode()
919 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
922 self.assertEqual(tail, b"")
923 self.assertEqual(obj_decoded, obj_expled)
924 self.assertNotEqual(obj_decoded, obj)
925 self.assertEqual(int(obj_decoded), int(obj_expled))
926 self.assertEqual(int(obj_decoded), int(obj))
927 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
928 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
929 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
931 obj_decoded.expl_llen,
932 len(len_encode(len(obj_encoded))),
934 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
935 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
938 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
940 self.assertEqual(obj_decoded.expl_offset, offset)
942 def test_go_vectors_valid(self):
943 for data, expect in ((
955 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
956 (b"\x80\x00\x00\x00", -2147483648),
959 Integer().decode(b"".join((
961 len_encode(len(data)),
967 def test_go_vectors_invalid(self):
972 with self.assertRaises(DecodeError):
973 Integer().decode(b"".join((
975 len_encode(len(data)),
981 def bit_string_values_strat(draw, schema=None, value_required=False, do_expl=False):
985 schema = draw(sets(text_letters(), min_size=1, max_size=256))
987 integers(min_value=0, max_value=255),
988 min_size=len(schema),
989 max_size=len(schema),
991 schema = list(zip(schema, bits))
993 def _value(value_required):
994 if not value_required and draw(booleans()):
996 generation_choice = 0
998 generation_choice = draw(sampled_from((1, 2, 3)))
999 if generation_choice == 1 or draw(booleans()):
1000 return "'%s'B" % "".join(draw(lists(
1001 sampled_from(("0", "1")),
1002 max_size=len(schema),
1004 elif generation_choice == 2 or draw(booleans()):
1005 return draw(binary(max_size=len(schema) // 8))
1006 elif generation_choice == 3 or draw(booleans()):
1007 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1009 value = _value(value_required)
1010 default = _value(value_required=False)
1014 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1016 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1017 optional = draw(one_of(none(), booleans()))
1019 draw(integers(min_value=0)),
1020 draw(integers(min_value=0)),
1021 draw(integers(min_value=0)),
1023 return (schema, value, impl, expl, default, optional, _decoded)
1026 class BitStringInherited(BitString):
1030 class TestBitString(CommonMixin, TestCase):
1031 base_klass = BitString
1033 @given(lists(booleans()))
1034 def test_b_encoding(self, bits):
1035 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1036 self.assertEqual(obj.bit_len, len(bits))
1037 self.assertSequenceEqual(list(obj), bits)
1038 for i, bit in enumerate(bits):
1039 self.assertEqual(obj[i], bit)
1041 @given(lists(booleans()))
1042 def test_out_of_bounds_bits(self, bits):
1043 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1044 for i in range(len(bits), len(bits) * 2):
1045 self.assertFalse(obj[i])
1047 def test_bad_b_encoding(self):
1048 with self.assertRaises(ValueError):
1049 BitString("'010120101'B")
1052 integers(min_value=1, max_value=255),
1053 integers(min_value=1, max_value=255),
1055 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1056 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1057 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1058 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1060 class BS(BitString):
1061 schema = (("whatever", 0),)
1062 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1063 self.assertEqual(obj.bit_len, leading_zeros + 1)
1064 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1066 def test_zero_len(self):
1067 with self.assertRaises(NotEnoughData):
1068 BitString().decode(b"".join((
1069 BitString.tag_default,
1073 def test_invalid_value_type(self):
1074 with self.assertRaises(InvalidValueType) as err:
1077 with self.assertRaises(InvalidValueType) as err:
1081 def test_obj_unknown(self):
1082 with self.assertRaises(ObjUnknown) as err:
1083 BitString(b"whatever")["whenever"]
1086 def test_get_invalid_typ(self):
1087 with self.assertRaises(InvalidValueType) as err:
1088 BitString(b"whatever")[(1, 2, 3)]
1091 @given(data_strategy())
1092 def test_unknown_name(self, d):
1093 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1094 missing = _schema.pop()
1096 class BS(BitString):
1097 schema = [(n, i) for i, n in enumerate(_schema)]
1098 with self.assertRaises(ObjUnknown) as err:
1103 def test_optional(self, optional):
1104 obj = BitString(default=BitString(b""), optional=optional)
1105 self.assertTrue(obj.optional)
1108 def test_ready(self, value):
1110 self.assertFalse(obj.ready)
1113 with self.assertRaises(ObjNotReady) as err:
1116 obj = BitString(value)
1117 self.assertTrue(obj.ready)
1122 tuples(integers(min_value=0), binary()),
1123 tuples(integers(min_value=0), binary()),
1127 def test_comparison(self, value1, value2, tag1, tag2):
1128 for klass in (BitString, BitStringInherited):
1129 obj1 = klass(value1)
1130 obj2 = klass(value2)
1131 self.assertEqual(obj1 == obj2, value1 == value2)
1132 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1133 obj1 = klass(value1, impl=tag1)
1134 obj2 = klass(value1, impl=tag2)
1135 self.assertEqual(obj1 == obj2, tag1 == tag2)
1137 @given(data_strategy())
1138 def test_call(self, d):
1139 for klass in (BitString, BitStringInherited):
1148 ) = d.draw(bit_string_values_strat())
1151 schema = schema_initial
1153 value=value_initial,
1156 default=default_initial,
1157 optional=optional_initial or False,
1158 _decoded=_decoded_initial,
1168 ) = d.draw(bit_string_values_strat(
1169 schema=schema_initial,
1170 do_expl=impl_initial is None,
1179 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1180 self.assertEqual(obj.expl_tag, expl or expl_initial)
1181 if obj.default is None:
1182 optional = optional_initial if optional is None else optional
1183 optional = False if optional is None else optional
1186 self.assertEqual(obj.optional, optional)
1187 self.assertEqual(obj.specs, obj_initial.specs)
1189 @given(bit_string_values_strat())
1190 def test_copy(self, values):
1191 for klass in (BitString, BitStringInherited):
1192 _schema, value, impl, expl, default, optional, _decoded = values
1201 optional=optional or False,
1204 obj_copied = obj.copy()
1205 self.assert_copied_basic_fields(obj, obj_copied)
1206 self.assertEqual(obj.specs, obj_copied.specs)
1207 self.assertEqual(obj._value, obj_copied._value)
1211 integers(min_value=1).map(tag_encode),
1213 def test_stripped(self, value, tag_impl):
1214 obj = BitString(value, impl=tag_impl)
1215 with self.assertRaises(NotEnoughData):
1216 obj.decode(obj.encode()[:-1])
1220 integers(min_value=1).map(tag_ctxc),
1222 def test_stripped_expl(self, value, tag_expl):
1223 obj = BitString(value, expl=tag_expl)
1224 with self.assertRaises(NotEnoughData):
1225 obj.decode(obj.encode()[:-1])
1228 integers(min_value=31),
1229 integers(min_value=0),
1232 def test_bad_tag(self, tag, offset, decode_path):
1233 decode_path = tuple(str(i) for i in decode_path)
1234 with self.assertRaises(DecodeError) as err:
1236 tag_encode(tag)[:-1],
1238 decode_path=decode_path,
1241 self.assertEqual(err.exception.offset, offset)
1242 self.assertEqual(err.exception.decode_path, decode_path)
1245 integers(min_value=128),
1246 integers(min_value=0),
1249 def test_bad_len(self, l, offset, decode_path):
1250 decode_path = tuple(str(i) for i in decode_path)
1251 with self.assertRaises(DecodeError) as err:
1253 BitString.tag_default + len_encode(l)[:-1],
1255 decode_path=decode_path,
1258 self.assertEqual(err.exception.offset, offset)
1259 self.assertEqual(err.exception.decode_path, decode_path)
1261 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1262 @given(data_strategy())
1263 def test_symmetric(self, d):
1272 ) = d.draw(bit_string_values_strat(value_required=True))
1273 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1274 offset = d.draw(integers(min_value=0))
1275 for klass in (BitString, BitStringInherited):
1286 self.assertFalse(obj.expled)
1287 obj_encoded = obj.encode()
1288 obj_expled = obj(value, expl=tag_expl)
1289 self.assertTrue(obj_expled.expled)
1292 obj_expled_encoded = obj_expled.encode()
1293 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1296 self.assertEqual(tail, b"")
1297 self.assertEqual(obj_decoded, obj_expled)
1298 self.assertNotEqual(obj_decoded, obj)
1299 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1300 self.assertEqual(bytes(obj_decoded), bytes(obj))
1301 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1302 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1303 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1305 obj_decoded.expl_llen,
1306 len(len_encode(len(obj_encoded))),
1308 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1309 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1312 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1314 self.assertEqual(obj_decoded.expl_offset, offset)
1315 if isinstance(value, tuple):
1316 self.assertSetEqual(set(value), set(obj_decoded.named))
1320 @given(integers(min_value=1, max_value=255))
1321 def test_bad_zero_value(self, pad_size):
1322 with self.assertRaises(DecodeError):
1323 BitString().decode(b"".join((
1324 BitString.tag_default,
1329 def test_go_vectors_invalid(self):
1335 with self.assertRaises(DecodeError):
1336 BitString().decode(b"".join((
1337 BitString.tag_default,
1342 def test_go_vectors_valid(self):
1343 obj, _ = BitString().decode(b"".join((
1344 BitString.tag_default,
1348 self.assertEqual(bytes(obj), b"")
1349 self.assertEqual(obj.bit_len, 0)
1351 obj, _ = BitString().decode(b"".join((
1352 BitString.tag_default,
1356 self.assertEqual(bytes(obj), b"\x00")
1357 self.assertEqual(obj.bit_len, 1)
1359 obj = BitString((16, b"\x82\x40"))
1360 self.assertTrue(obj[0])
1361 self.assertFalse(obj[1])
1362 self.assertTrue(obj[6])
1363 self.assertTrue(obj[9])
1364 self.assertFalse(obj[17])
1368 def octet_string_values_strat(draw, do_expl=False):
1369 bound_min, bound_max = sorted(draw(sets(
1370 integers(min_value=0, max_value=1 << 7),
1374 value = draw(one_of(
1376 binary(min_size=bound_min, max_size=bound_max),
1378 default = draw(one_of(
1380 binary(min_size=bound_min, max_size=bound_max),
1383 if draw(booleans()):
1384 bounds = (bound_min, bound_max)
1388 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1390 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1391 optional = draw(one_of(none(), booleans()))
1393 draw(integers(min_value=0)),
1394 draw(integers(min_value=0)),
1395 draw(integers(min_value=0)),
1397 return (value, bounds, impl, expl, default, optional, _decoded)
1400 class OctetStringInherited(OctetString):
1404 class TestOctetString(CommonMixin, TestCase):
1405 base_klass = OctetString
1407 def test_invalid_value_type(self):
1408 with self.assertRaises(InvalidValueType) as err:
1409 OctetString(text_type(123))
1413 def test_optional(self, optional):
1414 obj = OctetString(default=OctetString(b""), optional=optional)
1415 self.assertTrue(obj.optional)
1418 def test_ready(self, value):
1420 self.assertFalse(obj.ready)
1423 with self.assertRaises(ObjNotReady) as err:
1426 obj = OctetString(value)
1427 self.assertTrue(obj.ready)
1431 @given(binary(), binary(), binary(), binary())
1432 def test_comparison(self, value1, value2, tag1, tag2):
1433 for klass in (OctetString, OctetStringInherited):
1434 obj1 = klass(value1)
1435 obj2 = klass(value2)
1436 self.assertEqual(obj1 == obj2, value1 == value2)
1437 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1438 obj1 = klass(value1, impl=tag1)
1439 obj2 = klass(value1, impl=tag2)
1440 self.assertEqual(obj1 == obj2, tag1 == tag2)
1442 @given(data_strategy())
1443 def test_bounds_satisfied(self, d):
1444 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1445 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1446 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1447 OctetString(value=value, bounds=(bound_min, bound_max))
1449 @given(data_strategy())
1450 def test_bounds_unsatisfied(self, d):
1451 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1452 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1453 value = d.draw(binary(max_size=bound_min - 1))
1454 with self.assertRaises(BoundsError) as err:
1455 OctetString(value=value, bounds=(bound_min, bound_max))
1457 value = d.draw(binary(min_size=bound_max + 1))
1458 with self.assertRaises(BoundsError) as err:
1459 OctetString(value=value, bounds=(bound_min, bound_max))
1462 @given(data_strategy())
1463 def test_call(self, d):
1464 for klass in (OctetString, OctetStringInherited):
1473 ) = d.draw(octet_string_values_strat())
1474 obj_initial = klass(
1480 optional_initial or False,
1491 ) = d.draw(octet_string_values_strat(do_expl=impl_initial is None))
1492 if (default is None) and (obj_initial.default is not None):
1495 (bounds is None) and
1496 (value is not None) and
1497 (bounds_initial is not None) and
1498 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1502 (bounds is None) and
1503 (default is not None) and
1504 (bounds_initial is not None) and
1505 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1508 obj = obj_initial(value, bounds, impl, expl, default, optional)
1510 value_expected = default if value is None else value
1512 default_initial if value_expected is None
1515 self.assertEqual(obj, value_expected)
1516 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1517 self.assertEqual(obj.expl_tag, expl or expl_initial)
1520 default_initial if default is None else default,
1522 if obj.default is None:
1523 optional = optional_initial if optional is None else optional
1524 optional = False if optional is None else optional
1527 self.assertEqual(obj.optional, optional)
1529 (obj._bound_min, obj._bound_max),
1530 bounds or bounds_initial or (0, float("+inf")),
1533 @given(octet_string_values_strat())
1534 def test_copy(self, values):
1535 for klass in (OctetString, OctetStringInherited):
1536 obj = klass(*values)
1537 obj_copied = obj.copy()
1538 self.assert_copied_basic_fields(obj, obj_copied)
1539 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1540 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1541 self.assertEqual(obj._value, obj_copied._value)
1545 integers(min_value=1).map(tag_encode),
1547 def test_stripped(self, value, tag_impl):
1548 obj = OctetString(value, impl=tag_impl)
1549 with self.assertRaises(NotEnoughData):
1550 obj.decode(obj.encode()[:-1])
1554 integers(min_value=1).map(tag_ctxc),
1556 def test_stripped_expl(self, value, tag_expl):
1557 obj = OctetString(value, expl=tag_expl)
1558 with self.assertRaises(NotEnoughData):
1559 obj.decode(obj.encode()[:-1])
1562 integers(min_value=31),
1563 integers(min_value=0),
1566 def test_bad_tag(self, tag, offset, decode_path):
1567 decode_path = tuple(str(i) for i in decode_path)
1568 with self.assertRaises(DecodeError) as err:
1569 OctetString().decode(
1570 tag_encode(tag)[:-1],
1572 decode_path=decode_path,
1575 self.assertEqual(err.exception.offset, offset)
1576 self.assertEqual(err.exception.decode_path, decode_path)
1579 integers(min_value=128),
1580 integers(min_value=0),
1583 def test_bad_len(self, l, offset, decode_path):
1584 decode_path = tuple(str(i) for i in decode_path)
1585 with self.assertRaises(DecodeError) as err:
1586 OctetString().decode(
1587 OctetString.tag_default + len_encode(l)[:-1],
1589 decode_path=decode_path,
1592 self.assertEqual(err.exception.offset, offset)
1593 self.assertEqual(err.exception.decode_path, decode_path)
1596 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1597 integers(min_value=0),
1600 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1601 decode_path = tuple(str(i) for i in decode_path)
1602 value, bound_min = list(sorted(ints))
1604 class String(OctetString):
1605 bounds = (bound_min, bound_min)
1606 with self.assertRaises(DecodeError) as err:
1608 OctetString(b"\x00" * value).encode(),
1610 decode_path=decode_path,
1613 self.assertEqual(err.exception.offset, offset)
1614 self.assertEqual(err.exception.decode_path, decode_path)
1616 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1618 octet_string_values_strat(),
1620 integers(min_value=1).map(tag_ctxc),
1621 integers(min_value=0),
1623 def test_symmetric(self, values, value, tag_expl, offset):
1624 for klass in (OctetString, OctetStringInherited):
1625 _, _, _, _, default, optional, _decoded = values
1634 self.assertFalse(obj.expled)
1635 obj_encoded = obj.encode()
1636 obj_expled = obj(value, expl=tag_expl)
1637 self.assertTrue(obj_expled.expled)
1640 obj_expled_encoded = obj_expled.encode()
1641 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1644 self.assertEqual(tail, b"")
1645 self.assertEqual(obj_decoded, obj_expled)
1646 self.assertNotEqual(obj_decoded, obj)
1647 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1648 self.assertEqual(bytes(obj_decoded), bytes(obj))
1649 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1650 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1651 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1653 obj_decoded.expl_llen,
1654 len(len_encode(len(obj_encoded))),
1656 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1657 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1660 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1662 self.assertEqual(obj_decoded.expl_offset, offset)
1666 def null_values_strat(draw, do_expl=False):
1670 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1672 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1673 optional = draw(one_of(none(), booleans()))
1675 draw(integers(min_value=0)),
1676 draw(integers(min_value=0)),
1677 draw(integers(min_value=0)),
1679 return (impl, expl, optional, _decoded)
1682 class NullInherited(Null):
1686 class TestNull(CommonMixin, TestCase):
1689 def test_ready(self):
1691 self.assertTrue(obj.ready)
1695 @given(binary(), binary())
1696 def test_comparison(self, tag1, tag2):
1697 for klass in (Null, NullInherited):
1698 obj1 = klass(impl=tag1)
1699 obj2 = klass(impl=tag2)
1700 self.assertEqual(obj1 == obj2, tag1 == tag2)
1701 self.assertNotEqual(obj1, tag2)
1703 @given(data_strategy())
1704 def test_call(self, d):
1705 for klass in (Null, NullInherited):
1711 ) = d.draw(null_values_strat())
1712 obj_initial = klass(
1715 optional=optional_initial or False,
1716 _decoded=_decoded_initial,
1723 ) = d.draw(null_values_strat(do_expl=impl_initial is None))
1724 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1725 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1726 self.assertEqual(obj.expl_tag, expl or expl_initial)
1727 optional = optional_initial if optional is None else optional
1728 optional = False if optional is None else optional
1729 self.assertEqual(obj.optional, optional)
1731 @given(null_values_strat())
1732 def test_copy(self, values):
1733 for klass in (Null, NullInherited):
1734 impl, expl, optional, _decoded = values
1738 optional=optional or False,
1741 obj_copied = obj.copy()
1742 self.assert_copied_basic_fields(obj, obj_copied)
1744 @given(integers(min_value=1).map(tag_encode))
1745 def test_stripped(self, tag_impl):
1746 obj = Null(impl=tag_impl)
1747 with self.assertRaises(NotEnoughData):
1748 obj.decode(obj.encode()[:-1])
1750 @given(integers(min_value=1).map(tag_ctxc))
1751 def test_stripped_expl(self, tag_expl):
1752 obj = Null(expl=tag_expl)
1753 with self.assertRaises(NotEnoughData):
1754 obj.decode(obj.encode()[:-1])
1757 integers(min_value=31),
1758 integers(min_value=0),
1761 def test_bad_tag(self, tag, offset, decode_path):
1762 decode_path = tuple(str(i) for i in decode_path)
1763 with self.assertRaises(DecodeError) as err:
1765 tag_encode(tag)[:-1],
1767 decode_path=decode_path,
1770 self.assertEqual(err.exception.offset, offset)
1771 self.assertEqual(err.exception.decode_path, decode_path)
1774 integers(min_value=128),
1775 integers(min_value=0),
1778 def test_bad_len(self, l, offset, decode_path):
1779 decode_path = tuple(str(i) for i in decode_path)
1780 with self.assertRaises(DecodeError) as err:
1782 Null.tag_default + len_encode(l)[:-1],
1784 decode_path=decode_path,
1787 self.assertEqual(err.exception.offset, offset)
1788 self.assertEqual(err.exception.decode_path, decode_path)
1790 @given(binary(min_size=1))
1791 def test_tag_mismatch(self, impl):
1792 assume(impl != Null.tag_default)
1793 with self.assertRaises(TagMismatch):
1794 Null(impl=impl).decode(Null().encode())
1797 null_values_strat(),
1798 integers(min_value=1).map(tag_ctxc),
1799 integers(min_value=0),
1801 def test_symmetric(self, values, tag_expl, offset):
1802 for klass in (Null, NullInherited):
1803 _, _, optional, _decoded = values
1804 obj = klass(optional=optional, _decoded=_decoded)
1807 self.assertFalse(obj.expled)
1808 obj_encoded = obj.encode()
1809 obj_expled = obj(expl=tag_expl)
1810 self.assertTrue(obj_expled.expled)
1813 obj_expled_encoded = obj_expled.encode()
1814 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1817 self.assertEqual(tail, b"")
1818 self.assertEqual(obj_decoded, obj_expled)
1819 self.assertNotEqual(obj_decoded, obj)
1820 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1821 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1822 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1824 obj_decoded.expl_llen,
1825 len(len_encode(len(obj_encoded))),
1827 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1828 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1831 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1833 self.assertEqual(obj_decoded.expl_offset, offset)
1835 @given(integers(min_value=1))
1836 def test_invalid_len(self, l):
1837 with self.assertRaises(InvalidLength):
1838 Null().decode(b"".join((
1845 def oid_strategy(draw):
1846 first_arc = draw(integers(min_value=0, max_value=2))
1848 if first_arc in (0, 1):
1849 second_arc = draw(integers(min_value=0, max_value=39))
1851 second_arc = draw(integers(min_value=0))
1852 other_arcs = draw(lists(integers(min_value=0)))
1853 return tuple([first_arc, second_arc] + other_arcs)
1857 def oid_values_strat(draw, do_expl=False):
1858 value = draw(one_of(none(), oid_strategy()))
1862 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1864 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1865 default = draw(one_of(none(), oid_strategy()))
1866 optional = draw(one_of(none(), booleans()))
1868 draw(integers(min_value=0)),
1869 draw(integers(min_value=0)),
1870 draw(integers(min_value=0)),
1872 return (value, impl, expl, default, optional, _decoded)
1875 class ObjectIdentifierInherited(ObjectIdentifier):
1879 class TestObjectIdentifier(CommonMixin, TestCase):
1880 base_klass = ObjectIdentifier
1882 def test_invalid_value_type(self):
1883 with self.assertRaises(InvalidValueType) as err:
1884 ObjectIdentifier(123)
1888 def test_optional(self, optional):
1889 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
1890 self.assertTrue(obj.optional)
1892 @given(oid_strategy())
1893 def test_ready(self, value):
1894 obj = ObjectIdentifier()
1895 self.assertFalse(obj.ready)
1898 with self.assertRaises(ObjNotReady) as err:
1901 obj = ObjectIdentifier(value)
1902 self.assertTrue(obj.ready)
1907 @given(oid_strategy(), oid_strategy(), binary(), binary())
1908 def test_comparison(self, value1, value2, tag1, tag2):
1909 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1910 obj1 = klass(value1)
1911 obj2 = klass(value2)
1912 self.assertEqual(obj1 == obj2, value1 == value2)
1913 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
1914 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
1915 obj1 = klass(value1, impl=tag1)
1916 obj2 = klass(value1, impl=tag2)
1917 self.assertEqual(obj1 == obj2, tag1 == tag2)
1919 @given(lists(oid_strategy()))
1920 def test_sorted_works(self, values):
1921 self.assertSequenceEqual(
1922 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
1926 @given(data_strategy())
1927 def test_call(self, d):
1928 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1936 ) = d.draw(oid_values_strat())
1937 obj_initial = klass(
1942 optional_initial or False,
1952 ) = d.draw(oid_values_strat(do_expl=impl_initial is None))
1953 obj = obj_initial(value, impl, expl, default, optional)
1955 value_expected = default if value is None else value
1957 default_initial if value_expected is None
1960 self.assertEqual(obj, value_expected)
1961 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1962 self.assertEqual(obj.expl_tag, expl or expl_initial)
1965 default_initial if default is None else default,
1967 if obj.default is None:
1968 optional = optional_initial if optional is None else optional
1969 optional = False if optional is None else optional
1972 self.assertEqual(obj.optional, optional)
1974 @given(oid_values_strat())
1975 def test_copy(self, values):
1976 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1977 obj = klass(*values)
1978 obj_copied = obj.copy()
1979 self.assert_copied_basic_fields(obj, obj_copied)
1980 self.assertEqual(obj._value, obj_copied._value)
1982 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1985 integers(min_value=1).map(tag_encode),
1987 def test_stripped(self, value, tag_impl):
1988 obj = ObjectIdentifier(value, impl=tag_impl)
1989 with self.assertRaises(NotEnoughData):
1990 obj.decode(obj.encode()[:-1])
1994 integers(min_value=1).map(tag_ctxc),
1996 def test_stripped_expl(self, value, tag_expl):
1997 obj = ObjectIdentifier(value, expl=tag_expl)
1998 with self.assertRaises(NotEnoughData):
1999 obj.decode(obj.encode()[:-1])
2002 integers(min_value=31),
2003 integers(min_value=0),
2006 def test_bad_tag(self, tag, offset, decode_path):
2007 decode_path = tuple(str(i) for i in decode_path)
2008 with self.assertRaises(DecodeError) as err:
2009 ObjectIdentifier().decode(
2010 tag_encode(tag)[:-1],
2012 decode_path=decode_path,
2015 self.assertEqual(err.exception.offset, offset)
2016 self.assertEqual(err.exception.decode_path, decode_path)
2019 integers(min_value=128),
2020 integers(min_value=0),
2023 def test_bad_len(self, l, offset, decode_path):
2024 decode_path = tuple(str(i) for i in decode_path)
2025 with self.assertRaises(DecodeError) as err:
2026 ObjectIdentifier().decode(
2027 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2029 decode_path=decode_path,
2032 self.assertEqual(err.exception.offset, offset)
2033 self.assertEqual(err.exception.decode_path, decode_path)
2035 def test_zero_oid(self):
2036 with self.assertRaises(NotEnoughData):
2037 ObjectIdentifier().decode(
2038 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2041 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2042 @given(oid_strategy())
2043 def test_unfinished_oid(self, value):
2044 assume(list(value)[-1] > 255)
2045 obj_encoded = ObjectIdentifier(value).encode()
2046 obj, _ = ObjectIdentifier().decode(obj_encoded)
2047 data = obj_encoded[obj.tlen + obj.llen:-1]
2049 ObjectIdentifier.tag_default,
2050 len_encode(len(data)),
2053 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2056 @given(integers(min_value=0))
2057 def test_invalid_short(self, value):
2058 with self.assertRaises(InvalidOID):
2059 ObjectIdentifier((value,))
2060 with self.assertRaises(InvalidOID):
2061 ObjectIdentifier("%d" % value)
2063 @given(integers(min_value=3), integers(min_value=0))
2064 def test_invalid_first_arc(self, first_arc, second_arc):
2065 with self.assertRaises(InvalidOID):
2066 ObjectIdentifier((first_arc, second_arc))
2067 with self.assertRaises(InvalidOID):
2068 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2070 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2071 def test_invalid_second_arc(self, first_arc, second_arc):
2072 with self.assertRaises(InvalidOID):
2073 ObjectIdentifier((first_arc, second_arc))
2074 with self.assertRaises(InvalidOID):
2075 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2077 @given(text(alphabet=ascii_letters + ".", min_size=1))
2078 def test_junk(self, oid):
2079 with self.assertRaises(InvalidOID):
2080 ObjectIdentifier(oid)
2082 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2083 @given(oid_strategy())
2084 def test_validness(self, oid):
2085 obj = ObjectIdentifier(oid)
2086 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2091 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2095 integers(min_value=1).map(tag_ctxc),
2096 integers(min_value=0),
2098 def test_symmetric(self, values, value, tag_expl, offset):
2099 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2100 _, _, _, default, optional, _decoded = values
2109 self.assertFalse(obj.expled)
2110 obj_encoded = obj.encode()
2111 obj_expled = obj(value, expl=tag_expl)
2112 self.assertTrue(obj_expled.expled)
2115 obj_expled_encoded = obj_expled.encode()
2116 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2119 self.assertEqual(tail, b"")
2120 self.assertEqual(obj_decoded, obj_expled)
2121 self.assertNotEqual(obj_decoded, obj)
2122 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2123 self.assertEqual(tuple(obj_decoded), tuple(obj))
2124 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2125 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2126 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2128 obj_decoded.expl_llen,
2129 len(len_encode(len(obj_encoded))),
2131 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2132 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2135 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2137 self.assertEqual(obj_decoded.expl_offset, offset)
2140 oid_strategy().map(ObjectIdentifier),
2141 oid_strategy().map(ObjectIdentifier),
2143 def test_add(self, oid1, oid2):
2144 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2145 for oid_to_add in (oid2, tuple(oid2)):
2146 self.assertEqual(oid1 + oid_to_add, oid_expect)
2147 with self.assertRaises(InvalidValueType):
2150 def test_go_vectors_valid(self):
2151 for data, expect in (
2153 (b"\x55\x02", (2, 5, 2)),
2154 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2155 (b"\x81\x34\x03", (2, 100, 3)),
2158 ObjectIdentifier().decode(b"".join((
2159 ObjectIdentifier.tag_default,
2160 len_encode(len(data)),
2166 def test_go_vectors_invalid(self):
2167 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2168 with self.assertRaises(DecodeError):
2169 ObjectIdentifier().decode(b"".join((
2170 Integer.tag_default,
2171 len_encode(len(data)),
2177 def enumerated_values_strat(draw, schema=None, do_expl=False):
2179 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2180 values = list(draw(sets(
2182 min_size=len(schema),
2183 max_size=len(schema),
2185 schema = list(zip(schema, values))
2186 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2190 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2192 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2193 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2194 optional = draw(one_of(none(), booleans()))
2196 draw(integers(min_value=0)),
2197 draw(integers(min_value=0)),
2198 draw(integers(min_value=0)),
2200 return (schema, value, impl, expl, default, optional, _decoded)
2203 class TestEnumerated(CommonMixin, TestCase):
2204 class EWhatever(Enumerated):
2205 schema = (("whatever", 0),)
2207 base_klass = EWhatever
2209 def test_schema_required(self):
2210 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2213 def test_invalid_value_type(self):
2214 with self.assertRaises(InvalidValueType) as err:
2215 self.base_klass((1, 2))
2218 @given(sets(text_letters(), min_size=2))
2219 def test_unknown_name(self, schema_input):
2220 missing = schema_input.pop()
2222 class E(Enumerated):
2223 schema = [(n, 123) for n in schema_input]
2224 with self.assertRaises(ObjUnknown) as err:
2229 sets(text_letters(), min_size=2),
2230 sets(integers(), min_size=2),
2232 def test_unknown_value(self, schema_input, values_input):
2234 missing_value = values_input.pop()
2235 _input = list(zip(schema_input, values_input))
2237 class E(Enumerated):
2239 with self.assertRaises(DecodeError) as err:
2244 def test_optional(self, optional):
2245 obj = self.base_klass(default="whatever", optional=optional)
2246 self.assertTrue(obj.optional)
2248 def test_ready(self):
2249 obj = self.base_klass()
2250 self.assertFalse(obj.ready)
2253 with self.assertRaises(ObjNotReady) as err:
2256 obj = self.base_klass("whatever")
2257 self.assertTrue(obj.ready)
2261 @given(integers(), integers(), binary(), binary())
2262 def test_comparison(self, value1, value2, tag1, tag2):
2263 class E(Enumerated):
2265 ("whatever0", value1),
2266 ("whatever1", value2),
2269 class EInherited(E):
2271 for klass in (E, EInherited):
2272 obj1 = klass(value1)
2273 obj2 = klass(value2)
2274 self.assertEqual(obj1 == obj2, value1 == value2)
2275 self.assertEqual(obj1 == int(obj2), value1 == value2)
2276 obj1 = klass(value1, impl=tag1)
2277 obj2 = klass(value1, impl=tag2)
2278 self.assertEqual(obj1 == obj2, tag1 == tag2)
2280 @given(data_strategy())
2281 def test_call(self, d):
2290 ) = d.draw(enumerated_values_strat())
2292 class E(Enumerated):
2293 schema = schema_initial
2295 value=value_initial,
2298 default=default_initial,
2299 optional=optional_initial or False,
2300 _decoded=_decoded_initial,
2310 ) = d.draw(enumerated_values_strat(
2311 schema=schema_initial,
2312 do_expl=impl_initial is None,
2322 value_expected = default if value is None else value
2324 default_initial if value_expected is None
2329 dict(schema_initial).get(value_expected, value_expected),
2331 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2332 self.assertEqual(obj.expl_tag, expl or expl_initial)
2335 default_initial if default is None else default,
2337 if obj.default is None:
2338 optional = optional_initial if optional is None else optional
2339 optional = False if optional is None else optional
2342 self.assertEqual(obj.optional, optional)
2343 self.assertEqual(obj.specs, dict(schema_initial))
2345 @given(enumerated_values_strat())
2346 def test_copy(self, values):
2347 schema_input, value, impl, expl, default, optional, _decoded = values
2349 class E(Enumerated):
2350 schema = schema_input
2359 obj_copied = obj.copy()
2360 self.assert_copied_basic_fields(obj, obj_copied)
2361 self.assertEqual(obj.specs, obj_copied.specs)
2363 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2364 @given(data_strategy())
2365 def test_symmetric(self, d):
2366 schema_input, _, _, _, default, optional, _decoded = d.draw(
2367 enumerated_values_strat(),
2369 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2370 offset = d.draw(integers(min_value=0))
2371 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2373 class E(Enumerated):
2374 schema = schema_input
2383 self.assertFalse(obj.expled)
2384 obj_encoded = obj.encode()
2385 obj_expled = obj(value, expl=tag_expl)
2386 self.assertTrue(obj_expled.expled)
2389 obj_expled_encoded = obj_expled.encode()
2390 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2393 self.assertEqual(tail, b"")
2394 self.assertEqual(obj_decoded, obj_expled)
2395 self.assertNotEqual(obj_decoded, obj)
2396 self.assertEqual(int(obj_decoded), int(obj_expled))
2397 self.assertEqual(int(obj_decoded), int(obj))
2398 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2399 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2400 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2402 obj_decoded.expl_llen,
2403 len(len_encode(len(obj_encoded))),
2405 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2406 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2409 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2411 self.assertEqual(obj_decoded.expl_offset, offset)
2415 def string_values_strat(draw, alphabet, do_expl=False):
2416 bound_min, bound_max = sorted(draw(sets(
2417 integers(min_value=0, max_value=1 << 7),
2421 value = draw(one_of(
2423 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2425 default = draw(one_of(
2427 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2430 if draw(booleans()):
2431 bounds = (bound_min, bound_max)
2435 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2437 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2438 optional = draw(one_of(none(), booleans()))
2440 draw(integers(min_value=0)),
2441 draw(integers(min_value=0)),
2442 draw(integers(min_value=0)),
2444 return (value, bounds, impl, expl, default, optional, _decoded)
2447 class StringMixin(object):
2448 def test_invalid_value_type(self):
2449 with self.assertRaises(InvalidValueType) as err:
2450 self.base_klass((1, 2))
2453 def text_alphabet(self):
2454 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2455 return printable + whitespace
2459 def test_optional(self, optional):
2460 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2461 self.assertTrue(obj.optional)
2463 @given(data_strategy())
2464 def test_ready(self, d):
2465 obj = self.base_klass()
2466 self.assertFalse(obj.ready)
2470 with self.assertRaises(ObjNotReady) as err:
2473 value = d.draw(text(alphabet=self.text_alphabet()))
2474 obj = self.base_klass(value)
2475 self.assertTrue(obj.ready)
2480 @given(data_strategy())
2481 def test_comparison(self, d):
2482 value1 = d.draw(text(alphabet=self.text_alphabet()))
2483 value2 = d.draw(text(alphabet=self.text_alphabet()))
2484 tag1 = d.draw(binary())
2485 tag2 = d.draw(binary())
2486 obj1 = self.base_klass(value1)
2487 obj2 = self.base_klass(value2)
2488 self.assertEqual(obj1 == obj2, value1 == value2)
2489 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2490 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2491 obj1 = self.base_klass(value1, impl=tag1)
2492 obj2 = self.base_klass(value1, impl=tag2)
2493 self.assertEqual(obj1 == obj2, tag1 == tag2)
2495 @given(data_strategy())
2496 def test_bounds_satisfied(self, d):
2497 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2498 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2499 value = d.draw(text(
2500 alphabet=self.text_alphabet(),
2504 self.base_klass(value=value, bounds=(bound_min, bound_max))
2506 @given(data_strategy())
2507 def test_bounds_unsatisfied(self, d):
2508 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2509 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2510 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2511 with self.assertRaises(BoundsError) as err:
2512 self.base_klass(value=value, bounds=(bound_min, bound_max))
2514 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2515 with self.assertRaises(BoundsError) as err:
2516 self.base_klass(value=value, bounds=(bound_min, bound_max))
2519 @given(data_strategy())
2520 def test_call(self, d):
2529 ) = d.draw(string_values_strat(self.text_alphabet()))
2530 obj_initial = self.base_klass(
2536 optional_initial or False,
2547 ) = d.draw(string_values_strat(
2548 self.text_alphabet(),
2549 do_expl=impl_initial is None,
2551 if (default is None) and (obj_initial.default is not None):
2554 (bounds is None) and
2555 (value is not None) and
2556 (bounds_initial is not None) and
2557 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2561 (bounds is None) and
2562 (default is not None) and
2563 (bounds_initial is not None) and
2564 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2567 obj = obj_initial(value, bounds, impl, expl, default, optional)
2569 value_expected = default if value is None else value
2571 default_initial if value_expected is None
2574 self.assertEqual(obj, value_expected)
2575 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2576 self.assertEqual(obj.expl_tag, expl or expl_initial)
2579 default_initial if default is None else default,
2581 if obj.default is None:
2582 optional = optional_initial if optional is None else optional
2583 optional = False if optional is None else optional
2586 self.assertEqual(obj.optional, optional)
2588 (obj._bound_min, obj._bound_max),
2589 bounds or bounds_initial or (0, float("+inf")),
2592 @given(data_strategy())
2593 def test_copy(self, d):
2594 values = d.draw(string_values_strat(self.text_alphabet()))
2595 obj = self.base_klass(*values)
2596 obj_copied = obj.copy()
2597 self.assert_copied_basic_fields(obj, obj_copied)
2598 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2599 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2600 self.assertEqual(obj._value, obj_copied._value)
2602 @given(data_strategy())
2603 def test_stripped(self, d):
2604 value = d.draw(text(alphabet=self.text_alphabet()))
2605 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2606 obj = self.base_klass(value, impl=tag_impl)
2607 with self.assertRaises(NotEnoughData):
2608 obj.decode(obj.encode()[:-1])
2610 @given(data_strategy())
2611 def test_stripped_expl(self, d):
2612 value = d.draw(text(alphabet=self.text_alphabet()))
2613 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2614 obj = self.base_klass(value, expl=tag_expl)
2615 with self.assertRaises(NotEnoughData):
2616 obj.decode(obj.encode()[:-1])
2619 integers(min_value=31),
2620 integers(min_value=0),
2623 def test_bad_tag(self, tag, offset, decode_path):
2624 decode_path = tuple(str(i) for i in decode_path)
2625 with self.assertRaises(DecodeError) as err:
2626 self.base_klass().decode(
2627 tag_encode(tag)[:-1],
2629 decode_path=decode_path,
2632 self.assertEqual(err.exception.offset, offset)
2633 self.assertEqual(err.exception.decode_path, decode_path)
2636 integers(min_value=128),
2637 integers(min_value=0),
2640 def test_bad_len(self, l, offset, decode_path):
2641 decode_path = tuple(str(i) for i in decode_path)
2642 with self.assertRaises(DecodeError) as err:
2643 self.base_klass().decode(
2644 self.base_klass.tag_default + len_encode(l)[:-1],
2646 decode_path=decode_path,
2649 self.assertEqual(err.exception.offset, offset)
2650 self.assertEqual(err.exception.decode_path, decode_path)
2653 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2654 integers(min_value=0),
2657 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2658 decode_path = tuple(str(i) for i in decode_path)
2659 value, bound_min = list(sorted(ints))
2661 class String(self.base_klass):
2662 # Multiply this value by four, to satisfy UTF-32 bounds
2663 # (4 bytes per character) validation
2664 bounds = (bound_min * 4, bound_min * 4)
2665 with self.assertRaises(DecodeError) as err:
2667 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2669 decode_path=decode_path,
2672 self.assertEqual(err.exception.offset, offset)
2673 self.assertEqual(err.exception.decode_path, decode_path)
2675 @given(data_strategy())
2676 def test_symmetric(self, d):
2677 values = d.draw(string_values_strat(self.text_alphabet()))
2678 value = d.draw(text(alphabet=self.text_alphabet()))
2679 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2680 offset = d.draw(integers(min_value=0))
2681 _, _, _, _, default, optional, _decoded = values
2682 obj = self.base_klass(
2690 self.assertFalse(obj.expled)
2691 obj_encoded = obj.encode()
2692 obj_expled = obj(value, expl=tag_expl)
2693 self.assertTrue(obj_expled.expled)
2696 obj_expled_encoded = obj_expled.encode()
2697 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2700 self.assertEqual(tail, b"")
2701 self.assertEqual(obj_decoded, obj_expled)
2702 self.assertNotEqual(obj_decoded, obj)
2703 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2704 self.assertEqual(bytes(obj_decoded), bytes(obj))
2705 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2706 self.assertEqual(text_type(obj_decoded), text_type(obj))
2707 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2708 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2709 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2711 obj_decoded.expl_llen,
2712 len(len_encode(len(obj_encoded))),
2714 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2715 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2718 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2720 self.assertEqual(obj_decoded.expl_offset, offset)
2723 class TestUTF8String(StringMixin, CommonMixin, TestCase):
2724 base_klass = UTF8String
2727 class TestNumericString(StringMixin, CommonMixin, TestCase):
2728 base_klass = NumericString
2731 class TestPrintableString(StringMixin, CommonMixin, TestCase):
2732 base_klass = PrintableString
2735 class TestTeletexString(StringMixin, CommonMixin, TestCase):
2736 base_klass = TeletexString
2739 class TestVideotexString(StringMixin, CommonMixin, TestCase):
2740 base_klass = VideotexString
2743 class TestIA5String(StringMixin, CommonMixin, TestCase):
2744 base_klass = IA5String
2747 class TestGraphicString(StringMixin, CommonMixin, TestCase):
2748 base_klass = GraphicString
2751 class TestVisibleString(StringMixin, CommonMixin, TestCase):
2752 base_klass = VisibleString
2755 class TestGeneralString(StringMixin, CommonMixin, TestCase):
2756 base_klass = GeneralString
2759 class TestUniversalString(StringMixin, CommonMixin, TestCase):
2760 base_klass = UniversalString
2763 class TestBMPString(StringMixin, CommonMixin, TestCase):
2764 base_klass = BMPString
2768 def generalized_time_values_strat(
2776 if draw(booleans()):
2777 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2779 value = value.replace(microsecond=0)
2781 if draw(booleans()):
2782 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2784 default = default.replace(microsecond=0)
2788 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2790 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2791 optional = draw(one_of(none(), booleans()))
2793 draw(integers(min_value=0)),
2794 draw(integers(min_value=0)),
2795 draw(integers(min_value=0)),
2797 return (value, impl, expl, default, optional, _decoded)
2800 class TimeMixin(object):
2801 def test_invalid_value_type(self):
2802 with self.assertRaises(InvalidValueType) as err:
2803 self.base_klass(datetime.now().timetuple())
2806 @given(data_strategy())
2807 def test_optional(self, d):
2808 default = d.draw(datetimes(
2809 min_value=self.min_datetime,
2810 max_value=self.max_datetime,
2812 optional = d.draw(booleans())
2813 obj = self.base_klass(default=default, optional=optional)
2814 self.assertTrue(obj.optional)
2816 @given(data_strategy())
2817 def test_ready(self, d):
2818 obj = self.base_klass()
2819 self.assertFalse(obj.ready)
2822 with self.assertRaises(ObjNotReady) as err:
2825 value = d.draw(datetimes(min_value=self.min_datetime))
2826 obj = self.base_klass(value)
2827 self.assertTrue(obj.ready)
2831 @given(data_strategy())
2832 def test_comparison(self, d):
2833 value1 = d.draw(datetimes(
2834 min_value=self.min_datetime,
2835 max_value=self.max_datetime,
2837 value2 = d.draw(datetimes(
2838 min_value=self.min_datetime,
2839 max_value=self.max_datetime,
2841 tag1 = d.draw(binary())
2842 tag2 = d.draw(binary())
2844 value1 = value1.replace(microsecond=0)
2845 value2 = value2.replace(microsecond=0)
2846 obj1 = self.base_klass(value1)
2847 obj2 = self.base_klass(value2)
2848 self.assertEqual(obj1 == obj2, value1 == value2)
2849 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
2850 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2851 obj1 = self.base_klass(value1, impl=tag1)
2852 obj2 = self.base_klass(value1, impl=tag2)
2853 self.assertEqual(obj1 == obj2, tag1 == tag2)
2855 @given(data_strategy())
2856 def test_call(self, d):
2864 ) = d.draw(generalized_time_values_strat(
2865 min_datetime=self.min_datetime,
2866 max_datetime=self.max_datetime,
2867 omit_ms=self.omit_ms,
2869 obj_initial = self.base_klass(
2870 value=value_initial,
2873 default=default_initial,
2874 optional=optional_initial or False,
2875 _decoded=_decoded_initial,
2884 ) = d.draw(generalized_time_values_strat(
2885 min_datetime=self.min_datetime,
2886 max_datetime=self.max_datetime,
2887 omit_ms=self.omit_ms,
2888 do_expl=impl_initial is None,
2898 value_expected = default if value is None else value
2900 default_initial if value_expected is None
2903 self.assertEqual(obj, value_expected)
2904 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2905 self.assertEqual(obj.expl_tag, expl or expl_initial)
2908 default_initial if default is None else default,
2910 if obj.default is None:
2911 optional = optional_initial if optional is None else optional
2912 optional = False if optional is None else optional
2915 self.assertEqual(obj.optional, optional)
2917 @given(data_strategy())
2918 def test_copy(self, d):
2919 values = d.draw(generalized_time_values_strat(
2920 min_datetime=self.min_datetime,
2921 max_datetime=self.max_datetime,
2923 obj = self.base_klass(*values)
2924 obj_copied = obj.copy()
2925 self.assert_copied_basic_fields(obj, obj_copied)
2926 self.assertEqual(obj._value, obj_copied._value)
2928 @given(data_strategy())
2929 def test_stripped(self, d):
2930 value = d.draw(datetimes(
2931 min_value=self.min_datetime,
2932 max_value=self.max_datetime,
2934 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2935 obj = self.base_klass(value, impl=tag_impl)
2936 with self.assertRaises(NotEnoughData):
2937 obj.decode(obj.encode()[:-1])
2939 @given(data_strategy())
2940 def test_stripped_expl(self, d):
2941 value = d.draw(datetimes(
2942 min_value=self.min_datetime,
2943 max_value=self.max_datetime,
2945 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2946 obj = self.base_klass(value, expl=tag_expl)
2947 with self.assertRaises(NotEnoughData):
2948 obj.decode(obj.encode()[:-1])
2950 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2951 @given(data_strategy())
2952 def test_symmetric(self, d):
2953 values = d.draw(generalized_time_values_strat(
2954 min_datetime=self.min_datetime,
2955 max_datetime=self.max_datetime,
2957 value = d.draw(datetimes(
2958 min_value=self.min_datetime,
2959 max_value=self.max_datetime,
2961 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2962 offset = d.draw(integers(min_value=0))
2963 _, _, _, default, optional, _decoded = values
2964 obj = self.base_klass(
2972 self.assertFalse(obj.expled)
2973 obj_encoded = obj.encode()
2974 obj_expled = obj(value, expl=tag_expl)
2975 self.assertTrue(obj_expled.expled)
2978 obj_expled_encoded = obj_expled.encode()
2979 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2982 self.assertEqual(tail, b"")
2983 self.assertEqual(obj_decoded, obj_expled)
2984 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
2985 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
2986 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2987 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2988 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2990 obj_decoded.expl_llen,
2991 len(len_encode(len(obj_encoded))),
2993 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2994 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2997 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2999 self.assertEqual(obj_decoded.expl_offset, offset)
3002 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3003 base_klass = GeneralizedTime
3005 min_datetime = datetime(1900, 1, 1)
3006 max_datetime = datetime(9999, 12, 31)
3008 def test_go_vectors_invalid(self):
3020 b"-20100102030410Z",
3021 b"2010-0102030410Z",
3022 b"2010-0002030410Z",
3023 b"201001-02030410Z",
3024 b"20100102-030410Z",
3025 b"2010010203-0410Z",
3026 b"201001020304-10Z",
3027 # These ones are INVALID in *DER*, but accepted
3028 # by Go's encoding/asn1
3029 b"20100102030405+0607",
3030 b"20100102030405-0607",
3032 with self.assertRaises(DecodeError) as err:
3033 GeneralizedTime(data)
3036 def test_go_vectors_valid(self):
3038 GeneralizedTime(b"20100102030405Z").todatetime(),
3039 datetime(2010, 1, 2, 3, 4, 5, 0),
3043 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3044 base_klass = UTCTime
3046 min_datetime = datetime(2000, 1, 1)
3047 max_datetime = datetime(2049, 12, 31)
3049 def test_go_vectors_invalid(self):
3075 # These ones are INVALID in *DER*, but accepted
3076 # by Go's encoding/asn1
3077 b"910506164540-0700",
3078 b"910506164540+0730",
3082 with self.assertRaises(DecodeError) as err:
3086 def test_go_vectors_valid(self):
3088 UTCTime(b"910506234540Z").todatetime(),
3089 datetime(1991, 5, 6, 23, 45, 40, 0),
3092 @given(integers(min_value=0, max_value=49))
3093 def test_pre50(self, year):
3095 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3099 @given(integers(min_value=50, max_value=99))
3100 def test_post50(self, year):
3102 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3108 def any_values_strat(draw, do_expl=False):
3109 value = draw(one_of(none(), binary()))
3112 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3113 optional = draw(one_of(none(), booleans()))
3115 draw(integers(min_value=0)),
3116 draw(integers(min_value=0)),
3117 draw(integers(min_value=0)),
3119 return (value, expl, optional, _decoded)
3122 class AnyInherited(Any):
3126 class TestAny(CommonMixin, TestCase):
3129 def test_invalid_value_type(self):
3130 with self.assertRaises(InvalidValueType) as err:
3135 def test_optional(self, optional):
3136 obj = Any(optional=optional)
3137 self.assertEqual(obj.optional, optional)
3140 def test_ready(self, value):
3142 self.assertFalse(obj.ready)
3145 with self.assertRaises(ObjNotReady) as err:
3149 self.assertTrue(obj.ready)
3154 def test_basic(self, value):
3155 integer_encoded = Integer(value).encode()
3157 Any(integer_encoded),
3158 Any(Integer(value)),
3159 Any(Any(Integer(value))),
3161 self.assertSequenceEqual(bytes(obj), integer_encoded)
3163 obj.decode(obj.encode())[0].vlen,
3164 len(integer_encoded),
3168 self.assertSequenceEqual(obj.encode(), integer_encoded)
3170 @given(binary(), binary())
3171 def test_comparison(self, value1, value2):
3172 for klass in (Any, AnyInherited):
3173 obj1 = klass(value1)
3174 obj2 = klass(value2)
3175 self.assertEqual(obj1 == obj2, value1 == value2)
3176 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3178 @given(data_strategy())
3179 def test_call(self, d):
3180 for klass in (Any, AnyInherited):
3186 ) = d.draw(any_values_strat())
3187 obj_initial = klass(
3190 optional_initial or False,
3198 ) = d.draw(any_values_strat(do_expl=True))
3199 obj = obj_initial(value, expl, optional)
3201 value_expected = None if value is None else value
3202 self.assertEqual(obj, value_expected)
3203 self.assertEqual(obj.expl_tag, expl or expl_initial)
3204 if obj.default is None:
3205 optional = optional_initial if optional is None else optional
3206 optional = False if optional is None else optional
3207 self.assertEqual(obj.optional, optional)
3209 def test_simultaneous_impl_expl(self):
3210 # override it, as Any does not have implicit tag
3213 def test_decoded(self):
3214 # override it, as Any does not have implicit tag
3217 @given(any_values_strat())
3218 def test_copy(self, values):
3219 for klass in (Any, AnyInherited):
3220 obj = klass(*values)
3221 obj_copied = obj.copy()
3222 self.assert_copied_basic_fields(obj, obj_copied)
3223 self.assertEqual(obj._value, obj_copied._value)
3225 @given(binary().map(OctetString))
3226 def test_stripped(self, value):
3228 with self.assertRaises(NotEnoughData):
3229 obj.decode(obj.encode()[:-1])
3233 integers(min_value=1).map(tag_ctxc),
3235 def test_stripped_expl(self, value, tag_expl):
3236 obj = Any(value, expl=tag_expl)
3237 with self.assertRaises(NotEnoughData):
3238 obj.decode(obj.encode()[:-1])
3241 integers(min_value=31),
3242 integers(min_value=0),
3245 def test_bad_tag(self, tag, offset, decode_path):
3246 decode_path = tuple(str(i) for i in decode_path)
3247 with self.assertRaises(DecodeError) as err:
3249 tag_encode(tag)[:-1],
3251 decode_path=decode_path,
3254 self.assertEqual(err.exception.offset, offset)
3255 self.assertEqual(err.exception.decode_path, decode_path)
3258 integers(min_value=128),
3259 integers(min_value=0),
3262 def test_bad_len(self, l, offset, decode_path):
3263 decode_path = tuple(str(i) for i in decode_path)
3264 with self.assertRaises(DecodeError) as err:
3266 Any.tag_default + len_encode(l)[:-1],
3268 decode_path=decode_path,
3271 self.assertEqual(err.exception.offset, offset)
3272 self.assertEqual(err.exception.decode_path, decode_path)
3274 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3277 integers().map(lambda x: Integer(x).encode()),
3278 integers(min_value=1).map(tag_ctxc),
3279 integers(min_value=0),
3281 def test_symmetric(self, values, value, tag_expl, offset):
3282 for klass in (Any, AnyInherited):
3283 _, _, optional, _decoded = values
3284 obj = klass(value=value, optional=optional, _decoded=_decoded)
3287 self.assertFalse(obj.expled)
3288 obj_encoded = obj.encode()
3289 obj_expled = obj(value, expl=tag_expl)
3290 self.assertTrue(obj_expled.expled)
3293 obj_expled_encoded = obj_expled.encode()
3294 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
3297 self.assertEqual(tail, b"")
3298 self.assertEqual(obj_decoded, obj_expled)
3299 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3300 self.assertEqual(bytes(obj_decoded), bytes(obj))
3301 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3302 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3303 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3305 obj_decoded.expl_llen,
3306 len(len_encode(len(obj_encoded))),
3308 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3309 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3312 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3314 self.assertEqual(obj_decoded.expl_offset, offset)
3315 self.assertEqual(obj_decoded.tlen, 0)
3316 self.assertEqual(obj_decoded.llen, 0)
3317 self.assertEqual(obj_decoded.vlen, len(value))
3321 def choice_values_strat(draw, value_required=False, schema=None, do_expl=False):
3323 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3324 tags = [tag_encode(tag) for tag in draw(sets(
3325 integers(min_value=0),
3326 min_size=len(names),
3327 max_size=len(names),
3329 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3331 if value_required or draw(booleans()):
3332 value = draw(tuples(
3333 sampled_from([name for name, _ in schema]),
3334 integers().map(Integer),
3338 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3339 default = draw(one_of(
3341 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3343 optional = draw(one_of(none(), booleans()))
3345 draw(integers(min_value=0)),
3346 draw(integers(min_value=0)),
3347 draw(integers(min_value=0)),
3349 return (schema, value, expl, default, optional, _decoded)
3352 class ChoiceInherited(Choice):
3356 class TestChoice(CommonMixin, TestCase):
3358 schema = (("whatever", Boolean()),)
3361 def test_schema_required(self):
3362 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3365 def test_impl_forbidden(self):
3366 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3367 Choice(impl=b"whatever")
3369 def test_invalid_value_type(self):
3370 with self.assertRaises(InvalidValueType) as err:
3371 self.base_klass(123)
3373 with self.assertRaises(ObjUnknown) as err:
3374 self.base_klass(("whenever", Boolean(False)))
3376 with self.assertRaises(InvalidValueType) as err:
3377 self.base_klass(("whatever", Integer(123)))
3381 def test_optional(self, optional):
3382 obj = self.base_klass(
3383 default=self.base_klass(("whatever", Boolean(False))),
3386 self.assertTrue(obj.optional)
3389 def test_ready(self, value):
3390 obj = self.base_klass()
3391 self.assertFalse(obj.ready)
3394 self.assertIsNone(obj["whatever"])
3395 with self.assertRaises(ObjNotReady) as err:
3398 obj["whatever"] = Boolean()
3399 self.assertFalse(obj.ready)
3402 obj["whatever"] = Boolean(value)
3403 self.assertTrue(obj.ready)
3407 @given(booleans(), booleans())
3408 def test_comparison(self, value1, value2):
3409 class WahlInherited(self.base_klass):
3411 for klass in (self.base_klass, WahlInherited):
3412 obj1 = klass(("whatever", Boolean(value1)))
3413 obj2 = klass(("whatever", Boolean(value2)))
3414 self.assertEqual(obj1 == obj2, value1 == value2)
3415 self.assertEqual(obj1 == obj2._value, value1 == value2)
3416 self.assertFalse(obj1 == obj2._value[1])
3418 @given(data_strategy())
3419 def test_call(self, d):
3420 for klass in (Choice, ChoiceInherited):
3428 ) = d.draw(choice_values_strat())
3431 schema = schema_initial
3433 value=value_initial,
3435 default=default_initial,
3436 optional=optional_initial or False,
3437 _decoded=_decoded_initial,
3446 ) = d.draw(choice_values_strat(schema=schema_initial, do_expl=True))
3447 obj = obj_initial(value, expl, default, optional)
3449 value_expected = default if value is None else value
3451 default_initial if value_expected is None
3454 self.assertEqual(obj.choice, value_expected[0])
3455 self.assertEqual(obj.value, int(value_expected[1]))
3456 self.assertEqual(obj.expl_tag, expl or expl_initial)
3457 default_expect = default_initial if default is None else default
3458 if default_expect is not None:
3459 self.assertEqual(obj.default.choice, default_expect[0])
3460 self.assertEqual(obj.default.value, int(default_expect[1]))
3461 if obj.default is None:
3462 optional = optional_initial if optional is None else optional
3463 optional = False if optional is None else optional
3466 self.assertEqual(obj.optional, optional)
3467 self.assertEqual(obj.specs, obj_initial.specs)
3469 def test_simultaneous_impl_expl(self):
3470 # override it, as Any does not have implicit tag
3473 def test_decoded(self):
3474 # override it, as Any does not have implicit tag
3477 @given(choice_values_strat())
3478 def test_copy(self, values):
3479 _schema, value, expl, default, optional, _decoded = values
3481 class Wahl(self.base_klass):
3487 optional=optional or False,
3490 obj_copied = obj.copy()
3491 self.assertIsNone(obj.tag)
3492 self.assertIsNone(obj_copied.tag)
3493 # hack for assert_copied_basic_fields
3494 obj.tag = "whatever"
3495 obj_copied.tag = "whatever"
3496 self.assert_copied_basic_fields(obj, obj_copied)
3497 self.assertEqual(obj._value, obj_copied._value)
3498 self.assertEqual(obj.specs, obj_copied.specs)
3501 def test_stripped(self, value):
3502 obj = self.base_klass(("whatever", Boolean(value)))
3503 with self.assertRaises(NotEnoughData):
3504 obj.decode(obj.encode()[:-1])
3508 integers(min_value=1).map(tag_ctxc),
3510 def test_stripped_expl(self, value, tag_expl):
3511 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3512 with self.assertRaises(NotEnoughData):
3513 obj.decode(obj.encode()[:-1])
3515 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3516 @given(data_strategy())
3517 def test_symmetric(self, d):
3518 _schema, value, _, default, optional, _decoded = d.draw(
3519 choice_values_strat(value_required=True)
3521 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3522 offset = d.draw(integers(min_value=0))
3524 class Wahl(self.base_klass):
3534 self.assertFalse(obj.expled)
3535 obj_encoded = obj.encode()
3536 obj_expled = obj(value, expl=tag_expl)
3537 self.assertTrue(obj_expled.expled)
3540 obj_expled_encoded = obj_expled.encode()
3541 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
3544 self.assertEqual(tail, b"")
3545 self.assertEqual(obj_decoded, obj_expled)
3546 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3547 self.assertEqual(obj_decoded.value, obj_expled.value)
3548 self.assertEqual(obj_decoded.choice, obj.choice)
3549 self.assertEqual(obj_decoded.value, obj.value)
3550 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3551 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3552 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3554 obj_decoded.expl_llen,
3555 len(len_encode(len(obj_encoded))),
3557 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3558 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3561 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3563 self.assertEqual(obj_decoded.expl_offset, offset)
3564 self.assertSequenceEqual(
3566 obj_decoded.value.offset - offset:
3567 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3573 def test_set_get(self, value):
3576 ("erste", Boolean()),
3577 ("zweite", Integer()),
3580 with self.assertRaises(ObjUnknown) as err:
3581 obj["whatever"] = "whenever"
3582 with self.assertRaises(InvalidValueType) as err:
3583 obj["zweite"] = Boolean(False)
3584 obj["zweite"] = Integer(value)
3586 with self.assertRaises(ObjUnknown) as err:
3589 self.assertIsNone(obj["erste"])
3590 self.assertEqual(obj["zweite"], Integer(value))
3592 def test_tag_mismatch(self):
3595 ("erste", Boolean()),
3597 int_encoded = Integer(123).encode()
3598 bool_encoded = Boolean(False).encode()
3600 obj.decode(bool_encoded)
3601 with self.assertRaises(TagMismatch):
3602 obj.decode(int_encoded)
3606 def seq_values_strat(draw, seq_klass, do_expl=False):
3608 if draw(booleans()):
3611 k: v for k, v in draw(dictionaries(
3614 booleans().map(Boolean),
3615 integers().map(Integer),
3620 if draw(booleans()):
3621 schema = list(draw(dictionaries(
3624 booleans().map(Boolean),
3625 integers().map(Integer),
3631 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3633 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3635 if draw(booleans()):
3636 default = seq_klass()
3638 k: v for k, v in draw(dictionaries(
3641 booleans().map(Boolean),
3642 integers().map(Integer),
3646 optional = draw(one_of(none(), booleans()))
3648 draw(integers(min_value=0)),
3649 draw(integers(min_value=0)),
3650 draw(integers(min_value=0)),
3652 return (value, schema, impl, expl, default, optional, _decoded)
3656 def sequence_strat(draw, seq_klass):
3657 inputs = draw(lists(
3659 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
3660 tuples(just(Integer), integers(), one_of(none(), integers())),
3665 integers(min_value=1),
3666 min_size=len(inputs),
3667 max_size=len(inputs),
3670 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3671 for tag, expled in zip(tags, draw(lists(
3673 min_size=len(inputs),
3674 max_size=len(inputs),
3678 for i, optional in enumerate(draw(lists(
3679 sampled_from(("required", "optional", "empty")),
3680 min_size=len(inputs),
3681 max_size=len(inputs),
3683 if optional in ("optional", "empty"):
3684 inits[i]["optional"] = True
3685 if optional == "empty":
3687 empties = set(empties)
3688 names = list(draw(sets(
3690 min_size=len(inputs),
3691 max_size=len(inputs),
3694 for i, (klass, value, default) in enumerate(inputs):
3695 schema.append((names[i], klass(default=default, **inits[i])))
3696 seq_name = draw(text_letters())
3697 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3700 for i, (klass, value, default) in enumerate(inputs):
3707 "default_value": None if spec.default is None else default,
3711 expect["optional"] = True
3713 expect["presented"] = True
3714 expect["value"] = value
3716 expect["optional"] = True
3717 if default is not None and default == value:
3718 expect["presented"] = False
3719 seq[name] = klass(value)
3720 expects.append(expect)
3725 def sequences_strat(draw, seq_klass):
3726 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
3728 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3729 for tag, expled in zip(tags, draw(lists(
3736 i for i, is_default in enumerate(draw(lists(
3742 names = list(draw(sets(
3747 seq_expectses = draw(lists(
3748 sequence_strat(seq_klass=seq_klass),
3752 seqs = [seq for seq, _ in seq_expectses]
3754 for i, (name, seq) in enumerate(zip(names, seqs)):
3757 seq(default=(seq if i in defaulted else None), **inits[i]),
3759 seq_name = draw(text_letters())
3760 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3763 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
3766 "expects": expects_inner,
3769 seq_outer[name] = seq_inner
3770 if seq_outer.specs[name].default is None:
3771 expect["presented"] = True
3772 expect_outers.append(expect)
3773 return seq_outer, expect_outers
3776 class SeqMixing(object):
3777 def test_invalid_value_type(self):
3778 with self.assertRaises(InvalidValueType) as err:
3779 self.base_klass((1, 2, 3))
3782 def test_invalid_value_type_set(self):
3783 class Seq(self.base_klass):
3784 schema = (("whatever", Boolean()),)
3786 with self.assertRaises(InvalidValueType) as err:
3787 seq["whatever"] = Integer(123)
3791 def test_optional(self, optional):
3792 obj = self.base_klass(default=self.base_klass(), optional=optional)
3793 self.assertTrue(obj.optional)
3795 @given(data_strategy())
3796 def test_ready(self, d):
3798 str(i): v for i, v in enumerate(d.draw(lists(
3805 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
3812 for name in d.draw(permutations(
3813 list(ready.keys()) + list(non_ready.keys()),
3815 schema_input.append((name, Boolean()))
3817 class Seq(self.base_klass):
3818 schema = tuple(schema_input)
3820 for name in ready.keys():
3822 seq[name] = Boolean()
3823 self.assertFalse(seq.ready)
3826 for name, value in ready.items():
3827 seq[name] = Boolean(value)
3828 self.assertFalse(seq.ready)
3831 with self.assertRaises(ObjNotReady) as err:
3834 for name, value in non_ready.items():
3835 seq[name] = Boolean(value)
3836 self.assertTrue(seq.ready)
3840 @given(data_strategy())
3841 def test_call(self, d):
3842 class SeqInherited(self.base_klass):
3844 for klass in (self.base_klass, SeqInherited):
3853 ) = d.draw(seq_values_strat(seq_klass=klass))
3854 obj_initial = klass(
3860 optional_initial or False,
3871 ) = d.draw(seq_values_strat(
3873 do_expl=impl_initial is None,
3875 obj = obj_initial(value, impl, expl, default, optional)
3876 value_expected = default if value is None else value
3878 default_initial if value_expected is None
3881 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
3882 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3883 self.assertEqual(obj.expl_tag, expl or expl_initial)
3885 {} if obj.default is None else obj.default._value,
3886 getattr(default_initial if default is None else default, "_value", {}),
3888 if obj.default is None:
3889 optional = optional_initial if optional is None else optional
3890 optional = False if optional is None else optional
3893 self.assertEqual(list(obj.specs.items()), schema_initial or [])
3894 self.assertEqual(obj.optional, optional)
3896 @given(data_strategy())
3897 def test_copy(self, d):
3898 class SeqInherited(self.base_klass):
3900 for klass in (self.base_klass, SeqInherited):
3901 values = d.draw(seq_values_strat(seq_klass=klass))
3902 obj = klass(*values)
3903 obj_copied = obj.copy()
3904 self.assert_copied_basic_fields(obj, obj_copied)
3905 self.assertEqual(obj.specs, obj_copied.specs)
3906 self.assertEqual(obj._value, obj_copied._value)
3908 @given(data_strategy())
3909 def test_stripped(self, d):
3910 value = d.draw(integers())
3911 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3913 class Seq(self.base_klass):
3915 schema = (("whatever", Integer()),)
3917 seq["whatever"] = Integer(value)
3918 with self.assertRaises(NotEnoughData):
3919 seq.decode(seq.encode()[:-1])
3921 @given(data_strategy())
3922 def test_stripped_expl(self, d):
3923 value = d.draw(integers())
3924 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3926 class Seq(self.base_klass):
3928 schema = (("whatever", Integer()),)
3930 seq["whatever"] = Integer(value)
3931 with self.assertRaises(NotEnoughData):
3932 seq.decode(seq.encode()[:-1])
3934 @given(binary(min_size=2))
3935 def test_non_tag_mismatch_raised(self, junk):
3937 _, _, len_encoded = tag_strip(memoryview(junk))
3938 len_decode(len_encoded)
3944 class Seq(self.base_klass):
3946 ("whatever", Integer()),
3948 ("whenever", Integer()),
3951 seq["whatever"] = Integer(123)
3952 seq["junk"] = Any(junk)
3953 seq["whenever"] = Integer(123)
3954 with self.assertRaises(DecodeError):
3955 seq.decode(seq.encode())
3958 integers(min_value=31),
3959 integers(min_value=0),
3962 def test_bad_tag(self, tag, offset, decode_path):
3963 decode_path = tuple(str(i) for i in decode_path)
3964 with self.assertRaises(DecodeError) as err:
3965 self.base_klass().decode(
3966 tag_encode(tag)[:-1],
3968 decode_path=decode_path,
3971 self.assertEqual(err.exception.offset, offset)
3972 self.assertEqual(err.exception.decode_path, decode_path)
3975 integers(min_value=128),
3976 integers(min_value=0),
3979 def test_bad_len(self, l, offset, decode_path):
3980 decode_path = tuple(str(i) for i in decode_path)
3981 with self.assertRaises(DecodeError) as err:
3982 self.base_klass().decode(
3983 self.base_klass.tag_default + len_encode(l)[:-1],
3985 decode_path=decode_path,
3988 self.assertEqual(err.exception.offset, offset)
3989 self.assertEqual(err.exception.decode_path, decode_path)
3991 def _assert_expects(self, seq, expects):
3992 for expect in expects:
3994 seq.specs[expect["name"]].optional,
3997 if expect["default_value"] is not None:
3999 seq.specs[expect["name"]].default,
4000 expect["default_value"],
4002 if expect["presented"]:
4003 self.assertIn(expect["name"], seq)
4004 self.assertEqual(seq[expect["name"]], expect["value"])
4006 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4007 @given(data_strategy())
4008 def test_symmetric(self, d):
4009 seq, expects = d.draw(sequence_strat(seq_klass=self.base_klass))
4010 self.assertTrue(seq.ready)
4011 self.assertFalse(seq.decoded)
4012 self._assert_expects(seq, expects)
4015 seq_encoded = seq.encode()
4016 seq_decoded, tail = seq.decode(seq_encoded)
4017 self.assertEqual(tail, b"")
4018 self.assertTrue(seq.ready)
4019 self._assert_expects(seq_decoded, expects)
4020 self.assertEqual(seq, seq_decoded)
4021 self.assertEqual(seq_decoded.encode(), seq_encoded)
4022 for expect in expects:
4023 if not expect["presented"]:
4024 self.assertNotIn(expect["name"], seq_decoded)
4026 self.assertIn(expect["name"], seq_decoded)
4027 obj = seq_decoded[expect["name"]]
4028 self.assertTrue(obj.decoded)
4029 offset = obj.expl_offset if obj.expled else obj.offset
4030 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4031 self.assertSequenceEqual(
4032 seq_encoded[offset:offset + tlvlen],
4036 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4037 @given(data_strategy())
4038 def test_symmetric_with_seq(self, d):
4039 seq, expect_outers = d.draw(sequences_strat(seq_klass=self.base_klass))
4040 self.assertTrue(seq.ready)
4041 seq_encoded = seq.encode()
4042 seq_decoded, tail = seq.decode(seq_encoded)
4043 self.assertEqual(tail, b"")
4044 self.assertTrue(seq.ready)
4045 self.assertEqual(seq, seq_decoded)
4046 self.assertEqual(seq_decoded.encode(), seq_encoded)
4047 for expect_outer in expect_outers:
4048 if not expect_outer["presented"]:
4049 self.assertNotIn(expect_outer["name"], seq_decoded)
4051 self.assertIn(expect_outer["name"], seq_decoded)
4052 obj = seq_decoded[expect_outer["name"]]
4053 self.assertTrue(obj.decoded)
4054 offset = obj.expl_offset if obj.expled else obj.offset
4055 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4056 self.assertSequenceEqual(
4057 seq_encoded[offset:offset + tlvlen],
4060 self._assert_expects(obj, expect_outer["expects"])
4062 @given(data_strategy())
4063 def test_default_disappears(self, d):
4064 _schema = list(d.draw(dictionaries(
4066 sets(integers(), min_size=2, max_size=2),
4070 class Seq(self.base_klass):
4072 (n, Integer(default=d))
4073 for n, (_, d) in _schema
4076 for name, (value, _) in _schema:
4077 seq[name] = Integer(value)
4078 self.assertEqual(len(seq._value), len(_schema))
4079 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4080 self.assertGreater(len(seq.encode()), len(empty_seq))
4081 for name, (_, default) in _schema:
4082 seq[name] = Integer(default)
4083 self.assertEqual(len(seq._value), 0)
4084 self.assertSequenceEqual(seq.encode(), empty_seq)
4086 @given(data_strategy())
4087 def test_encoded_default_accepted(self, d):
4088 _schema = list(d.draw(dictionaries(
4093 tags = [tag_encode(tag) for tag in d.draw(sets(
4094 integers(min_value=0),
4095 min_size=len(_schema),
4096 max_size=len(_schema),
4099 class SeqWithoutDefault(self.base_klass):
4101 (n, Integer(impl=t))
4102 for (n, _), t in zip(_schema, tags)
4104 seq_without_default = SeqWithoutDefault()
4105 for name, value in _schema:
4106 seq_without_default[name] = Integer(value)
4107 seq_encoded = seq_without_default.encode()
4109 class SeqWithDefault(self.base_klass):
4111 (n, Integer(default=v, impl=t))
4112 for (n, v), t in zip(_schema, tags)
4114 seq_with_default = SeqWithDefault()
4115 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4116 for name, value in _schema:
4117 self.assertEqual(seq_decoded[name], seq_with_default[name])
4118 self.assertEqual(seq_decoded[name], value)
4120 @given(data_strategy())
4121 def test_missing_from_spec(self, d):
4122 names = list(d.draw(sets(text_letters(), min_size=2)))
4123 tags = [tag_encode(tag) for tag in d.draw(sets(
4124 integers(min_value=0),
4125 min_size=len(names),
4126 max_size=len(names),
4128 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4130 class SeqFull(self.base_klass):
4131 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4132 seq_full = SeqFull()
4133 for i, name in enumerate(names):
4134 seq_full[name] = Integer(i)
4135 seq_encoded = seq_full.encode()
4136 altered = names_tags[:-2] + names_tags[-1:]
4138 class SeqMissing(self.base_klass):
4139 schema = [(n, Integer(impl=t)) for n, t in altered]
4140 seq_missing = SeqMissing()
4141 with self.assertRaises(TagMismatch):
4142 seq_missing.decode(seq_encoded)
4145 class TestSequence(SeqMixing, CommonMixin, TestCase):
4146 base_klass = Sequence
4152 def test_remaining(self, value, junk):
4153 class Seq(Sequence):
4155 ("whatever", Integer()),
4157 int_encoded = Integer(value).encode()
4159 Sequence.tag_default,
4160 len_encode(len(int_encoded + junk)),
4163 with assertRaisesRegex(self, DecodeError, "remaining"):
4164 Seq().decode(junked)
4166 @given(sets(text_letters(), min_size=2))
4167 def test_obj_unknown(self, names):
4168 missing = names.pop()
4170 class Seq(Sequence):
4171 schema = [(n, Boolean()) for n in names]
4173 with self.assertRaises(ObjUnknown) as err:
4176 with self.assertRaises(ObjUnknown) as err:
4177 seq[missing] = Boolean()
4181 class TestSet(SeqMixing, CommonMixin, TestCase):
4184 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4185 @given(data_strategy())
4186 def test_sorted(self, d):
4188 tag_encode(tag) for tag in
4189 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4193 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4195 for name, _ in Seq.schema:
4196 seq[name] = OctetString(b"")
4197 seq_encoded = seq.encode()
4198 seq_decoded, _ = seq.decode(seq_encoded)
4199 self.assertSequenceEqual(
4200 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4201 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4206 def seqof_values_strat(draw, schema=None, do_expl=False):
4208 schema = draw(sampled_from((Boolean(), Integer())))
4209 bound_min, bound_max = sorted(draw(sets(
4210 integers(min_value=0, max_value=10),
4214 if isinstance(schema, Boolean):
4215 values_generator = booleans().map(Boolean)
4216 elif isinstance(schema, Integer):
4217 values_generator = integers().map(Integer)
4218 values_generator = lists(
4223 values = draw(one_of(none(), values_generator))
4227 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4229 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4230 default = draw(one_of(none(), values_generator))
4231 optional = draw(one_of(none(), booleans()))
4233 draw(integers(min_value=0)),
4234 draw(integers(min_value=0)),
4235 draw(integers(min_value=0)),
4240 (bound_min, bound_max),
4249 class SeqOfMixing(object):
4250 def test_invalid_value_type(self):
4251 with self.assertRaises(InvalidValueType) as err:
4252 self.base_klass(123)
4255 def test_invalid_values_type(self):
4256 class SeqOf(self.base_klass):
4258 with self.assertRaises(InvalidValueType) as err:
4259 SeqOf([Integer(123), Boolean(False), Integer(234)])
4262 def test_schema_required(self):
4263 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4264 self.base_klass.__mro__[1]()
4266 @given(booleans(), booleans(), binary(), binary())
4267 def test_comparison(self, value1, value2, tag1, tag2):
4268 class SeqOf(self.base_klass):
4270 obj1 = SeqOf([Boolean(value1)])
4271 obj2 = SeqOf([Boolean(value2)])
4272 self.assertEqual(obj1 == obj2, value1 == value2)
4273 self.assertEqual(obj1 == list(obj2), value1 == value2)
4274 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4275 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4276 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4277 self.assertEqual(obj1 == obj2, tag1 == tag2)
4279 @given(lists(booleans()))
4280 def test_iter(self, values):
4281 class SeqOf(self.base_klass):
4283 obj = SeqOf([Boolean(value) for value in values])
4284 self.assertEqual(len(obj), len(values))
4285 for i, value in enumerate(obj):
4286 self.assertEqual(value, values[i])
4288 @given(data_strategy())
4289 def test_ready(self, d):
4290 ready = [Integer(v) for v in d.draw(lists(
4297 range(d.draw(integers(min_value=1, max_value=5)))
4300 class SeqOf(self.base_klass):
4302 values = d.draw(permutations(ready + non_ready))
4304 for value in values:
4306 self.assertFalse(seqof.ready)
4309 with self.assertRaises(ObjNotReady) as err:
4312 for i, value in enumerate(values):
4313 self.assertEqual(seqof[i], value)
4314 if not seqof[i].ready:
4315 seqof[i] = Integer(i)
4316 self.assertTrue(seqof.ready)
4320 def test_spec_mismatch(self):
4321 class SeqOf(self.base_klass):
4324 seqof.append(Integer(123))
4325 with self.assertRaises(ValueError):
4326 seqof.append(Boolean(False))
4327 with self.assertRaises(ValueError):
4328 seqof[0] = Boolean(False)
4330 @given(data_strategy())
4331 def test_bounds_satisfied(self, d):
4332 class SeqOf(self.base_klass):
4334 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4335 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4336 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4337 SeqOf(value=value, bounds=(bound_min, bound_max))
4339 @given(data_strategy())
4340 def test_bounds_unsatisfied(self, d):
4341 class SeqOf(self.base_klass):
4343 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4344 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4345 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4346 with self.assertRaises(BoundsError) as err:
4347 SeqOf(value=value, bounds=(bound_min, bound_max))
4349 value = [Boolean()] * d.draw(integers(
4350 min_value=bound_max + 1,
4351 max_value=bound_max + 10,
4353 with self.assertRaises(BoundsError) as err:
4354 SeqOf(value=value, bounds=(bound_min, bound_max))
4357 @given(integers(min_value=1, max_value=10))
4358 def test_out_of_bounds(self, bound_max):
4359 class SeqOf(self.base_klass):
4361 bounds = (0, bound_max)
4363 for _ in range(bound_max):
4364 seqof.append(Integer(123))
4365 with self.assertRaises(BoundsError):
4366 seqof.append(Integer(123))
4368 @given(data_strategy())
4369 def test_call(self, d):
4379 ) = d.draw(seqof_values_strat())
4381 class SeqOf(self.base_klass):
4382 schema = schema_initial
4383 obj_initial = SeqOf(
4384 value=value_initial,
4385 bounds=bounds_initial,
4388 default=default_initial,
4389 optional=optional_initial or False,
4390 _decoded=_decoded_initial,
4401 ) = d.draw(seqof_values_strat(
4402 schema=schema_initial,
4403 do_expl=impl_initial is None,
4405 if (default is None) and (obj_initial.default is not None):
4408 (bounds is None) and
4409 (value is not None) and
4410 (bounds_initial is not None) and
4411 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4415 (bounds is None) and
4416 (default is not None) and
4417 (bounds_initial is not None) and
4418 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4430 value_expected = default if value is None else value
4432 default_initial if value_expected is None
4435 value_expected = () if value_expected is None else value_expected
4436 self.assertEqual(obj, value_expected)
4437 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4438 self.assertEqual(obj.expl_tag, expl or expl_initial)
4441 default_initial if default is None else default,
4443 if obj.default is None:
4444 optional = optional_initial if optional is None else optional
4445 optional = False if optional is None else optional
4448 self.assertEqual(obj.optional, optional)
4450 (obj._bound_min, obj._bound_max),
4451 bounds or bounds_initial or (0, float("+inf")),
4454 @given(seqof_values_strat())
4455 def test_copy(self, values):
4456 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4458 class SeqOf(self.base_klass):
4466 optional=optional or False,
4469 obj_copied = obj.copy()
4470 self.assert_copied_basic_fields(obj, obj_copied)
4471 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4472 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4473 self.assertEqual(obj._value, obj_copied._value)
4477 integers(min_value=1).map(tag_encode),
4479 def test_stripped(self, values, tag_impl):
4480 class SeqOf(self.base_klass):
4481 schema = OctetString()
4482 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4483 with self.assertRaises(NotEnoughData):
4484 obj.decode(obj.encode()[:-1])
4488 integers(min_value=1).map(tag_ctxc),
4490 def test_stripped_expl(self, values, tag_expl):
4491 class SeqOf(self.base_klass):
4492 schema = OctetString()
4493 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4494 with self.assertRaises(NotEnoughData):
4495 obj.decode(obj.encode()[:-1])
4498 integers(min_value=31),
4499 integers(min_value=0),
4502 def test_bad_tag(self, tag, offset, decode_path):
4503 decode_path = tuple(str(i) for i in decode_path)
4504 with self.assertRaises(DecodeError) as err:
4505 self.base_klass().decode(
4506 tag_encode(tag)[:-1],
4508 decode_path=decode_path,
4511 self.assertEqual(err.exception.offset, offset)
4512 self.assertEqual(err.exception.decode_path, decode_path)
4515 integers(min_value=128),
4516 integers(min_value=0),
4519 def test_bad_len(self, l, offset, decode_path):
4520 decode_path = tuple(str(i) for i in decode_path)
4521 with self.assertRaises(DecodeError) as err:
4522 self.base_klass().decode(
4523 self.base_klass.tag_default + len_encode(l)[:-1],
4525 decode_path=decode_path,
4528 self.assertEqual(err.exception.offset, offset)
4529 self.assertEqual(err.exception.decode_path, decode_path)
4531 @given(binary(min_size=1))
4532 def test_tag_mismatch(self, impl):
4533 assume(impl != self.base_klass.tag_default)
4534 with self.assertRaises(TagMismatch):
4535 self.base_klass(impl=impl).decode(self.base_klass().encode())
4537 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4539 seqof_values_strat(schema=Integer()),
4540 lists(integers().map(Integer)),
4541 integers(min_value=1).map(tag_ctxc),
4542 integers(min_value=0),
4544 def test_symmetric(self, values, value, tag_expl, offset):
4545 _, _, _, _, _, default, optional, _decoded = values
4547 class SeqOf(self.base_klass):
4557 self.assertFalse(obj.expled)
4558 obj_encoded = obj.encode()
4559 obj_expled = obj(value, expl=tag_expl)
4560 self.assertTrue(obj_expled.expled)
4563 obj_expled_encoded = obj_expled.encode()
4564 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
4567 self.assertEqual(tail, b"")
4568 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
4569 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4570 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4571 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4573 obj_decoded.expl_llen,
4574 len(len_encode(len(obj_encoded))),
4576 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4577 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4580 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4582 self.assertEqual(obj_decoded.expl_offset, offset)
4583 for obj_inner in obj_decoded:
4584 self.assertIn(obj_inner, obj_decoded)
4585 self.assertSequenceEqual(
4588 obj_inner.offset - offset:
4589 obj_inner.offset + obj_inner.tlvlen - offset
4594 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
4595 class SeqOf(SequenceOf):
4599 def _test_symmetric_compare_objs(self, obj1, obj2):
4600 self.assertEqual(obj1, obj2)
4601 self.assertSequenceEqual(list(obj1), list(obj2))
4604 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
4609 def _test_symmetric_compare_objs(self, obj1, obj2):
4610 self.assertSetEqual(
4611 set(int(v) for v in obj1),
4612 set(int(v) for v in obj2),
4615 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4616 @given(data_strategy())
4617 def test_sorted(self, d):
4618 values = [OctetString(v) for v in d.draw(lists(binary()))]
4621 schema = OctetString()
4623 seq_encoded = seq.encode()
4624 seq_decoded, _ = seq.decode(seq_encoded)
4625 self.assertSequenceEqual(
4626 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4627 b"".join(sorted([v.encode() for v in values])),
4631 class TestGoMarshalVectors(TestCase):
4633 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
4634 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
4635 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
4636 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
4637 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
4639 class Seq(Sequence):
4641 ("erste", Integer()),
4642 ("zweite", Integer(optional=True))
4645 seq["erste"] = Integer(64)
4646 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4647 seq["erste"] = Integer(0x123456)
4648 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
4649 seq["erste"] = Integer(64)
4650 seq["zweite"] = Integer(65)
4651 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
4653 class NestedSeq(Sequence):
4657 seq["erste"] = Integer(127)
4658 seq["zweite"] = None
4659 nested = NestedSeq()
4660 nested["nest"] = seq
4661 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
4663 self.assertSequenceEqual(
4664 OctetString(b"\x01\x02\x03").encode(),
4665 hexdec("0403010203"),
4668 class Seq(Sequence):
4670 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
4673 seq["erste"] = Integer(64)
4674 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
4676 class Seq(Sequence):
4678 ("erste", Integer(expl=tag_ctxc(5))),
4681 seq["erste"] = Integer(64)
4682 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
4684 class Seq(Sequence):
4687 impl=tag_encode(0, klass=TagClassContext),
4692 seq["erste"] = Null()
4693 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
4695 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4697 self.assertSequenceEqual(
4698 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
4699 hexdec("170d3730303130313030303030305a"),
4701 self.assertSequenceEqual(
4702 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
4703 hexdec("170d3039313131353232353631365a"),
4705 self.assertSequenceEqual(
4706 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
4707 hexdec("180f32313030303430353132303130315a"),
4710 class Seq(Sequence):
4712 ("erste", GeneralizedTime()),
4715 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
4716 self.assertSequenceEqual(
4718 hexdec("3011180f32303039313131353232353631365a"),
4721 self.assertSequenceEqual(
4722 BitString((1, b"\x80")).encode(),
4725 self.assertSequenceEqual(
4726 BitString((12, b"\x81\xF0")).encode(),
4727 hexdec("03030481f0"),
4730 self.assertSequenceEqual(
4731 ObjectIdentifier("1.2.3.4").encode(),
4732 hexdec("06032a0304"),
4734 self.assertSequenceEqual(
4735 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
4736 hexdec("06092a864888932d010105"),
4738 self.assertSequenceEqual(
4739 ObjectIdentifier("2.100.3").encode(),
4740 hexdec("0603813403"),
4743 self.assertSequenceEqual(
4744 PrintableString("test").encode(),
4745 hexdec("130474657374"),
4747 self.assertSequenceEqual(
4748 PrintableString("x" * 127).encode(),
4749 hexdec("137F" + "78" * 127),
4751 self.assertSequenceEqual(
4752 PrintableString("x" * 128).encode(),
4753 hexdec("138180" + "78" * 128),
4755 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
4757 class Seq(Sequence):
4759 ("erste", IA5String()),
4762 seq["erste"] = IA5String("test")
4763 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
4765 class Seq(Sequence):
4767 ("erste", PrintableString()),
4770 seq["erste"] = PrintableString("test")
4771 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
4772 seq["erste"] = PrintableString("test*")
4773 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
4775 class Seq(Sequence):
4777 ("erste", Any(optional=True)),
4778 ("zweite", Integer()),
4781 seq["zweite"] = Integer(64)
4782 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4787 seq.append(Integer(10))
4788 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
4790 class _SeqOf(SequenceOf):
4791 schema = PrintableString()
4793 class SeqOf(SequenceOf):
4796 _seqof.append(PrintableString("1"))
4798 seqof.append(_seqof)
4799 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
4801 class Seq(Sequence):
4803 ("erste", Integer(default=1)),
4806 seq["erste"] = Integer(0)
4807 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
4808 seq["erste"] = Integer(1)
4809 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4810 seq["erste"] = Integer(2)
4811 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
4814 class TestPP(TestCase):
4815 @given(data_strategy())
4816 def test_oid_printing(self, d):
4818 str(ObjectIdentifier(k)): v * 2
4819 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
4821 chosen = d.draw(sampled_from(sorted(oids)))
4822 chosen_id = oids[chosen]
4823 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
4824 self.assertNotIn(chosen_id, pp_console_row(pp))
4825 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
4828 class TestAutoAddSlots(TestCase):
4830 class Inher(Integer):
4833 with self.assertRaises(AttributeError):
4835 inher.unexistent = "whatever"