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):
298 self.assertSequenceEqual(obj.impl, impl_tag)
299 self.assertFalse(obj.expled)
302 def test_expl_inherited(self, expl_tag):
303 class Inherited(self.base_klass):
307 self.assertSequenceEqual(obj.expl, expl_tag)
308 self.assertTrue(obj.expled)
310 def assert_copied_basic_fields(self, obj, obj_copied):
311 self.assertEqual(obj, obj_copied)
312 self.assertSequenceEqual(obj.tag, obj_copied.tag)
313 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
314 self.assertEqual(obj.default, obj_copied.default)
315 self.assertEqual(obj.optional, obj_copied.optional)
316 self.assertEqual(obj.offset, obj_copied.offset)
317 self.assertEqual(obj.llen, obj_copied.llen)
318 self.assertEqual(obj.vlen, obj_copied.vlen)
322 def boolean_values_strat(draw, do_expl=False):
323 value = draw(one_of(none(), booleans()))
327 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
329 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
330 default = draw(one_of(none(), booleans()))
331 optional = draw(one_of(none(), booleans()))
333 draw(integers(min_value=0)),
334 draw(integers(min_value=0)),
335 draw(integers(min_value=0)),
337 return (value, impl, expl, default, optional, _decoded)
340 class BooleanInherited(Boolean):
344 class TestBoolean(CommonMixin, TestCase):
347 def test_invalid_value_type(self):
348 with self.assertRaises(InvalidValueType) as err:
353 def test_optional(self, optional):
354 obj = Boolean(default=Boolean(False), optional=optional)
355 self.assertTrue(obj.optional)
358 def test_ready(self, value):
360 self.assertFalse(obj.ready)
363 with self.assertRaises(ObjNotReady) as err:
367 self.assertTrue(obj.ready)
371 @given(booleans(), booleans(), binary(), binary())
372 def test_comparison(self, value1, value2, tag1, tag2):
373 for klass in (Boolean, BooleanInherited):
376 self.assertEqual(obj1 == obj2, value1 == value2)
377 self.assertEqual(obj1 == bool(obj2), value1 == value2)
378 obj1 = klass(value1, impl=tag1)
379 obj2 = klass(value1, impl=tag2)
380 self.assertEqual(obj1 == obj2, tag1 == tag2)
382 @given(data_strategy())
383 def test_call(self, d):
384 for klass in (Boolean, BooleanInherited):
392 ) = d.draw(boolean_values_strat())
398 optional_initial or False,
408 ) = d.draw(boolean_values_strat(do_expl=impl_initial is None))
409 obj = obj_initial(value, impl, expl, default, optional)
411 value_expected = default if value is None else value
413 default_initial if value_expected is None
416 self.assertEqual(obj, value_expected)
417 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
418 self.assertEqual(obj.expl_tag, expl or expl_initial)
421 default_initial if default is None else default,
423 if obj.default is None:
424 optional = optional_initial if optional is None else optional
425 optional = False if optional is None else optional
428 self.assertEqual(obj.optional, optional)
430 @given(boolean_values_strat())
431 def test_copy(self, values):
432 for klass in (Boolean, BooleanInherited):
434 obj_copied = obj.copy()
435 self.assert_copied_basic_fields(obj, obj_copied)
439 integers(min_value=1).map(tag_encode),
441 def test_stripped(self, value, tag_impl):
442 obj = Boolean(value, impl=tag_impl)
443 with self.assertRaises(NotEnoughData):
444 obj.decode(obj.encode()[:-1])
448 integers(min_value=1).map(tag_ctxc),
450 def test_stripped_expl(self, value, tag_expl):
451 obj = Boolean(value, expl=tag_expl)
452 with self.assertRaises(NotEnoughData):
453 obj.decode(obj.encode()[:-1])
456 integers(min_value=31),
457 integers(min_value=0),
460 def test_bad_tag(self, tag, offset, decode_path):
461 decode_path = tuple(str(i) for i in decode_path)
462 with self.assertRaises(DecodeError) as err:
464 tag_encode(tag)[:-1],
466 decode_path=decode_path,
469 self.assertEqual(err.exception.offset, offset)
470 self.assertEqual(err.exception.decode_path, decode_path)
473 integers(min_value=31),
474 integers(min_value=0),
477 def test_bad_expl_tag(self, tag, offset, decode_path):
478 decode_path = tuple(str(i) for i in decode_path)
479 with self.assertRaises(DecodeError) as err:
480 Boolean(expl=Boolean.tag_default).decode(
481 tag_encode(tag)[:-1],
483 decode_path=decode_path,
486 self.assertEqual(err.exception.offset, offset)
487 self.assertEqual(err.exception.decode_path, decode_path)
490 integers(min_value=128),
491 integers(min_value=0),
494 def test_bad_len(self, l, offset, decode_path):
495 decode_path = tuple(str(i) for i in decode_path)
496 with self.assertRaises(DecodeError) as err:
498 Boolean.tag_default + len_encode(l)[:-1],
500 decode_path=decode_path,
503 self.assertEqual(err.exception.offset, offset)
504 self.assertEqual(err.exception.decode_path, decode_path)
507 integers(min_value=128),
508 integers(min_value=0),
511 def test_bad_expl_len(self, l, offset, decode_path):
512 decode_path = tuple(str(i) for i in decode_path)
513 with self.assertRaises(DecodeError) as err:
514 Boolean(expl=Boolean.tag_default).decode(
515 Boolean.tag_default + len_encode(l)[:-1],
517 decode_path=decode_path,
520 self.assertEqual(err.exception.offset, offset)
521 self.assertEqual(err.exception.decode_path, decode_path)
523 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
525 boolean_values_strat(),
527 integers(min_value=1).map(tag_ctxc),
528 integers(min_value=0),
530 def test_symmetric(self, values, value, tag_expl, offset):
531 for klass in (Boolean, BooleanInherited):
532 _, _, _, default, optional, _decoded = values
541 self.assertFalse(obj.expled)
542 obj_encoded = obj.encode()
543 obj_expled = obj(value, expl=tag_expl)
544 self.assertTrue(obj_expled.expled)
547 obj_expled_encoded = obj_expled.encode()
548 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
551 self.assertEqual(tail, b"")
552 self.assertEqual(obj_decoded, obj_expled)
553 self.assertNotEqual(obj_decoded, obj)
554 self.assertEqual(bool(obj_decoded), bool(obj_expled))
555 self.assertEqual(bool(obj_decoded), bool(obj))
556 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
557 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
558 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
560 obj_decoded.expl_llen,
561 len(len_encode(len(obj_encoded))),
563 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
564 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
567 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
569 self.assertEqual(obj_decoded.expl_offset, offset)
571 @given(integers(min_value=2))
572 def test_invalid_len(self, l):
573 with self.assertRaises(InvalidLength):
574 Boolean().decode(b"".join((
580 @given(integers(min_value=0 + 1, max_value=255 - 1))
581 def test_invalid_value(self, value):
582 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
583 Boolean().decode(b"".join((
591 def integer_values_strat(draw, do_expl=False):
592 bound_min, value, default, bound_max = sorted(draw(sets(
601 _specs = draw(sets(text_letters()))
604 min_size=len(_specs),
605 max_size=len(_specs),
607 _specs = list(zip(_specs, values))
610 bounds = (bound_min, bound_max)
614 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
616 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
619 optional = draw(one_of(none(), booleans()))
621 draw(integers(min_value=0)),
622 draw(integers(min_value=0)),
623 draw(integers(min_value=0)),
625 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
628 class IntegerInherited(Integer):
632 class TestInteger(CommonMixin, TestCase):
635 def test_invalid_value_type(self):
636 with self.assertRaises(InvalidValueType) as err:
640 @given(sets(text_letters(), min_size=2))
641 def test_unknown_name(self, names_input):
642 missing = names_input.pop()
646 schema = [(n, 123) for n in names_input]
647 with self.assertRaises(ObjUnknown) as err:
651 @given(sets(text_letters(), min_size=2))
652 def test_known_name(self, names_input):
655 schema = [(n, 123) for n in names_input]
656 Int(names_input.pop())
659 def test_optional(self, optional):
660 obj = Integer(default=Integer(0), optional=optional)
661 self.assertTrue(obj.optional)
664 def test_ready(self, value):
666 self.assertFalse(obj.ready)
669 with self.assertRaises(ObjNotReady) as err:
673 self.assertTrue(obj.ready)
678 @given(integers(), integers(), binary(), binary())
679 def test_comparison(self, value1, value2, tag1, tag2):
680 for klass in (Integer, IntegerInherited):
683 self.assertEqual(obj1 == obj2, value1 == value2)
684 self.assertEqual(obj1 == int(obj2), value1 == value2)
685 obj1 = klass(value1, impl=tag1)
686 obj2 = klass(value1, impl=tag2)
687 self.assertEqual(obj1 == obj2, tag1 == tag2)
689 @given(lists(integers()))
690 def test_sorted_works(self, values):
691 self.assertSequenceEqual(
692 [int(v) for v in sorted(Integer(v) for v in values)],
696 @given(data_strategy())
697 def test_named(self, d):
698 names_input = list(d.draw(sets(text_letters(), min_size=1)))
699 values_input = list(d.draw(sets(
701 min_size=len(names_input),
702 max_size=len(names_input),
704 chosen_name = d.draw(sampled_from(names_input))
705 names_input = dict(zip(names_input, values_input))
710 _int = Int(chosen_name)
711 self.assertEqual(_int.named, chosen_name)
712 self.assertEqual(int(_int), names_input[chosen_name])
714 @given(integers(), integers(min_value=0), integers(min_value=0))
715 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
716 value = bound_min + value_delta
717 bound_max = value + bound_delta
718 Integer(value=value, bounds=(bound_min, bound_max))
720 @given(sets(integers(), min_size=3, max_size=3))
721 def test_bounds_unsatisfied(self, values):
722 values = sorted(values)
723 with self.assertRaises(BoundsError) as err:
724 Integer(value=values[0], bounds=(values[1], values[2]))
726 with self.assertRaises(BoundsError) as err:
727 Integer(value=values[2], bounds=(values[0], values[1]))
730 @given(data_strategy())
731 def test_call(self, d):
732 for klass in (Integer, IntegerInherited):
742 ) = d.draw(integer_values_strat())
749 optional_initial or False,
762 ) = d.draw(integer_values_strat(do_expl=impl_initial is None))
763 if (default is None) and (obj_initial.default is not None):
767 (value is not None) and
768 (bounds_initial is not None) and
769 not (bounds_initial[0] <= value <= bounds_initial[1])
774 (default is not None) and
775 (bounds_initial is not None) and
776 not (bounds_initial[0] <= default <= bounds_initial[1])
779 obj = obj_initial(value, bounds, impl, expl, default, optional)
781 value_expected = default if value is None else value
783 default_initial if value_expected is None
786 self.assertEqual(obj, value_expected)
787 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
788 self.assertEqual(obj.expl_tag, expl or expl_initial)
791 default_initial if default is None else default,
793 if obj.default is None:
794 optional = optional_initial if optional is None else optional
795 optional = False if optional is None else optional
798 self.assertEqual(obj.optional, optional)
800 (obj._bound_min, obj._bound_max),
801 bounds or bounds_initial or (float("-inf"), float("+inf")),
805 {} if _specs_initial is None else dict(_specs_initial),
808 @given(integer_values_strat())
809 def test_copy(self, values):
810 for klass in (Integer, IntegerInherited):
812 obj_copied = obj.copy()
813 self.assert_copied_basic_fields(obj, obj_copied)
814 self.assertEqual(obj.specs, obj_copied.specs)
815 self.assertEqual(obj._bound_min, obj_copied._bound_min)
816 self.assertEqual(obj._bound_max, obj_copied._bound_max)
817 self.assertEqual(obj._value, obj_copied._value)
821 integers(min_value=1).map(tag_encode),
823 def test_stripped(self, value, tag_impl):
824 obj = Integer(value, impl=tag_impl)
825 with self.assertRaises(NotEnoughData):
826 obj.decode(obj.encode()[:-1])
830 integers(min_value=1).map(tag_ctxc),
832 def test_stripped_expl(self, value, tag_expl):
833 obj = Integer(value, expl=tag_expl)
834 with self.assertRaises(NotEnoughData):
835 obj.decode(obj.encode()[:-1])
837 def test_zero_len(self):
838 with self.assertRaises(NotEnoughData):
839 Integer().decode(b"".join((
845 integers(min_value=31),
846 integers(min_value=0),
849 def test_bad_tag(self, tag, offset, decode_path):
850 decode_path = tuple(str(i) for i in decode_path)
851 with self.assertRaises(DecodeError) as err:
853 tag_encode(tag)[:-1],
855 decode_path=decode_path,
858 self.assertEqual(err.exception.offset, offset)
859 self.assertEqual(err.exception.decode_path, decode_path)
862 integers(min_value=128),
863 integers(min_value=0),
866 def test_bad_len(self, l, offset, decode_path):
867 decode_path = tuple(str(i) for i in decode_path)
868 with self.assertRaises(DecodeError) as err:
870 Integer.tag_default + len_encode(l)[:-1],
872 decode_path=decode_path,
875 self.assertEqual(err.exception.offset, offset)
876 self.assertEqual(err.exception.decode_path, decode_path)
879 sets(integers(), min_size=2, max_size=2),
880 integers(min_value=0),
883 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
884 decode_path = tuple(str(i) for i in decode_path)
885 value, bound_min = list(sorted(ints))
888 bounds = (bound_min, bound_min)
889 with self.assertRaises(DecodeError) as err:
891 Integer(value).encode(),
893 decode_path=decode_path,
896 self.assertEqual(err.exception.offset, offset)
897 self.assertEqual(err.exception.decode_path, decode_path)
899 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
901 integer_values_strat(),
903 integers(min_value=1).map(tag_ctxc),
904 integers(min_value=0),
906 def test_symmetric(self, values, value, tag_expl, offset):
907 for klass in (Integer, IntegerInherited):
908 _, _, _, _, default, optional, _, _decoded = values
917 self.assertFalse(obj.expled)
918 obj_encoded = obj.encode()
919 obj_expled = obj(value, expl=tag_expl)
920 self.assertTrue(obj_expled.expled)
923 obj_expled_encoded = obj_expled.encode()
924 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
927 self.assertEqual(tail, b"")
928 self.assertEqual(obj_decoded, obj_expled)
929 self.assertNotEqual(obj_decoded, obj)
930 self.assertEqual(int(obj_decoded), int(obj_expled))
931 self.assertEqual(int(obj_decoded), int(obj))
932 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
933 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
934 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
936 obj_decoded.expl_llen,
937 len(len_encode(len(obj_encoded))),
939 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
940 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
943 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
945 self.assertEqual(obj_decoded.expl_offset, offset)
947 def test_go_vectors_valid(self):
948 for data, expect in ((
960 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
961 (b"\x80\x00\x00\x00", -2147483648),
964 Integer().decode(b"".join((
966 len_encode(len(data)),
972 def test_go_vectors_invalid(self):
977 with self.assertRaises(DecodeError):
978 Integer().decode(b"".join((
980 len_encode(len(data)),
986 def bit_string_values_strat(draw, schema=None, value_required=False, do_expl=False):
990 schema = draw(sets(text_letters(), min_size=1, max_size=256))
992 integers(min_value=0, max_value=255),
993 min_size=len(schema),
994 max_size=len(schema),
996 schema = list(zip(schema, bits))
998 def _value(value_required):
999 if not value_required and draw(booleans()):
1001 generation_choice = 0
1003 generation_choice = draw(sampled_from((1, 2, 3)))
1004 if generation_choice == 1 or draw(booleans()):
1005 return "'%s'B" % "".join(draw(lists(
1006 sampled_from(("0", "1")),
1007 max_size=len(schema),
1009 elif generation_choice == 2 or draw(booleans()):
1010 return draw(binary(max_size=len(schema) // 8))
1011 elif generation_choice == 3 or draw(booleans()):
1012 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1014 value = _value(value_required)
1015 default = _value(value_required=False)
1019 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1021 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1022 optional = draw(one_of(none(), booleans()))
1024 draw(integers(min_value=0)),
1025 draw(integers(min_value=0)),
1026 draw(integers(min_value=0)),
1028 return (schema, value, impl, expl, default, optional, _decoded)
1031 class BitStringInherited(BitString):
1035 class TestBitString(CommonMixin, TestCase):
1036 base_klass = BitString
1038 @given(lists(booleans()))
1039 def test_b_encoding(self, bits):
1040 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1041 self.assertEqual(obj.bit_len, len(bits))
1042 self.assertSequenceEqual(list(obj), bits)
1043 for i, bit in enumerate(bits):
1044 self.assertEqual(obj[i], bit)
1046 @given(lists(booleans()))
1047 def test_out_of_bounds_bits(self, bits):
1048 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1049 for i in range(len(bits), len(bits) * 2):
1050 self.assertFalse(obj[i])
1052 def test_bad_b_encoding(self):
1053 with self.assertRaises(ValueError):
1054 BitString("'010120101'B")
1057 integers(min_value=1, max_value=255),
1058 integers(min_value=1, max_value=255),
1060 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1061 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1062 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1063 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1065 class BS(BitString):
1067 schema = (("whatever", 0),)
1068 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1069 self.assertEqual(obj.bit_len, leading_zeros + 1)
1070 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1072 def test_zero_len(self):
1073 with self.assertRaises(NotEnoughData):
1074 BitString().decode(b"".join((
1075 BitString.tag_default,
1079 def test_invalid_value_type(self):
1080 with self.assertRaises(InvalidValueType) as err:
1083 with self.assertRaises(InvalidValueType) as err:
1087 def test_obj_unknown(self):
1088 with self.assertRaises(ObjUnknown) as err:
1089 BitString(b"whatever")["whenever"]
1092 def test_get_invalid_typ(self):
1093 with self.assertRaises(InvalidValueType) as err:
1094 BitString(b"whatever")[(1, 2, 3)]
1097 @given(data_strategy())
1098 def test_unknown_name(self, d):
1099 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1100 missing = _schema.pop()
1102 class BS(BitString):
1104 schema = [(n, i) for i, n in enumerate(_schema)]
1105 with self.assertRaises(ObjUnknown) as err:
1110 def test_optional(self, optional):
1111 obj = BitString(default=BitString(b""), optional=optional)
1112 self.assertTrue(obj.optional)
1115 def test_ready(self, value):
1117 self.assertFalse(obj.ready)
1120 with self.assertRaises(ObjNotReady) as err:
1123 obj = BitString(value)
1124 self.assertTrue(obj.ready)
1129 tuples(integers(min_value=0), binary()),
1130 tuples(integers(min_value=0), binary()),
1134 def test_comparison(self, value1, value2, tag1, tag2):
1135 for klass in (BitString, BitStringInherited):
1136 obj1 = klass(value1)
1137 obj2 = klass(value2)
1138 self.assertEqual(obj1 == obj2, value1 == value2)
1139 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1140 obj1 = klass(value1, impl=tag1)
1141 obj2 = klass(value1, impl=tag2)
1142 self.assertEqual(obj1 == obj2, tag1 == tag2)
1144 @given(data_strategy())
1145 def test_call(self, d):
1146 for klass in (BitString, BitStringInherited):
1155 ) = d.draw(bit_string_values_strat())
1159 schema = schema_initial
1161 value=value_initial,
1164 default=default_initial,
1165 optional=optional_initial or False,
1166 _decoded=_decoded_initial,
1176 ) = d.draw(bit_string_values_strat(
1177 schema=schema_initial,
1178 do_expl=impl_initial is None,
1187 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1188 self.assertEqual(obj.expl_tag, expl or expl_initial)
1189 if obj.default is None:
1190 optional = optional_initial if optional is None else optional
1191 optional = False if optional is None else optional
1194 self.assertEqual(obj.optional, optional)
1195 self.assertEqual(obj.specs, obj_initial.specs)
1197 @given(bit_string_values_strat())
1198 def test_copy(self, values):
1199 for klass in (BitString, BitStringInherited):
1200 _schema, value, impl, expl, default, optional, _decoded = values
1210 optional=optional or False,
1213 obj_copied = obj.copy()
1214 self.assert_copied_basic_fields(obj, obj_copied)
1215 self.assertEqual(obj.specs, obj_copied.specs)
1216 self.assertEqual(obj._value, obj_copied._value)
1220 integers(min_value=1).map(tag_encode),
1222 def test_stripped(self, value, tag_impl):
1223 obj = BitString(value, impl=tag_impl)
1224 with self.assertRaises(NotEnoughData):
1225 obj.decode(obj.encode()[:-1])
1229 integers(min_value=1).map(tag_ctxc),
1231 def test_stripped_expl(self, value, tag_expl):
1232 obj = BitString(value, expl=tag_expl)
1233 with self.assertRaises(NotEnoughData):
1234 obj.decode(obj.encode()[:-1])
1237 integers(min_value=31),
1238 integers(min_value=0),
1241 def test_bad_tag(self, tag, offset, decode_path):
1242 decode_path = tuple(str(i) for i in decode_path)
1243 with self.assertRaises(DecodeError) as err:
1245 tag_encode(tag)[:-1],
1247 decode_path=decode_path,
1250 self.assertEqual(err.exception.offset, offset)
1251 self.assertEqual(err.exception.decode_path, decode_path)
1254 integers(min_value=128),
1255 integers(min_value=0),
1258 def test_bad_len(self, l, offset, decode_path):
1259 decode_path = tuple(str(i) for i in decode_path)
1260 with self.assertRaises(DecodeError) as err:
1262 BitString.tag_default + len_encode(l)[:-1],
1264 decode_path=decode_path,
1267 self.assertEqual(err.exception.offset, offset)
1268 self.assertEqual(err.exception.decode_path, decode_path)
1270 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1271 @given(data_strategy())
1272 def test_symmetric(self, d):
1281 ) = d.draw(bit_string_values_strat(value_required=True))
1282 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1283 offset = d.draw(integers(min_value=0))
1284 for klass in (BitString, BitStringInherited):
1296 self.assertFalse(obj.expled)
1297 obj_encoded = obj.encode()
1298 obj_expled = obj(value, expl=tag_expl)
1299 self.assertTrue(obj_expled.expled)
1302 obj_expled_encoded = obj_expled.encode()
1303 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1306 self.assertEqual(tail, b"")
1307 self.assertEqual(obj_decoded, obj_expled)
1308 self.assertNotEqual(obj_decoded, obj)
1309 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1310 self.assertEqual(bytes(obj_decoded), bytes(obj))
1311 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1312 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1313 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1315 obj_decoded.expl_llen,
1316 len(len_encode(len(obj_encoded))),
1318 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1319 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1322 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1324 self.assertEqual(obj_decoded.expl_offset, offset)
1325 if isinstance(value, tuple):
1326 self.assertSetEqual(set(value), set(obj_decoded.named))
1330 @given(integers(min_value=1, max_value=255))
1331 def test_bad_zero_value(self, pad_size):
1332 with self.assertRaises(DecodeError):
1333 BitString().decode(b"".join((
1334 BitString.tag_default,
1339 def test_go_vectors_invalid(self):
1345 with self.assertRaises(DecodeError):
1346 BitString().decode(b"".join((
1347 BitString.tag_default,
1352 def test_go_vectors_valid(self):
1353 obj, _ = BitString().decode(b"".join((
1354 BitString.tag_default,
1358 self.assertEqual(bytes(obj), b"")
1359 self.assertEqual(obj.bit_len, 0)
1361 obj, _ = BitString().decode(b"".join((
1362 BitString.tag_default,
1366 self.assertEqual(bytes(obj), b"\x00")
1367 self.assertEqual(obj.bit_len, 1)
1369 obj = BitString((16, b"\x82\x40"))
1370 self.assertTrue(obj[0])
1371 self.assertFalse(obj[1])
1372 self.assertTrue(obj[6])
1373 self.assertTrue(obj[9])
1374 self.assertFalse(obj[17])
1378 def octet_string_values_strat(draw, do_expl=False):
1379 bound_min, bound_max = sorted(draw(sets(
1380 integers(min_value=0, max_value=1 << 7),
1384 value = draw(one_of(
1386 binary(min_size=bound_min, max_size=bound_max),
1388 default = draw(one_of(
1390 binary(min_size=bound_min, max_size=bound_max),
1393 if draw(booleans()):
1394 bounds = (bound_min, bound_max)
1398 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1400 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1401 optional = draw(one_of(none(), booleans()))
1403 draw(integers(min_value=0)),
1404 draw(integers(min_value=0)),
1405 draw(integers(min_value=0)),
1407 return (value, bounds, impl, expl, default, optional, _decoded)
1410 class OctetStringInherited(OctetString):
1414 class TestOctetString(CommonMixin, TestCase):
1415 base_klass = OctetString
1417 def test_invalid_value_type(self):
1418 with self.assertRaises(InvalidValueType) as err:
1419 OctetString(text_type(123))
1423 def test_optional(self, optional):
1424 obj = OctetString(default=OctetString(b""), optional=optional)
1425 self.assertTrue(obj.optional)
1428 def test_ready(self, value):
1430 self.assertFalse(obj.ready)
1433 with self.assertRaises(ObjNotReady) as err:
1436 obj = OctetString(value)
1437 self.assertTrue(obj.ready)
1441 @given(binary(), binary(), binary(), binary())
1442 def test_comparison(self, value1, value2, tag1, tag2):
1443 for klass in (OctetString, OctetStringInherited):
1444 obj1 = klass(value1)
1445 obj2 = klass(value2)
1446 self.assertEqual(obj1 == obj2, value1 == value2)
1447 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1448 obj1 = klass(value1, impl=tag1)
1449 obj2 = klass(value1, impl=tag2)
1450 self.assertEqual(obj1 == obj2, tag1 == tag2)
1452 @given(data_strategy())
1453 def test_bounds_satisfied(self, d):
1454 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1455 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1456 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1457 OctetString(value=value, bounds=(bound_min, bound_max))
1459 @given(data_strategy())
1460 def test_bounds_unsatisfied(self, d):
1461 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1462 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1463 value = d.draw(binary(max_size=bound_min - 1))
1464 with self.assertRaises(BoundsError) as err:
1465 OctetString(value=value, bounds=(bound_min, bound_max))
1467 value = d.draw(binary(min_size=bound_max + 1))
1468 with self.assertRaises(BoundsError) as err:
1469 OctetString(value=value, bounds=(bound_min, bound_max))
1472 @given(data_strategy())
1473 def test_call(self, d):
1474 for klass in (OctetString, OctetStringInherited):
1483 ) = d.draw(octet_string_values_strat())
1484 obj_initial = klass(
1490 optional_initial or False,
1501 ) = d.draw(octet_string_values_strat(do_expl=impl_initial is None))
1502 if (default is None) and (obj_initial.default is not None):
1505 (bounds is None) and
1506 (value is not None) and
1507 (bounds_initial is not None) and
1508 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1512 (bounds is None) and
1513 (default is not None) and
1514 (bounds_initial is not None) and
1515 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1518 obj = obj_initial(value, bounds, impl, expl, default, optional)
1520 value_expected = default if value is None else value
1522 default_initial if value_expected is None
1525 self.assertEqual(obj, value_expected)
1526 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1527 self.assertEqual(obj.expl_tag, expl or expl_initial)
1530 default_initial if default is None else default,
1532 if obj.default is None:
1533 optional = optional_initial if optional is None else optional
1534 optional = False if optional is None else optional
1537 self.assertEqual(obj.optional, optional)
1539 (obj._bound_min, obj._bound_max),
1540 bounds or bounds_initial or (0, float("+inf")),
1543 @given(octet_string_values_strat())
1544 def test_copy(self, values):
1545 for klass in (OctetString, OctetStringInherited):
1546 obj = klass(*values)
1547 obj_copied = obj.copy()
1548 self.assert_copied_basic_fields(obj, obj_copied)
1549 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1550 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1551 self.assertEqual(obj._value, obj_copied._value)
1555 integers(min_value=1).map(tag_encode),
1557 def test_stripped(self, value, tag_impl):
1558 obj = OctetString(value, impl=tag_impl)
1559 with self.assertRaises(NotEnoughData):
1560 obj.decode(obj.encode()[:-1])
1564 integers(min_value=1).map(tag_ctxc),
1566 def test_stripped_expl(self, value, tag_expl):
1567 obj = OctetString(value, expl=tag_expl)
1568 with self.assertRaises(NotEnoughData):
1569 obj.decode(obj.encode()[:-1])
1572 integers(min_value=31),
1573 integers(min_value=0),
1576 def test_bad_tag(self, tag, offset, decode_path):
1577 decode_path = tuple(str(i) for i in decode_path)
1578 with self.assertRaises(DecodeError) as err:
1579 OctetString().decode(
1580 tag_encode(tag)[:-1],
1582 decode_path=decode_path,
1585 self.assertEqual(err.exception.offset, offset)
1586 self.assertEqual(err.exception.decode_path, decode_path)
1589 integers(min_value=128),
1590 integers(min_value=0),
1593 def test_bad_len(self, l, offset, decode_path):
1594 decode_path = tuple(str(i) for i in decode_path)
1595 with self.assertRaises(DecodeError) as err:
1596 OctetString().decode(
1597 OctetString.tag_default + len_encode(l)[:-1],
1599 decode_path=decode_path,
1602 self.assertEqual(err.exception.offset, offset)
1603 self.assertEqual(err.exception.decode_path, decode_path)
1606 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1607 integers(min_value=0),
1610 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1611 decode_path = tuple(str(i) for i in decode_path)
1612 value, bound_min = list(sorted(ints))
1614 class String(OctetString):
1615 bounds = (bound_min, bound_min)
1616 with self.assertRaises(DecodeError) as err:
1618 OctetString(b"\x00" * value).encode(),
1620 decode_path=decode_path,
1623 self.assertEqual(err.exception.offset, offset)
1624 self.assertEqual(err.exception.decode_path, decode_path)
1626 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1628 octet_string_values_strat(),
1630 integers(min_value=1).map(tag_ctxc),
1631 integers(min_value=0),
1633 def test_symmetric(self, values, value, tag_expl, offset):
1634 for klass in (OctetString, OctetStringInherited):
1635 _, _, _, _, default, optional, _decoded = values
1644 self.assertFalse(obj.expled)
1645 obj_encoded = obj.encode()
1646 obj_expled = obj(value, expl=tag_expl)
1647 self.assertTrue(obj_expled.expled)
1650 obj_expled_encoded = obj_expled.encode()
1651 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1654 self.assertEqual(tail, b"")
1655 self.assertEqual(obj_decoded, obj_expled)
1656 self.assertNotEqual(obj_decoded, obj)
1657 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1658 self.assertEqual(bytes(obj_decoded), bytes(obj))
1659 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1660 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1661 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1663 obj_decoded.expl_llen,
1664 len(len_encode(len(obj_encoded))),
1666 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1667 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1670 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1672 self.assertEqual(obj_decoded.expl_offset, offset)
1676 def null_values_strat(draw, do_expl=False):
1680 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1682 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1683 optional = draw(one_of(none(), booleans()))
1685 draw(integers(min_value=0)),
1686 draw(integers(min_value=0)),
1687 draw(integers(min_value=0)),
1689 return (impl, expl, optional, _decoded)
1692 class NullInherited(Null):
1696 class TestNull(CommonMixin, TestCase):
1699 def test_ready(self):
1701 self.assertTrue(obj.ready)
1705 @given(binary(), binary())
1706 def test_comparison(self, tag1, tag2):
1707 for klass in (Null, NullInherited):
1708 obj1 = klass(impl=tag1)
1709 obj2 = klass(impl=tag2)
1710 self.assertEqual(obj1 == obj2, tag1 == tag2)
1711 self.assertNotEqual(obj1, tag2)
1713 @given(data_strategy())
1714 def test_call(self, d):
1715 for klass in (Null, NullInherited):
1721 ) = d.draw(null_values_strat())
1722 obj_initial = klass(
1725 optional=optional_initial or False,
1726 _decoded=_decoded_initial,
1733 ) = d.draw(null_values_strat(do_expl=impl_initial is None))
1734 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1735 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1736 self.assertEqual(obj.expl_tag, expl or expl_initial)
1737 optional = optional_initial if optional is None else optional
1738 optional = False if optional is None else optional
1739 self.assertEqual(obj.optional, optional)
1741 @given(null_values_strat())
1742 def test_copy(self, values):
1743 for klass in (Null, NullInherited):
1744 impl, expl, optional, _decoded = values
1748 optional=optional or False,
1751 obj_copied = obj.copy()
1752 self.assert_copied_basic_fields(obj, obj_copied)
1754 @given(integers(min_value=1).map(tag_encode))
1755 def test_stripped(self, tag_impl):
1756 obj = Null(impl=tag_impl)
1757 with self.assertRaises(NotEnoughData):
1758 obj.decode(obj.encode()[:-1])
1760 @given(integers(min_value=1).map(tag_ctxc))
1761 def test_stripped_expl(self, tag_expl):
1762 obj = Null(expl=tag_expl)
1763 with self.assertRaises(NotEnoughData):
1764 obj.decode(obj.encode()[:-1])
1767 integers(min_value=31),
1768 integers(min_value=0),
1771 def test_bad_tag(self, tag, offset, decode_path):
1772 decode_path = tuple(str(i) for i in decode_path)
1773 with self.assertRaises(DecodeError) as err:
1775 tag_encode(tag)[:-1],
1777 decode_path=decode_path,
1780 self.assertEqual(err.exception.offset, offset)
1781 self.assertEqual(err.exception.decode_path, decode_path)
1784 integers(min_value=128),
1785 integers(min_value=0),
1788 def test_bad_len(self, l, offset, decode_path):
1789 decode_path = tuple(str(i) for i in decode_path)
1790 with self.assertRaises(DecodeError) as err:
1792 Null.tag_default + len_encode(l)[:-1],
1794 decode_path=decode_path,
1797 self.assertEqual(err.exception.offset, offset)
1798 self.assertEqual(err.exception.decode_path, decode_path)
1800 @given(binary(min_size=1))
1801 def test_tag_mismatch(self, impl):
1802 assume(impl != Null.tag_default)
1803 with self.assertRaises(TagMismatch):
1804 Null(impl=impl).decode(Null().encode())
1807 null_values_strat(),
1808 integers(min_value=1).map(tag_ctxc),
1809 integers(min_value=0),
1811 def test_symmetric(self, values, tag_expl, offset):
1812 for klass in (Null, NullInherited):
1813 _, _, optional, _decoded = values
1814 obj = klass(optional=optional, _decoded=_decoded)
1817 self.assertFalse(obj.expled)
1818 obj_encoded = obj.encode()
1819 obj_expled = obj(expl=tag_expl)
1820 self.assertTrue(obj_expled.expled)
1823 obj_expled_encoded = obj_expled.encode()
1824 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1827 self.assertEqual(tail, b"")
1828 self.assertEqual(obj_decoded, obj_expled)
1829 self.assertNotEqual(obj_decoded, obj)
1830 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1831 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1832 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1834 obj_decoded.expl_llen,
1835 len(len_encode(len(obj_encoded))),
1837 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1838 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1841 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1843 self.assertEqual(obj_decoded.expl_offset, offset)
1845 @given(integers(min_value=1))
1846 def test_invalid_len(self, l):
1847 with self.assertRaises(InvalidLength):
1848 Null().decode(b"".join((
1855 def oid_strategy(draw):
1856 first_arc = draw(integers(min_value=0, max_value=2))
1858 if first_arc in (0, 1):
1859 second_arc = draw(integers(min_value=0, max_value=39))
1861 second_arc = draw(integers(min_value=0))
1862 other_arcs = draw(lists(integers(min_value=0)))
1863 return tuple([first_arc, second_arc] + other_arcs)
1867 def oid_values_strat(draw, do_expl=False):
1868 value = draw(one_of(none(), oid_strategy()))
1872 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1874 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1875 default = draw(one_of(none(), oid_strategy()))
1876 optional = draw(one_of(none(), booleans()))
1878 draw(integers(min_value=0)),
1879 draw(integers(min_value=0)),
1880 draw(integers(min_value=0)),
1882 return (value, impl, expl, default, optional, _decoded)
1885 class ObjectIdentifierInherited(ObjectIdentifier):
1889 class TestObjectIdentifier(CommonMixin, TestCase):
1890 base_klass = ObjectIdentifier
1892 def test_invalid_value_type(self):
1893 with self.assertRaises(InvalidValueType) as err:
1894 ObjectIdentifier(123)
1898 def test_optional(self, optional):
1899 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
1900 self.assertTrue(obj.optional)
1902 @given(oid_strategy())
1903 def test_ready(self, value):
1904 obj = ObjectIdentifier()
1905 self.assertFalse(obj.ready)
1908 with self.assertRaises(ObjNotReady) as err:
1911 obj = ObjectIdentifier(value)
1912 self.assertTrue(obj.ready)
1917 @given(oid_strategy(), oid_strategy(), binary(), binary())
1918 def test_comparison(self, value1, value2, tag1, tag2):
1919 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1920 obj1 = klass(value1)
1921 obj2 = klass(value2)
1922 self.assertEqual(obj1 == obj2, value1 == value2)
1923 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
1924 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
1925 obj1 = klass(value1, impl=tag1)
1926 obj2 = klass(value1, impl=tag2)
1927 self.assertEqual(obj1 == obj2, tag1 == tag2)
1929 @given(lists(oid_strategy()))
1930 def test_sorted_works(self, values):
1931 self.assertSequenceEqual(
1932 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
1936 @given(data_strategy())
1937 def test_call(self, d):
1938 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1946 ) = d.draw(oid_values_strat())
1947 obj_initial = klass(
1952 optional_initial or False,
1962 ) = d.draw(oid_values_strat(do_expl=impl_initial is None))
1963 obj = obj_initial(value, impl, expl, default, optional)
1965 value_expected = default if value is None else value
1967 default_initial if value_expected is None
1970 self.assertEqual(obj, value_expected)
1971 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1972 self.assertEqual(obj.expl_tag, expl or expl_initial)
1975 default_initial if default is None else default,
1977 if obj.default is None:
1978 optional = optional_initial if optional is None else optional
1979 optional = False if optional is None else optional
1982 self.assertEqual(obj.optional, optional)
1984 @given(oid_values_strat())
1985 def test_copy(self, values):
1986 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1987 obj = klass(*values)
1988 obj_copied = obj.copy()
1989 self.assert_copied_basic_fields(obj, obj_copied)
1990 self.assertEqual(obj._value, obj_copied._value)
1992 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1995 integers(min_value=1).map(tag_encode),
1997 def test_stripped(self, value, tag_impl):
1998 obj = ObjectIdentifier(value, impl=tag_impl)
1999 with self.assertRaises(NotEnoughData):
2000 obj.decode(obj.encode()[:-1])
2004 integers(min_value=1).map(tag_ctxc),
2006 def test_stripped_expl(self, value, tag_expl):
2007 obj = ObjectIdentifier(value, expl=tag_expl)
2008 with self.assertRaises(NotEnoughData):
2009 obj.decode(obj.encode()[:-1])
2012 integers(min_value=31),
2013 integers(min_value=0),
2016 def test_bad_tag(self, tag, offset, decode_path):
2017 decode_path = tuple(str(i) for i in decode_path)
2018 with self.assertRaises(DecodeError) as err:
2019 ObjectIdentifier().decode(
2020 tag_encode(tag)[:-1],
2022 decode_path=decode_path,
2025 self.assertEqual(err.exception.offset, offset)
2026 self.assertEqual(err.exception.decode_path, decode_path)
2029 integers(min_value=128),
2030 integers(min_value=0),
2033 def test_bad_len(self, l, offset, decode_path):
2034 decode_path = tuple(str(i) for i in decode_path)
2035 with self.assertRaises(DecodeError) as err:
2036 ObjectIdentifier().decode(
2037 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2039 decode_path=decode_path,
2042 self.assertEqual(err.exception.offset, offset)
2043 self.assertEqual(err.exception.decode_path, decode_path)
2045 def test_zero_oid(self):
2046 with self.assertRaises(NotEnoughData):
2047 ObjectIdentifier().decode(
2048 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2051 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2052 @given(oid_strategy())
2053 def test_unfinished_oid(self, value):
2054 assume(list(value)[-1] > 255)
2055 obj_encoded = ObjectIdentifier(value).encode()
2056 obj, _ = ObjectIdentifier().decode(obj_encoded)
2057 data = obj_encoded[obj.tlen + obj.llen:-1]
2059 ObjectIdentifier.tag_default,
2060 len_encode(len(data)),
2063 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2066 @given(integers(min_value=0))
2067 def test_invalid_short(self, value):
2068 with self.assertRaises(InvalidOID):
2069 ObjectIdentifier((value,))
2070 with self.assertRaises(InvalidOID):
2071 ObjectIdentifier("%d" % value)
2073 @given(integers(min_value=3), integers(min_value=0))
2074 def test_invalid_first_arc(self, first_arc, second_arc):
2075 with self.assertRaises(InvalidOID):
2076 ObjectIdentifier((first_arc, second_arc))
2077 with self.assertRaises(InvalidOID):
2078 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2080 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2081 def test_invalid_second_arc(self, first_arc, second_arc):
2082 with self.assertRaises(InvalidOID):
2083 ObjectIdentifier((first_arc, second_arc))
2084 with self.assertRaises(InvalidOID):
2085 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2087 @given(text(alphabet=ascii_letters + ".", min_size=1))
2088 def test_junk(self, oid):
2089 with self.assertRaises(InvalidOID):
2090 ObjectIdentifier(oid)
2092 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2093 @given(oid_strategy())
2094 def test_validness(self, oid):
2095 obj = ObjectIdentifier(oid)
2096 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2101 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2105 integers(min_value=1).map(tag_ctxc),
2106 integers(min_value=0),
2108 def test_symmetric(self, values, value, tag_expl, offset):
2109 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2110 _, _, _, default, optional, _decoded = values
2119 self.assertFalse(obj.expled)
2120 obj_encoded = obj.encode()
2121 obj_expled = obj(value, expl=tag_expl)
2122 self.assertTrue(obj_expled.expled)
2125 obj_expled_encoded = obj_expled.encode()
2126 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2129 self.assertEqual(tail, b"")
2130 self.assertEqual(obj_decoded, obj_expled)
2131 self.assertNotEqual(obj_decoded, obj)
2132 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2133 self.assertEqual(tuple(obj_decoded), tuple(obj))
2134 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2135 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2136 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2138 obj_decoded.expl_llen,
2139 len(len_encode(len(obj_encoded))),
2141 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2142 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2145 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2147 self.assertEqual(obj_decoded.expl_offset, offset)
2150 oid_strategy().map(ObjectIdentifier),
2151 oid_strategy().map(ObjectIdentifier),
2153 def test_add(self, oid1, oid2):
2154 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2155 for oid_to_add in (oid2, tuple(oid2)):
2156 self.assertEqual(oid1 + oid_to_add, oid_expect)
2157 with self.assertRaises(InvalidValueType):
2160 def test_go_vectors_valid(self):
2161 for data, expect in (
2163 (b"\x55\x02", (2, 5, 2)),
2164 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2165 (b"\x81\x34\x03", (2, 100, 3)),
2168 ObjectIdentifier().decode(b"".join((
2169 ObjectIdentifier.tag_default,
2170 len_encode(len(data)),
2176 def test_go_vectors_invalid(self):
2177 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2178 with self.assertRaises(DecodeError):
2179 ObjectIdentifier().decode(b"".join((
2180 Integer.tag_default,
2181 len_encode(len(data)),
2187 def enumerated_values_strat(draw, schema=None, do_expl=False):
2189 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2190 values = list(draw(sets(
2192 min_size=len(schema),
2193 max_size=len(schema),
2195 schema = list(zip(schema, values))
2196 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2200 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2202 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2203 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2204 optional = draw(one_of(none(), booleans()))
2206 draw(integers(min_value=0)),
2207 draw(integers(min_value=0)),
2208 draw(integers(min_value=0)),
2210 return (schema, value, impl, expl, default, optional, _decoded)
2213 class TestEnumerated(CommonMixin, TestCase):
2214 class EWhatever(Enumerated):
2216 schema = (("whatever", 0),)
2218 base_klass = EWhatever
2220 def test_schema_required(self):
2221 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2224 def test_invalid_value_type(self):
2225 with self.assertRaises(InvalidValueType) as err:
2226 self.base_klass((1, 2))
2229 @given(sets(text_letters(), min_size=2))
2230 def test_unknown_name(self, schema_input):
2231 missing = schema_input.pop()
2233 class E(Enumerated):
2235 schema = [(n, 123) for n in schema_input]
2236 with self.assertRaises(ObjUnknown) as err:
2241 sets(text_letters(), min_size=2),
2242 sets(integers(), min_size=2),
2244 def test_unknown_value(self, schema_input, values_input):
2246 missing_value = values_input.pop()
2247 _input = list(zip(schema_input, values_input))
2249 class E(Enumerated):
2252 with self.assertRaises(DecodeError) as err:
2257 def test_optional(self, optional):
2258 obj = self.base_klass(default="whatever", optional=optional)
2259 self.assertTrue(obj.optional)
2261 def test_ready(self):
2262 obj = self.base_klass()
2263 self.assertFalse(obj.ready)
2266 with self.assertRaises(ObjNotReady) as err:
2269 obj = self.base_klass("whatever")
2270 self.assertTrue(obj.ready)
2274 @given(integers(), integers(), binary(), binary())
2275 def test_comparison(self, value1, value2, tag1, tag2):
2276 class E(Enumerated):
2279 ("whatever0", value1),
2280 ("whatever1", value2),
2283 class EInherited(E):
2285 for klass in (E, EInherited):
2286 obj1 = klass(value1)
2287 obj2 = klass(value2)
2288 self.assertEqual(obj1 == obj2, value1 == value2)
2289 self.assertEqual(obj1 == int(obj2), value1 == value2)
2290 obj1 = klass(value1, impl=tag1)
2291 obj2 = klass(value1, impl=tag2)
2292 self.assertEqual(obj1 == obj2, tag1 == tag2)
2294 @given(data_strategy())
2295 def test_call(self, d):
2304 ) = d.draw(enumerated_values_strat())
2306 class E(Enumerated):
2308 schema = schema_initial
2310 value=value_initial,
2313 default=default_initial,
2314 optional=optional_initial or False,
2315 _decoded=_decoded_initial,
2325 ) = d.draw(enumerated_values_strat(
2326 schema=schema_initial,
2327 do_expl=impl_initial is None,
2337 value_expected = default if value is None else value
2339 default_initial if value_expected is None
2344 dict(schema_initial).get(value_expected, value_expected),
2346 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2347 self.assertEqual(obj.expl_tag, expl or expl_initial)
2350 default_initial if default is None else default,
2352 if obj.default is None:
2353 optional = optional_initial if optional is None else optional
2354 optional = False if optional is None else optional
2357 self.assertEqual(obj.optional, optional)
2358 self.assertEqual(obj.specs, dict(schema_initial))
2360 @given(enumerated_values_strat())
2361 def test_copy(self, values):
2362 schema_input, value, impl, expl, default, optional, _decoded = values
2364 class E(Enumerated):
2366 schema = schema_input
2375 obj_copied = obj.copy()
2376 self.assert_copied_basic_fields(obj, obj_copied)
2377 self.assertEqual(obj.specs, obj_copied.specs)
2379 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2380 @given(data_strategy())
2381 def test_symmetric(self, d):
2382 schema_input, _, _, _, default, optional, _decoded = d.draw(
2383 enumerated_values_strat(),
2385 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2386 offset = d.draw(integers(min_value=0))
2387 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2389 class E(Enumerated):
2391 schema = schema_input
2400 self.assertFalse(obj.expled)
2401 obj_encoded = obj.encode()
2402 obj_expled = obj(value, expl=tag_expl)
2403 self.assertTrue(obj_expled.expled)
2406 obj_expled_encoded = obj_expled.encode()
2407 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2410 self.assertEqual(tail, b"")
2411 self.assertEqual(obj_decoded, obj_expled)
2412 self.assertNotEqual(obj_decoded, obj)
2413 self.assertEqual(int(obj_decoded), int(obj_expled))
2414 self.assertEqual(int(obj_decoded), int(obj))
2415 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2416 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2417 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2419 obj_decoded.expl_llen,
2420 len(len_encode(len(obj_encoded))),
2422 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2423 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2426 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2428 self.assertEqual(obj_decoded.expl_offset, offset)
2432 def string_values_strat(draw, alphabet, do_expl=False):
2433 bound_min, bound_max = sorted(draw(sets(
2434 integers(min_value=0, max_value=1 << 7),
2438 value = draw(one_of(
2440 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2442 default = draw(one_of(
2444 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2447 if draw(booleans()):
2448 bounds = (bound_min, bound_max)
2452 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2454 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2455 optional = draw(one_of(none(), booleans()))
2457 draw(integers(min_value=0)),
2458 draw(integers(min_value=0)),
2459 draw(integers(min_value=0)),
2461 return (value, bounds, impl, expl, default, optional, _decoded)
2464 class StringMixin(object):
2465 def test_invalid_value_type(self):
2466 with self.assertRaises(InvalidValueType) as err:
2467 self.base_klass((1, 2))
2470 def text_alphabet(self):
2471 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2472 return printable + whitespace
2476 def test_optional(self, optional):
2477 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2478 self.assertTrue(obj.optional)
2480 @given(data_strategy())
2481 def test_ready(self, d):
2482 obj = self.base_klass()
2483 self.assertFalse(obj.ready)
2487 with self.assertRaises(ObjNotReady) as err:
2490 value = d.draw(text(alphabet=self.text_alphabet()))
2491 obj = self.base_klass(value)
2492 self.assertTrue(obj.ready)
2497 @given(data_strategy())
2498 def test_comparison(self, d):
2499 value1 = d.draw(text(alphabet=self.text_alphabet()))
2500 value2 = d.draw(text(alphabet=self.text_alphabet()))
2501 tag1 = d.draw(binary())
2502 tag2 = d.draw(binary())
2503 obj1 = self.base_klass(value1)
2504 obj2 = self.base_klass(value2)
2505 self.assertEqual(obj1 == obj2, value1 == value2)
2506 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2507 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2508 obj1 = self.base_klass(value1, impl=tag1)
2509 obj2 = self.base_klass(value1, impl=tag2)
2510 self.assertEqual(obj1 == obj2, tag1 == tag2)
2512 @given(data_strategy())
2513 def test_bounds_satisfied(self, d):
2514 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2515 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2516 value = d.draw(text(
2517 alphabet=self.text_alphabet(),
2521 self.base_klass(value=value, bounds=(bound_min, bound_max))
2523 @given(data_strategy())
2524 def test_bounds_unsatisfied(self, d):
2525 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2526 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2527 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2528 with self.assertRaises(BoundsError) as err:
2529 self.base_klass(value=value, bounds=(bound_min, bound_max))
2531 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2532 with self.assertRaises(BoundsError) as err:
2533 self.base_klass(value=value, bounds=(bound_min, bound_max))
2536 @given(data_strategy())
2537 def test_call(self, d):
2546 ) = d.draw(string_values_strat(self.text_alphabet()))
2547 obj_initial = self.base_klass(
2553 optional_initial or False,
2564 ) = d.draw(string_values_strat(
2565 self.text_alphabet(),
2566 do_expl=impl_initial is None,
2568 if (default is None) and (obj_initial.default is not None):
2571 (bounds is None) and
2572 (value is not None) and
2573 (bounds_initial is not None) and
2574 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2578 (bounds is None) and
2579 (default is not None) and
2580 (bounds_initial is not None) and
2581 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2584 obj = obj_initial(value, bounds, impl, expl, default, optional)
2586 value_expected = default if value is None else value
2588 default_initial if value_expected is None
2591 self.assertEqual(obj, value_expected)
2592 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2593 self.assertEqual(obj.expl_tag, expl or expl_initial)
2596 default_initial if default is None else default,
2598 if obj.default is None:
2599 optional = optional_initial if optional is None else optional
2600 optional = False if optional is None else optional
2603 self.assertEqual(obj.optional, optional)
2605 (obj._bound_min, obj._bound_max),
2606 bounds or bounds_initial or (0, float("+inf")),
2609 @given(data_strategy())
2610 def test_copy(self, d):
2611 values = d.draw(string_values_strat(self.text_alphabet()))
2612 obj = self.base_klass(*values)
2613 obj_copied = obj.copy()
2614 self.assert_copied_basic_fields(obj, obj_copied)
2615 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2616 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2617 self.assertEqual(obj._value, obj_copied._value)
2619 @given(data_strategy())
2620 def test_stripped(self, d):
2621 value = d.draw(text(alphabet=self.text_alphabet()))
2622 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2623 obj = self.base_klass(value, impl=tag_impl)
2624 with self.assertRaises(NotEnoughData):
2625 obj.decode(obj.encode()[:-1])
2627 @given(data_strategy())
2628 def test_stripped_expl(self, d):
2629 value = d.draw(text(alphabet=self.text_alphabet()))
2630 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2631 obj = self.base_klass(value, expl=tag_expl)
2632 with self.assertRaises(NotEnoughData):
2633 obj.decode(obj.encode()[:-1])
2636 integers(min_value=31),
2637 integers(min_value=0),
2640 def test_bad_tag(self, tag, 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 tag_encode(tag)[:-1],
2646 decode_path=decode_path,
2649 self.assertEqual(err.exception.offset, offset)
2650 self.assertEqual(err.exception.decode_path, decode_path)
2653 integers(min_value=128),
2654 integers(min_value=0),
2657 def test_bad_len(self, l, offset, decode_path):
2658 decode_path = tuple(str(i) for i in decode_path)
2659 with self.assertRaises(DecodeError) as err:
2660 self.base_klass().decode(
2661 self.base_klass.tag_default + len_encode(l)[:-1],
2663 decode_path=decode_path,
2666 self.assertEqual(err.exception.offset, offset)
2667 self.assertEqual(err.exception.decode_path, decode_path)
2670 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2671 integers(min_value=0),
2674 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2675 decode_path = tuple(str(i) for i in decode_path)
2676 value, bound_min = list(sorted(ints))
2678 class String(self.base_klass):
2679 # Multiply this value by four, to satisfy UTF-32 bounds
2680 # (4 bytes per character) validation
2681 bounds = (bound_min * 4, bound_min * 4)
2682 with self.assertRaises(DecodeError) as err:
2684 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2686 decode_path=decode_path,
2689 self.assertEqual(err.exception.offset, offset)
2690 self.assertEqual(err.exception.decode_path, decode_path)
2692 @given(data_strategy())
2693 def test_symmetric(self, d):
2694 values = d.draw(string_values_strat(self.text_alphabet()))
2695 value = d.draw(text(alphabet=self.text_alphabet()))
2696 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2697 offset = d.draw(integers(min_value=0))
2698 _, _, _, _, default, optional, _decoded = values
2699 obj = self.base_klass(
2707 self.assertFalse(obj.expled)
2708 obj_encoded = obj.encode()
2709 obj_expled = obj(value, expl=tag_expl)
2710 self.assertTrue(obj_expled.expled)
2713 obj_expled_encoded = obj_expled.encode()
2714 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2717 self.assertEqual(tail, b"")
2718 self.assertEqual(obj_decoded, obj_expled)
2719 self.assertNotEqual(obj_decoded, obj)
2720 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2721 self.assertEqual(bytes(obj_decoded), bytes(obj))
2722 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2723 self.assertEqual(text_type(obj_decoded), text_type(obj))
2724 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2725 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2726 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2728 obj_decoded.expl_llen,
2729 len(len_encode(len(obj_encoded))),
2731 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2732 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2735 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2737 self.assertEqual(obj_decoded.expl_offset, offset)
2740 class TestUTF8String(StringMixin, CommonMixin, TestCase):
2741 base_klass = UTF8String
2744 class TestNumericString(StringMixin, CommonMixin, TestCase):
2745 base_klass = NumericString
2748 class TestPrintableString(StringMixin, CommonMixin, TestCase):
2749 base_klass = PrintableString
2752 class TestTeletexString(StringMixin, CommonMixin, TestCase):
2753 base_klass = TeletexString
2756 class TestVideotexString(StringMixin, CommonMixin, TestCase):
2757 base_klass = VideotexString
2760 class TestIA5String(StringMixin, CommonMixin, TestCase):
2761 base_klass = IA5String
2764 class TestGraphicString(StringMixin, CommonMixin, TestCase):
2765 base_klass = GraphicString
2768 class TestVisibleString(StringMixin, CommonMixin, TestCase):
2769 base_klass = VisibleString
2772 class TestGeneralString(StringMixin, CommonMixin, TestCase):
2773 base_klass = GeneralString
2776 class TestUniversalString(StringMixin, CommonMixin, TestCase):
2777 base_klass = UniversalString
2780 class TestBMPString(StringMixin, CommonMixin, TestCase):
2781 base_klass = BMPString
2785 def generalized_time_values_strat(
2793 if draw(booleans()):
2794 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2796 value = value.replace(microsecond=0)
2798 if draw(booleans()):
2799 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2801 default = default.replace(microsecond=0)
2805 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2807 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2808 optional = draw(one_of(none(), booleans()))
2810 draw(integers(min_value=0)),
2811 draw(integers(min_value=0)),
2812 draw(integers(min_value=0)),
2814 return (value, impl, expl, default, optional, _decoded)
2817 class TimeMixin(object):
2818 def test_invalid_value_type(self):
2819 with self.assertRaises(InvalidValueType) as err:
2820 self.base_klass(datetime.now().timetuple())
2823 @given(data_strategy())
2824 def test_optional(self, d):
2825 default = d.draw(datetimes(
2826 min_value=self.min_datetime,
2827 max_value=self.max_datetime,
2829 optional = d.draw(booleans())
2830 obj = self.base_klass(default=default, optional=optional)
2831 self.assertTrue(obj.optional)
2833 @given(data_strategy())
2834 def test_ready(self, d):
2835 obj = self.base_klass()
2836 self.assertFalse(obj.ready)
2839 with self.assertRaises(ObjNotReady) as err:
2842 value = d.draw(datetimes(min_value=self.min_datetime))
2843 obj = self.base_klass(value)
2844 self.assertTrue(obj.ready)
2848 @given(data_strategy())
2849 def test_comparison(self, d):
2850 value1 = d.draw(datetimes(
2851 min_value=self.min_datetime,
2852 max_value=self.max_datetime,
2854 value2 = d.draw(datetimes(
2855 min_value=self.min_datetime,
2856 max_value=self.max_datetime,
2858 tag1 = d.draw(binary())
2859 tag2 = d.draw(binary())
2861 value1 = value1.replace(microsecond=0)
2862 value2 = value2.replace(microsecond=0)
2863 obj1 = self.base_klass(value1)
2864 obj2 = self.base_klass(value2)
2865 self.assertEqual(obj1 == obj2, value1 == value2)
2866 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
2867 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2868 obj1 = self.base_klass(value1, impl=tag1)
2869 obj2 = self.base_klass(value1, impl=tag2)
2870 self.assertEqual(obj1 == obj2, tag1 == tag2)
2872 @given(data_strategy())
2873 def test_call(self, d):
2881 ) = d.draw(generalized_time_values_strat(
2882 min_datetime=self.min_datetime,
2883 max_datetime=self.max_datetime,
2884 omit_ms=self.omit_ms,
2886 obj_initial = self.base_klass(
2887 value=value_initial,
2890 default=default_initial,
2891 optional=optional_initial or False,
2892 _decoded=_decoded_initial,
2901 ) = d.draw(generalized_time_values_strat(
2902 min_datetime=self.min_datetime,
2903 max_datetime=self.max_datetime,
2904 omit_ms=self.omit_ms,
2905 do_expl=impl_initial is None,
2915 value_expected = default if value is None else value
2917 default_initial if value_expected is None
2920 self.assertEqual(obj, value_expected)
2921 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2922 self.assertEqual(obj.expl_tag, expl or expl_initial)
2925 default_initial if default is None else default,
2927 if obj.default is None:
2928 optional = optional_initial if optional is None else optional
2929 optional = False if optional is None else optional
2932 self.assertEqual(obj.optional, optional)
2934 @given(data_strategy())
2935 def test_copy(self, d):
2936 values = d.draw(generalized_time_values_strat(
2937 min_datetime=self.min_datetime,
2938 max_datetime=self.max_datetime,
2940 obj = self.base_klass(*values)
2941 obj_copied = obj.copy()
2942 self.assert_copied_basic_fields(obj, obj_copied)
2943 self.assertEqual(obj._value, obj_copied._value)
2945 @given(data_strategy())
2946 def test_stripped(self, d):
2947 value = d.draw(datetimes(
2948 min_value=self.min_datetime,
2949 max_value=self.max_datetime,
2951 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2952 obj = self.base_klass(value, impl=tag_impl)
2953 with self.assertRaises(NotEnoughData):
2954 obj.decode(obj.encode()[:-1])
2956 @given(data_strategy())
2957 def test_stripped_expl(self, d):
2958 value = d.draw(datetimes(
2959 min_value=self.min_datetime,
2960 max_value=self.max_datetime,
2962 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2963 obj = self.base_klass(value, expl=tag_expl)
2964 with self.assertRaises(NotEnoughData):
2965 obj.decode(obj.encode()[:-1])
2967 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2968 @given(data_strategy())
2969 def test_symmetric(self, d):
2970 values = d.draw(generalized_time_values_strat(
2971 min_datetime=self.min_datetime,
2972 max_datetime=self.max_datetime,
2974 value = d.draw(datetimes(
2975 min_value=self.min_datetime,
2976 max_value=self.max_datetime,
2978 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2979 offset = d.draw(integers(min_value=0))
2980 _, _, _, default, optional, _decoded = values
2981 obj = self.base_klass(
2989 self.assertFalse(obj.expled)
2990 obj_encoded = obj.encode()
2991 obj_expled = obj(value, expl=tag_expl)
2992 self.assertTrue(obj_expled.expled)
2995 obj_expled_encoded = obj_expled.encode()
2996 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2999 self.assertEqual(tail, b"")
3000 self.assertEqual(obj_decoded, obj_expled)
3001 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3002 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3003 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3004 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3005 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3007 obj_decoded.expl_llen,
3008 len(len_encode(len(obj_encoded))),
3010 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3011 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3014 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3016 self.assertEqual(obj_decoded.expl_offset, offset)
3019 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3020 base_klass = GeneralizedTime
3022 min_datetime = datetime(1900, 1, 1)
3023 max_datetime = datetime(9999, 12, 31)
3025 def test_go_vectors_invalid(self):
3037 b"-20100102030410Z",
3038 b"2010-0102030410Z",
3039 b"2010-0002030410Z",
3040 b"201001-02030410Z",
3041 b"20100102-030410Z",
3042 b"2010010203-0410Z",
3043 b"201001020304-10Z",
3044 # These ones are INVALID in *DER*, but accepted
3045 # by Go's encoding/asn1
3046 b"20100102030405+0607",
3047 b"20100102030405-0607",
3049 with self.assertRaises(DecodeError) as err:
3050 GeneralizedTime(data)
3053 def test_go_vectors_valid(self):
3055 GeneralizedTime(b"20100102030405Z").todatetime(),
3056 datetime(2010, 1, 2, 3, 4, 5, 0),
3060 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3061 base_klass = UTCTime
3063 min_datetime = datetime(2000, 1, 1)
3064 max_datetime = datetime(2049, 12, 31)
3066 def test_go_vectors_invalid(self):
3092 # These ones are INVALID in *DER*, but accepted
3093 # by Go's encoding/asn1
3094 b"910506164540-0700",
3095 b"910506164540+0730",
3099 with self.assertRaises(DecodeError) as err:
3103 def test_go_vectors_valid(self):
3105 UTCTime(b"910506234540Z").todatetime(),
3106 datetime(1991, 5, 6, 23, 45, 40, 0),
3109 @given(integers(min_value=0, max_value=49))
3110 def test_pre50(self, year):
3112 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3116 @given(integers(min_value=50, max_value=99))
3117 def test_post50(self, year):
3119 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3125 def any_values_strat(draw, do_expl=False):
3126 value = draw(one_of(none(), binary()))
3129 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3130 optional = draw(one_of(none(), booleans()))
3132 draw(integers(min_value=0)),
3133 draw(integers(min_value=0)),
3134 draw(integers(min_value=0)),
3136 return (value, expl, optional, _decoded)
3139 class AnyInherited(Any):
3143 class TestAny(CommonMixin, TestCase):
3146 def test_invalid_value_type(self):
3147 with self.assertRaises(InvalidValueType) as err:
3152 def test_optional(self, optional):
3153 obj = Any(optional=optional)
3154 self.assertEqual(obj.optional, optional)
3157 def test_ready(self, value):
3159 self.assertFalse(obj.ready)
3162 with self.assertRaises(ObjNotReady) as err:
3166 self.assertTrue(obj.ready)
3171 def test_basic(self, value):
3172 integer_encoded = Integer(value).encode()
3174 Any(integer_encoded),
3175 Any(Integer(value)),
3176 Any(Any(Integer(value))),
3178 self.assertSequenceEqual(bytes(obj), integer_encoded)
3180 obj.decode(obj.encode())[0].vlen,
3181 len(integer_encoded),
3185 self.assertSequenceEqual(obj.encode(), integer_encoded)
3187 @given(binary(), binary())
3188 def test_comparison(self, value1, value2):
3189 for klass in (Any, AnyInherited):
3190 obj1 = klass(value1)
3191 obj2 = klass(value2)
3192 self.assertEqual(obj1 == obj2, value1 == value2)
3193 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3195 @given(data_strategy())
3196 def test_call(self, d):
3197 for klass in (Any, AnyInherited):
3203 ) = d.draw(any_values_strat())
3204 obj_initial = klass(
3207 optional_initial or False,
3215 ) = d.draw(any_values_strat(do_expl=True))
3216 obj = obj_initial(value, expl, optional)
3218 value_expected = None if value is None else value
3219 self.assertEqual(obj, value_expected)
3220 self.assertEqual(obj.expl_tag, expl or expl_initial)
3221 if obj.default is None:
3222 optional = optional_initial if optional is None else optional
3223 optional = False if optional is None else optional
3224 self.assertEqual(obj.optional, optional)
3226 def test_simultaneous_impl_expl(self):
3227 # override it, as Any does not have implicit tag
3230 def test_decoded(self):
3231 # override it, as Any does not have implicit tag
3234 @given(any_values_strat())
3235 def test_copy(self, values):
3236 for klass in (Any, AnyInherited):
3237 obj = klass(*values)
3238 obj_copied = obj.copy()
3239 self.assert_copied_basic_fields(obj, obj_copied)
3240 self.assertEqual(obj._value, obj_copied._value)
3242 @given(binary().map(OctetString))
3243 def test_stripped(self, value):
3245 with self.assertRaises(NotEnoughData):
3246 obj.decode(obj.encode()[:-1])
3250 integers(min_value=1).map(tag_ctxc),
3252 def test_stripped_expl(self, value, tag_expl):
3253 obj = Any(value, expl=tag_expl)
3254 with self.assertRaises(NotEnoughData):
3255 obj.decode(obj.encode()[:-1])
3258 integers(min_value=31),
3259 integers(min_value=0),
3262 def test_bad_tag(self, tag, offset, decode_path):
3263 decode_path = tuple(str(i) for i in decode_path)
3264 with self.assertRaises(DecodeError) as err:
3266 tag_encode(tag)[:-1],
3268 decode_path=decode_path,
3271 self.assertEqual(err.exception.offset, offset)
3272 self.assertEqual(err.exception.decode_path, decode_path)
3275 integers(min_value=128),
3276 integers(min_value=0),
3279 def test_bad_len(self, l, offset, decode_path):
3280 decode_path = tuple(str(i) for i in decode_path)
3281 with self.assertRaises(DecodeError) as err:
3283 Any.tag_default + len_encode(l)[:-1],
3285 decode_path=decode_path,
3288 self.assertEqual(err.exception.offset, offset)
3289 self.assertEqual(err.exception.decode_path, decode_path)
3291 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3294 integers().map(lambda x: Integer(x).encode()),
3295 integers(min_value=1).map(tag_ctxc),
3296 integers(min_value=0),
3298 def test_symmetric(self, values, value, tag_expl, offset):
3299 for klass in (Any, AnyInherited):
3300 _, _, optional, _decoded = values
3301 obj = klass(value=value, optional=optional, _decoded=_decoded)
3304 self.assertFalse(obj.expled)
3305 obj_encoded = obj.encode()
3306 obj_expled = obj(value, expl=tag_expl)
3307 self.assertTrue(obj_expled.expled)
3310 obj_expled_encoded = obj_expled.encode()
3311 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
3314 self.assertEqual(tail, b"")
3315 self.assertEqual(obj_decoded, obj_expled)
3316 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3317 self.assertEqual(bytes(obj_decoded), bytes(obj))
3318 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3319 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3320 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3322 obj_decoded.expl_llen,
3323 len(len_encode(len(obj_encoded))),
3325 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3326 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3329 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3331 self.assertEqual(obj_decoded.expl_offset, offset)
3332 self.assertEqual(obj_decoded.tlen, 0)
3333 self.assertEqual(obj_decoded.llen, 0)
3334 self.assertEqual(obj_decoded.vlen, len(value))
3338 def choice_values_strat(draw, value_required=False, schema=None, do_expl=False):
3340 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3341 tags = [tag_encode(tag) for tag in draw(sets(
3342 integers(min_value=0),
3343 min_size=len(names),
3344 max_size=len(names),
3346 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3348 if value_required or draw(booleans()):
3349 value = draw(tuples(
3350 sampled_from([name for name, _ in schema]),
3351 integers().map(Integer),
3355 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3356 default = draw(one_of(
3358 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3360 optional = draw(one_of(none(), booleans()))
3362 draw(integers(min_value=0)),
3363 draw(integers(min_value=0)),
3364 draw(integers(min_value=0)),
3366 return (schema, value, expl, default, optional, _decoded)
3369 class ChoiceInherited(Choice):
3373 class TestChoice(CommonMixin, TestCase):
3375 schema = (("whatever", Boolean()),)
3378 def test_schema_required(self):
3379 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3382 def test_impl_forbidden(self):
3383 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3384 Choice(impl=b"whatever")
3386 def test_invalid_value_type(self):
3387 with self.assertRaises(InvalidValueType) as err:
3388 self.base_klass(123)
3390 with self.assertRaises(ObjUnknown) as err:
3391 self.base_klass(("whenever", Boolean(False)))
3393 with self.assertRaises(InvalidValueType) as err:
3394 self.base_klass(("whatever", Integer(123)))
3398 def test_optional(self, optional):
3399 obj = self.base_klass(
3400 default=self.base_klass(("whatever", Boolean(False))),
3403 self.assertTrue(obj.optional)
3406 def test_ready(self, value):
3407 obj = self.base_klass()
3408 self.assertFalse(obj.ready)
3411 self.assertIsNone(obj["whatever"])
3412 with self.assertRaises(ObjNotReady) as err:
3415 obj["whatever"] = Boolean()
3416 self.assertFalse(obj.ready)
3419 obj["whatever"] = Boolean(value)
3420 self.assertTrue(obj.ready)
3424 @given(booleans(), booleans())
3425 def test_comparison(self, value1, value2):
3426 class WahlInherited(self.base_klass):
3428 for klass in (self.base_klass, WahlInherited):
3429 obj1 = klass(("whatever", Boolean(value1)))
3430 obj2 = klass(("whatever", Boolean(value2)))
3431 self.assertEqual(obj1 == obj2, value1 == value2)
3432 self.assertEqual(obj1 == obj2._value, value1 == value2)
3433 self.assertFalse(obj1 == obj2._value[1])
3435 @given(data_strategy())
3436 def test_call(self, d):
3437 for klass in (Choice, ChoiceInherited):
3445 ) = d.draw(choice_values_strat())
3449 schema = schema_initial
3451 value=value_initial,
3453 default=default_initial,
3454 optional=optional_initial or False,
3455 _decoded=_decoded_initial,
3464 ) = d.draw(choice_values_strat(schema=schema_initial, do_expl=True))
3465 obj = obj_initial(value, expl, default, optional)
3467 value_expected = default if value is None else value
3469 default_initial if value_expected is None
3472 self.assertEqual(obj.choice, value_expected[0])
3473 self.assertEqual(obj.value, int(value_expected[1]))
3474 self.assertEqual(obj.expl_tag, expl or expl_initial)
3475 default_expect = default_initial if default is None else default
3476 if default_expect is not None:
3477 self.assertEqual(obj.default.choice, default_expect[0])
3478 self.assertEqual(obj.default.value, int(default_expect[1]))
3479 if obj.default is None:
3480 optional = optional_initial if optional is None else optional
3481 optional = False if optional is None else optional
3484 self.assertEqual(obj.optional, optional)
3485 self.assertEqual(obj.specs, obj_initial.specs)
3487 def test_simultaneous_impl_expl(self):
3488 # override it, as Any does not have implicit tag
3491 def test_decoded(self):
3492 # override it, as Any does not have implicit tag
3495 @given(choice_values_strat())
3496 def test_copy(self, values):
3497 _schema, value, expl, default, optional, _decoded = values
3499 class Wahl(self.base_klass):
3506 optional=optional or False,
3509 obj_copied = obj.copy()
3510 self.assertIsNone(obj.tag)
3511 self.assertIsNone(obj_copied.tag)
3512 # hack for assert_copied_basic_fields
3513 obj.tag = "whatever"
3514 obj_copied.tag = "whatever"
3515 self.assert_copied_basic_fields(obj, obj_copied)
3516 self.assertEqual(obj._value, obj_copied._value)
3517 self.assertEqual(obj.specs, obj_copied.specs)
3520 def test_stripped(self, value):
3521 obj = self.base_klass(("whatever", Boolean(value)))
3522 with self.assertRaises(NotEnoughData):
3523 obj.decode(obj.encode()[:-1])
3527 integers(min_value=1).map(tag_ctxc),
3529 def test_stripped_expl(self, value, tag_expl):
3530 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3531 with self.assertRaises(NotEnoughData):
3532 obj.decode(obj.encode()[:-1])
3534 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3535 @given(data_strategy())
3536 def test_symmetric(self, d):
3537 _schema, value, _, default, optional, _decoded = d.draw(
3538 choice_values_strat(value_required=True)
3540 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3541 offset = d.draw(integers(min_value=0))
3543 class Wahl(self.base_klass):
3554 self.assertFalse(obj.expled)
3555 obj_encoded = obj.encode()
3556 obj_expled = obj(value, expl=tag_expl)
3557 self.assertTrue(obj_expled.expled)
3560 obj_expled_encoded = obj_expled.encode()
3561 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
3564 self.assertEqual(tail, b"")
3565 self.assertEqual(obj_decoded, obj_expled)
3566 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3567 self.assertEqual(obj_decoded.value, obj_expled.value)
3568 self.assertEqual(obj_decoded.choice, obj.choice)
3569 self.assertEqual(obj_decoded.value, obj.value)
3570 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3571 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3572 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3574 obj_decoded.expl_llen,
3575 len(len_encode(len(obj_encoded))),
3577 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3578 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3581 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3583 self.assertEqual(obj_decoded.expl_offset, offset)
3584 self.assertSequenceEqual(
3586 obj_decoded.value.offset - offset:
3587 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3593 def test_set_get(self, value):
3596 ("erste", Boolean()),
3597 ("zweite", Integer()),
3600 with self.assertRaises(ObjUnknown) as err:
3601 obj["whatever"] = "whenever"
3602 with self.assertRaises(InvalidValueType) as err:
3603 obj["zweite"] = Boolean(False)
3604 obj["zweite"] = Integer(value)
3606 with self.assertRaises(ObjUnknown) as err:
3609 self.assertIsNone(obj["erste"])
3610 self.assertEqual(obj["zweite"], Integer(value))
3612 def test_tag_mismatch(self):
3615 ("erste", Boolean()),
3617 int_encoded = Integer(123).encode()
3618 bool_encoded = Boolean(False).encode()
3620 obj.decode(bool_encoded)
3621 with self.assertRaises(TagMismatch):
3622 obj.decode(int_encoded)
3626 def seq_values_strat(draw, seq_klass, do_expl=False):
3628 if draw(booleans()):
3631 k: v for k, v in draw(dictionaries(
3634 booleans().map(Boolean),
3635 integers().map(Integer),
3640 if draw(booleans()):
3641 schema = list(draw(dictionaries(
3644 booleans().map(Boolean),
3645 integers().map(Integer),
3651 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3653 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3655 if draw(booleans()):
3656 default = seq_klass()
3658 k: v for k, v in draw(dictionaries(
3661 booleans().map(Boolean),
3662 integers().map(Integer),
3666 optional = draw(one_of(none(), booleans()))
3668 draw(integers(min_value=0)),
3669 draw(integers(min_value=0)),
3670 draw(integers(min_value=0)),
3672 return (value, schema, impl, expl, default, optional, _decoded)
3676 def sequence_strat(draw, seq_klass):
3677 inputs = draw(lists(
3679 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
3680 tuples(just(Integer), integers(), one_of(none(), integers())),
3685 integers(min_value=1),
3686 min_size=len(inputs),
3687 max_size=len(inputs),
3690 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3691 for tag, expled in zip(tags, draw(lists(
3693 min_size=len(inputs),
3694 max_size=len(inputs),
3698 for i, optional in enumerate(draw(lists(
3699 sampled_from(("required", "optional", "empty")),
3700 min_size=len(inputs),
3701 max_size=len(inputs),
3703 if optional in ("optional", "empty"):
3704 inits[i]["optional"] = True
3705 if optional == "empty":
3707 empties = set(empties)
3708 names = list(draw(sets(
3710 min_size=len(inputs),
3711 max_size=len(inputs),
3714 for i, (klass, value, default) in enumerate(inputs):
3715 schema.append((names[i], klass(default=default, **inits[i])))
3716 seq_name = draw(text_letters())
3717 Seq = type(seq_name, (seq_klass,), {"__slots__": (), "schema": tuple(schema)})
3720 for i, (klass, value, default) in enumerate(inputs):
3727 "default_value": None if spec.default is None else default,
3731 expect["optional"] = True
3733 expect["presented"] = True
3734 expect["value"] = value
3736 expect["optional"] = True
3737 if default is not None and default == value:
3738 expect["presented"] = False
3739 seq[name] = klass(value)
3740 expects.append(expect)
3745 def sequences_strat(draw, seq_klass):
3746 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
3748 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3749 for tag, expled in zip(tags, draw(lists(
3756 i for i, is_default in enumerate(draw(lists(
3762 names = list(draw(sets(
3767 seq_expectses = draw(lists(
3768 sequence_strat(seq_klass=seq_klass),
3772 seqs = [seq for seq, _ in seq_expectses]
3774 for i, (name, seq) in enumerate(zip(names, seqs)):
3777 seq(default=(seq if i in defaulted else None), **inits[i]),
3779 seq_name = draw(text_letters())
3780 Seq = type(seq_name, (seq_klass,), {"__slots__": (), "schema": tuple(schema)})
3783 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
3786 "expects": expects_inner,
3789 seq_outer[name] = seq_inner
3790 if seq_outer.specs[name].default is None:
3791 expect["presented"] = True
3792 expect_outers.append(expect)
3793 return seq_outer, expect_outers
3796 class SeqMixing(object):
3797 def test_invalid_value_type(self):
3798 with self.assertRaises(InvalidValueType) as err:
3799 self.base_klass((1, 2, 3))
3802 def test_invalid_value_type_set(self):
3803 class Seq(self.base_klass):
3805 schema = (("whatever", Boolean()),)
3807 with self.assertRaises(InvalidValueType) as err:
3808 seq["whatever"] = Integer(123)
3812 def test_optional(self, optional):
3813 obj = self.base_klass(default=self.base_klass(), optional=optional)
3814 self.assertTrue(obj.optional)
3816 @given(data_strategy())
3817 def test_ready(self, d):
3819 str(i): v for i, v in enumerate(d.draw(lists(
3826 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
3833 for name in d.draw(permutations(
3834 list(ready.keys()) + list(non_ready.keys()),
3836 schema_input.append((name, Boolean()))
3838 class Seq(self.base_klass):
3840 schema = tuple(schema_input)
3842 for name in ready.keys():
3844 seq[name] = Boolean()
3845 self.assertFalse(seq.ready)
3848 for name, value in ready.items():
3849 seq[name] = Boolean(value)
3850 self.assertFalse(seq.ready)
3853 with self.assertRaises(ObjNotReady) as err:
3856 for name, value in non_ready.items():
3857 seq[name] = Boolean(value)
3858 self.assertTrue(seq.ready)
3862 @given(data_strategy())
3863 def test_call(self, d):
3864 class SeqInherited(self.base_klass):
3866 for klass in (self.base_klass, SeqInherited):
3875 ) = d.draw(seq_values_strat(seq_klass=klass))
3876 obj_initial = klass(
3882 optional_initial or False,
3893 ) = d.draw(seq_values_strat(
3895 do_expl=impl_initial is None,
3897 obj = obj_initial(value, impl, expl, default, optional)
3898 value_expected = default if value is None else value
3900 default_initial if value_expected is None
3903 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
3904 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3905 self.assertEqual(obj.expl_tag, expl or expl_initial)
3907 {} if obj.default is None else obj.default._value,
3908 getattr(default_initial if default is None else default, "_value", {}),
3910 if obj.default is None:
3911 optional = optional_initial if optional is None else optional
3912 optional = False if optional is None else optional
3915 self.assertEqual(list(obj.specs.items()), schema_initial or [])
3916 self.assertEqual(obj.optional, optional)
3918 @given(data_strategy())
3919 def test_copy(self, d):
3920 class SeqInherited(self.base_klass):
3922 for klass in (self.base_klass, SeqInherited):
3923 values = d.draw(seq_values_strat(seq_klass=klass))
3924 obj = klass(*values)
3925 obj_copied = obj.copy()
3926 self.assert_copied_basic_fields(obj, obj_copied)
3927 self.assertEqual(obj.specs, obj_copied.specs)
3928 self.assertEqual(obj._value, obj_copied._value)
3930 @given(data_strategy())
3931 def test_stripped(self, d):
3932 value = d.draw(integers())
3933 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3935 class Seq(self.base_klass):
3938 schema = (("whatever", Integer()),)
3940 seq["whatever"] = Integer(value)
3941 with self.assertRaises(NotEnoughData):
3942 seq.decode(seq.encode()[:-1])
3944 @given(data_strategy())
3945 def test_stripped_expl(self, d):
3946 value = d.draw(integers())
3947 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3949 class Seq(self.base_klass):
3952 schema = (("whatever", Integer()),)
3954 seq["whatever"] = Integer(value)
3955 with self.assertRaises(NotEnoughData):
3956 seq.decode(seq.encode()[:-1])
3958 @given(binary(min_size=2))
3959 def test_non_tag_mismatch_raised(self, junk):
3961 _, _, len_encoded = tag_strip(memoryview(junk))
3962 len_decode(len_encoded)
3968 class Seq(self.base_klass):
3971 ("whatever", Integer()),
3973 ("whenever", Integer()),
3976 seq["whatever"] = Integer(123)
3977 seq["junk"] = Any(junk)
3978 seq["whenever"] = Integer(123)
3979 with self.assertRaises(DecodeError):
3980 seq.decode(seq.encode())
3983 integers(min_value=31),
3984 integers(min_value=0),
3987 def test_bad_tag(self, tag, offset, decode_path):
3988 decode_path = tuple(str(i) for i in decode_path)
3989 with self.assertRaises(DecodeError) as err:
3990 self.base_klass().decode(
3991 tag_encode(tag)[:-1],
3993 decode_path=decode_path,
3996 self.assertEqual(err.exception.offset, offset)
3997 self.assertEqual(err.exception.decode_path, decode_path)
4000 integers(min_value=128),
4001 integers(min_value=0),
4004 def test_bad_len(self, l, offset, decode_path):
4005 decode_path = tuple(str(i) for i in decode_path)
4006 with self.assertRaises(DecodeError) as err:
4007 self.base_klass().decode(
4008 self.base_klass.tag_default + len_encode(l)[:-1],
4010 decode_path=decode_path,
4013 self.assertEqual(err.exception.offset, offset)
4014 self.assertEqual(err.exception.decode_path, decode_path)
4016 def _assert_expects(self, seq, expects):
4017 for expect in expects:
4019 seq.specs[expect["name"]].optional,
4022 if expect["default_value"] is not None:
4024 seq.specs[expect["name"]].default,
4025 expect["default_value"],
4027 if expect["presented"]:
4028 self.assertIn(expect["name"], seq)
4029 self.assertEqual(seq[expect["name"]], expect["value"])
4031 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4032 @given(data_strategy())
4033 def test_symmetric(self, d):
4034 seq, expects = d.draw(sequence_strat(seq_klass=self.base_klass))
4035 self.assertTrue(seq.ready)
4036 self.assertFalse(seq.decoded)
4037 self._assert_expects(seq, expects)
4040 seq_encoded = seq.encode()
4041 seq_decoded, tail = seq.decode(seq_encoded)
4042 self.assertEqual(tail, b"")
4043 self.assertTrue(seq.ready)
4044 self._assert_expects(seq_decoded, expects)
4045 self.assertEqual(seq, seq_decoded)
4046 self.assertEqual(seq_decoded.encode(), seq_encoded)
4047 for expect in expects:
4048 if not expect["presented"]:
4049 self.assertNotIn(expect["name"], seq_decoded)
4051 self.assertIn(expect["name"], seq_decoded)
4052 obj = seq_decoded[expect["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],
4061 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4062 @given(data_strategy())
4063 def test_symmetric_with_seq(self, d):
4064 seq, expect_outers = d.draw(sequences_strat(seq_klass=self.base_klass))
4065 self.assertTrue(seq.ready)
4066 seq_encoded = seq.encode()
4067 seq_decoded, tail = seq.decode(seq_encoded)
4068 self.assertEqual(tail, b"")
4069 self.assertTrue(seq.ready)
4070 self.assertEqual(seq, seq_decoded)
4071 self.assertEqual(seq_decoded.encode(), seq_encoded)
4072 for expect_outer in expect_outers:
4073 if not expect_outer["presented"]:
4074 self.assertNotIn(expect_outer["name"], seq_decoded)
4076 self.assertIn(expect_outer["name"], seq_decoded)
4077 obj = seq_decoded[expect_outer["name"]]
4078 self.assertTrue(obj.decoded)
4079 offset = obj.expl_offset if obj.expled else obj.offset
4080 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4081 self.assertSequenceEqual(
4082 seq_encoded[offset:offset + tlvlen],
4085 self._assert_expects(obj, expect_outer["expects"])
4087 @given(data_strategy())
4088 def test_default_disappears(self, d):
4089 _schema = list(d.draw(dictionaries(
4091 sets(integers(), min_size=2, max_size=2),
4095 class Seq(self.base_klass):
4098 (n, Integer(default=d))
4099 for n, (_, d) in _schema
4102 for name, (value, _) in _schema:
4103 seq[name] = Integer(value)
4104 self.assertEqual(len(seq._value), len(_schema))
4105 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4106 self.assertGreater(len(seq.encode()), len(empty_seq))
4107 for name, (_, default) in _schema:
4108 seq[name] = Integer(default)
4109 self.assertEqual(len(seq._value), 0)
4110 self.assertSequenceEqual(seq.encode(), empty_seq)
4112 @given(data_strategy())
4113 def test_encoded_default_accepted(self, d):
4114 _schema = list(d.draw(dictionaries(
4119 tags = [tag_encode(tag) for tag in d.draw(sets(
4120 integers(min_value=0),
4121 min_size=len(_schema),
4122 max_size=len(_schema),
4125 class SeqWithoutDefault(self.base_klass):
4128 (n, Integer(impl=t))
4129 for (n, _), t in zip(_schema, tags)
4131 seq_without_default = SeqWithoutDefault()
4132 for name, value in _schema:
4133 seq_without_default[name] = Integer(value)
4134 seq_encoded = seq_without_default.encode()
4136 class SeqWithDefault(self.base_klass):
4139 (n, Integer(default=v, impl=t))
4140 for (n, v), t in zip(_schema, tags)
4142 seq_with_default = SeqWithDefault()
4143 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4144 for name, value in _schema:
4145 self.assertEqual(seq_decoded[name], seq_with_default[name])
4146 self.assertEqual(seq_decoded[name], value)
4148 @given(data_strategy())
4149 def test_missing_from_spec(self, d):
4150 names = list(d.draw(sets(text_letters(), min_size=2)))
4151 tags = [tag_encode(tag) for tag in d.draw(sets(
4152 integers(min_value=0),
4153 min_size=len(names),
4154 max_size=len(names),
4156 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4158 class SeqFull(self.base_klass):
4160 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4161 seq_full = SeqFull()
4162 for i, name in enumerate(names):
4163 seq_full[name] = Integer(i)
4164 seq_encoded = seq_full.encode()
4165 altered = names_tags[:-2] + names_tags[-1:]
4167 class SeqMissing(self.base_klass):
4169 schema = [(n, Integer(impl=t)) for n, t in altered]
4170 seq_missing = SeqMissing()
4171 with self.assertRaises(TagMismatch):
4172 seq_missing.decode(seq_encoded)
4175 class TestSequence(SeqMixing, CommonMixin, TestCase):
4176 base_klass = Sequence
4182 def test_remaining(self, value, junk):
4183 class Seq(Sequence):
4186 ("whatever", Integer()),
4188 int_encoded = Integer(value).encode()
4190 Sequence.tag_default,
4191 len_encode(len(int_encoded + junk)),
4194 with assertRaisesRegex(self, DecodeError, "remaining"):
4195 Seq().decode(junked)
4197 @given(sets(text_letters(), min_size=2))
4198 def test_obj_unknown(self, names):
4199 missing = names.pop()
4201 class Seq(Sequence):
4203 schema = [(n, Boolean()) for n in names]
4205 with self.assertRaises(ObjUnknown) as err:
4208 with self.assertRaises(ObjUnknown) as err:
4209 seq[missing] = Boolean()
4213 class TestSet(SeqMixing, CommonMixin, TestCase):
4216 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4217 @given(data_strategy())
4218 def test_sorted(self, d):
4220 tag_encode(tag) for tag in
4221 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4226 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4228 for name, _ in Seq.schema:
4229 seq[name] = OctetString(b"")
4230 seq_encoded = seq.encode()
4231 seq_decoded, _ = seq.decode(seq_encoded)
4232 self.assertSequenceEqual(
4233 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4234 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4239 def seqof_values_strat(draw, schema=None, do_expl=False):
4241 schema = draw(sampled_from((Boolean(), Integer())))
4242 bound_min, bound_max = sorted(draw(sets(
4243 integers(min_value=0, max_value=10),
4247 if isinstance(schema, Boolean):
4248 values_generator = booleans().map(Boolean)
4249 elif isinstance(schema, Integer):
4250 values_generator = integers().map(Integer)
4251 values_generator = lists(
4256 values = draw(one_of(none(), values_generator))
4260 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4262 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4263 default = draw(one_of(none(), values_generator))
4264 optional = draw(one_of(none(), booleans()))
4266 draw(integers(min_value=0)),
4267 draw(integers(min_value=0)),
4268 draw(integers(min_value=0)),
4273 (bound_min, bound_max),
4282 class SeqOfMixing(object):
4283 def test_invalid_value_type(self):
4284 with self.assertRaises(InvalidValueType) as err:
4285 self.base_klass(123)
4288 def test_invalid_values_type(self):
4289 class SeqOf(self.base_klass):
4292 with self.assertRaises(InvalidValueType) as err:
4293 SeqOf([Integer(123), Boolean(False), Integer(234)])
4296 def test_schema_required(self):
4297 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4298 self.base_klass.__mro__[1]()
4300 @given(booleans(), booleans(), binary(), binary())
4301 def test_comparison(self, value1, value2, tag1, tag2):
4302 class SeqOf(self.base_klass):
4305 obj1 = SeqOf([Boolean(value1)])
4306 obj2 = SeqOf([Boolean(value2)])
4307 self.assertEqual(obj1 == obj2, value1 == value2)
4308 self.assertEqual(obj1 == list(obj2), value1 == value2)
4309 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4310 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4311 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4312 self.assertEqual(obj1 == obj2, tag1 == tag2)
4314 @given(lists(booleans()))
4315 def test_iter(self, values):
4316 class SeqOf(self.base_klass):
4319 obj = SeqOf([Boolean(value) for value in values])
4320 self.assertEqual(len(obj), len(values))
4321 for i, value in enumerate(obj):
4322 self.assertEqual(value, values[i])
4324 @given(data_strategy())
4325 def test_ready(self, d):
4326 ready = [Integer(v) for v in d.draw(lists(
4333 range(d.draw(integers(min_value=1, max_value=5)))
4336 class SeqOf(self.base_klass):
4339 values = d.draw(permutations(ready + non_ready))
4341 for value in values:
4343 self.assertFalse(seqof.ready)
4346 with self.assertRaises(ObjNotReady) as err:
4349 for i, value in enumerate(values):
4350 self.assertEqual(seqof[i], value)
4351 if not seqof[i].ready:
4352 seqof[i] = Integer(i)
4353 self.assertTrue(seqof.ready)
4357 def test_spec_mismatch(self):
4358 class SeqOf(self.base_klass):
4362 seqof.append(Integer(123))
4363 with self.assertRaises(ValueError):
4364 seqof.append(Boolean(False))
4365 with self.assertRaises(ValueError):
4366 seqof[0] = Boolean(False)
4368 @given(data_strategy())
4369 def test_bounds_satisfied(self, d):
4370 class SeqOf(self.base_klass):
4373 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4374 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4375 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4376 SeqOf(value=value, bounds=(bound_min, bound_max))
4378 @given(data_strategy())
4379 def test_bounds_unsatisfied(self, d):
4380 class SeqOf(self.base_klass):
4383 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4384 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4385 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4386 with self.assertRaises(BoundsError) as err:
4387 SeqOf(value=value, bounds=(bound_min, bound_max))
4389 value = [Boolean()] * d.draw(integers(
4390 min_value=bound_max + 1,
4391 max_value=bound_max + 10,
4393 with self.assertRaises(BoundsError) as err:
4394 SeqOf(value=value, bounds=(bound_min, bound_max))
4397 @given(integers(min_value=1, max_value=10))
4398 def test_out_of_bounds(self, bound_max):
4399 class SeqOf(self.base_klass):
4402 bounds = (0, bound_max)
4404 for _ in range(bound_max):
4405 seqof.append(Integer(123))
4406 with self.assertRaises(BoundsError):
4407 seqof.append(Integer(123))
4409 @given(data_strategy())
4410 def test_call(self, d):
4420 ) = d.draw(seqof_values_strat())
4422 class SeqOf(self.base_klass):
4424 schema = schema_initial
4425 obj_initial = SeqOf(
4426 value=value_initial,
4427 bounds=bounds_initial,
4430 default=default_initial,
4431 optional=optional_initial or False,
4432 _decoded=_decoded_initial,
4443 ) = d.draw(seqof_values_strat(
4444 schema=schema_initial,
4445 do_expl=impl_initial is None,
4447 if (default is None) and (obj_initial.default is not None):
4450 (bounds is None) and
4451 (value is not None) and
4452 (bounds_initial is not None) and
4453 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4457 (bounds is None) and
4458 (default is not None) and
4459 (bounds_initial is not None) and
4460 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4472 value_expected = default if value is None else value
4474 default_initial if value_expected is None
4477 value_expected = () if value_expected is None else value_expected
4478 self.assertEqual(obj, value_expected)
4479 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4480 self.assertEqual(obj.expl_tag, expl or expl_initial)
4483 default_initial if default is None else default,
4485 if obj.default is None:
4486 optional = optional_initial if optional is None else optional
4487 optional = False if optional is None else optional
4490 self.assertEqual(obj.optional, optional)
4492 (obj._bound_min, obj._bound_max),
4493 bounds or bounds_initial or (0, float("+inf")),
4496 @given(seqof_values_strat())
4497 def test_copy(self, values):
4498 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4500 class SeqOf(self.base_klass):
4509 optional=optional or False,
4512 obj_copied = obj.copy()
4513 self.assert_copied_basic_fields(obj, obj_copied)
4514 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4515 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4516 self.assertEqual(obj._value, obj_copied._value)
4520 integers(min_value=1).map(tag_encode),
4522 def test_stripped(self, values, tag_impl):
4523 class SeqOf(self.base_klass):
4525 schema = OctetString()
4526 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4527 with self.assertRaises(NotEnoughData):
4528 obj.decode(obj.encode()[:-1])
4532 integers(min_value=1).map(tag_ctxc),
4534 def test_stripped_expl(self, values, tag_expl):
4535 class SeqOf(self.base_klass):
4537 schema = OctetString()
4538 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4539 with self.assertRaises(NotEnoughData):
4540 obj.decode(obj.encode()[:-1])
4543 integers(min_value=31),
4544 integers(min_value=0),
4547 def test_bad_tag(self, tag, offset, decode_path):
4548 decode_path = tuple(str(i) for i in decode_path)
4549 with self.assertRaises(DecodeError) as err:
4550 self.base_klass().decode(
4551 tag_encode(tag)[:-1],
4553 decode_path=decode_path,
4556 self.assertEqual(err.exception.offset, offset)
4557 self.assertEqual(err.exception.decode_path, decode_path)
4560 integers(min_value=128),
4561 integers(min_value=0),
4564 def test_bad_len(self, l, offset, decode_path):
4565 decode_path = tuple(str(i) for i in decode_path)
4566 with self.assertRaises(DecodeError) as err:
4567 self.base_klass().decode(
4568 self.base_klass.tag_default + len_encode(l)[:-1],
4570 decode_path=decode_path,
4573 self.assertEqual(err.exception.offset, offset)
4574 self.assertEqual(err.exception.decode_path, decode_path)
4576 @given(binary(min_size=1))
4577 def test_tag_mismatch(self, impl):
4578 assume(impl != self.base_klass.tag_default)
4579 with self.assertRaises(TagMismatch):
4580 self.base_klass(impl=impl).decode(self.base_klass().encode())
4582 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4584 seqof_values_strat(schema=Integer()),
4585 lists(integers().map(Integer)),
4586 integers(min_value=1).map(tag_ctxc),
4587 integers(min_value=0),
4589 def test_symmetric(self, values, value, tag_expl, offset):
4590 _, _, _, _, _, default, optional, _decoded = values
4592 class SeqOf(self.base_klass):
4603 self.assertFalse(obj.expled)
4604 obj_encoded = obj.encode()
4605 obj_expled = obj(value, expl=tag_expl)
4606 self.assertTrue(obj_expled.expled)
4609 obj_expled_encoded = obj_expled.encode()
4610 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
4613 self.assertEqual(tail, b"")
4614 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
4615 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4616 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4617 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4619 obj_decoded.expl_llen,
4620 len(len_encode(len(obj_encoded))),
4622 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4623 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4626 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4628 self.assertEqual(obj_decoded.expl_offset, offset)
4629 for obj_inner in obj_decoded:
4630 self.assertIn(obj_inner, obj_decoded)
4631 self.assertSequenceEqual(
4634 obj_inner.offset - offset:
4635 obj_inner.offset + obj_inner.tlvlen - offset
4640 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
4641 class SeqOf(SequenceOf):
4646 def _test_symmetric_compare_objs(self, obj1, obj2):
4647 self.assertEqual(obj1, obj2)
4648 self.assertSequenceEqual(list(obj1), list(obj2))
4651 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
4657 def _test_symmetric_compare_objs(self, obj1, obj2):
4658 self.assertSetEqual(
4659 set(int(v) for v in obj1),
4660 set(int(v) for v in obj2),
4663 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4664 @given(data_strategy())
4665 def test_sorted(self, d):
4666 values = [OctetString(v) for v in d.draw(lists(binary()))]
4670 schema = OctetString()
4672 seq_encoded = seq.encode()
4673 seq_decoded, _ = seq.decode(seq_encoded)
4674 self.assertSequenceEqual(
4675 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4676 b"".join(sorted([v.encode() for v in values])),
4680 class TestGoMarshalVectors(TestCase):
4682 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
4683 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
4684 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
4685 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
4686 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
4688 class Seq(Sequence):
4691 ("erste", Integer()),
4692 ("zweite", Integer(optional=True))
4695 seq["erste"] = Integer(64)
4696 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4697 seq["erste"] = Integer(0x123456)
4698 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
4699 seq["erste"] = Integer(64)
4700 seq["zweite"] = Integer(65)
4701 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
4703 class NestedSeq(Sequence):
4708 seq["erste"] = Integer(127)
4709 seq["zweite"] = None
4710 nested = NestedSeq()
4711 nested["nest"] = seq
4712 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
4714 self.assertSequenceEqual(
4715 OctetString(b"\x01\x02\x03").encode(),
4716 hexdec("0403010203"),
4719 class Seq(Sequence):
4722 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
4725 seq["erste"] = Integer(64)
4726 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
4728 class Seq(Sequence):
4731 ("erste", Integer(expl=tag_ctxc(5))),
4734 seq["erste"] = Integer(64)
4735 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
4737 class Seq(Sequence):
4741 impl=tag_encode(0, klass=TagClassContext),
4746 seq["erste"] = Null()
4747 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
4749 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4751 self.assertSequenceEqual(
4752 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
4753 hexdec("170d3730303130313030303030305a"),
4755 self.assertSequenceEqual(
4756 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
4757 hexdec("170d3039313131353232353631365a"),
4759 self.assertSequenceEqual(
4760 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
4761 hexdec("180f32313030303430353132303130315a"),
4764 class Seq(Sequence):
4767 ("erste", GeneralizedTime()),
4770 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
4771 self.assertSequenceEqual(
4773 hexdec("3011180f32303039313131353232353631365a"),
4776 self.assertSequenceEqual(
4777 BitString((1, b"\x80")).encode(),
4780 self.assertSequenceEqual(
4781 BitString((12, b"\x81\xF0")).encode(),
4782 hexdec("03030481f0"),
4785 self.assertSequenceEqual(
4786 ObjectIdentifier("1.2.3.4").encode(),
4787 hexdec("06032a0304"),
4789 self.assertSequenceEqual(
4790 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
4791 hexdec("06092a864888932d010105"),
4793 self.assertSequenceEqual(
4794 ObjectIdentifier("2.100.3").encode(),
4795 hexdec("0603813403"),
4798 self.assertSequenceEqual(
4799 PrintableString("test").encode(),
4800 hexdec("130474657374"),
4802 self.assertSequenceEqual(
4803 PrintableString("x" * 127).encode(),
4804 hexdec("137F" + "78" * 127),
4806 self.assertSequenceEqual(
4807 PrintableString("x" * 128).encode(),
4808 hexdec("138180" + "78" * 128),
4810 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
4812 class Seq(Sequence):
4815 ("erste", IA5String()),
4818 seq["erste"] = IA5String("test")
4819 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
4821 class Seq(Sequence):
4824 ("erste", PrintableString()),
4827 seq["erste"] = PrintableString("test")
4828 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
4829 seq["erste"] = PrintableString("test*")
4830 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
4832 class Seq(Sequence):
4835 ("erste", Any(optional=True)),
4836 ("zweite", Integer()),
4839 seq["zweite"] = Integer(64)
4840 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4846 seq.append(Integer(10))
4847 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
4849 class _SeqOf(SequenceOf):
4851 schema = PrintableString()
4853 class SeqOf(SequenceOf):
4857 _seqof.append(PrintableString("1"))
4859 seqof.append(_seqof)
4860 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
4862 class Seq(Sequence):
4865 ("erste", Integer(default=1)),
4868 seq["erste"] = Integer(0)
4869 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
4870 seq["erste"] = Integer(1)
4871 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4872 seq["erste"] = Integer(2)
4873 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
4876 class TestPP(TestCase):
4877 @given(data_strategy())
4878 def test_oid_printing(self, d):
4880 str(ObjectIdentifier(k)): v * 2
4881 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
4883 chosen = d.draw(sampled_from(sorted(oids)))
4884 chosen_id = oids[chosen]
4885 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
4886 self.assertNotIn(chosen_id, pp_console_row(pp))
4887 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))