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 decode_path_defby
60 from pyderasn import DecodeError
61 from pyderasn import Enumerated
62 from pyderasn import GeneralizedTime
63 from pyderasn import GeneralString
64 from pyderasn import GraphicString
65 from pyderasn import hexdec
66 from pyderasn import hexenc
67 from pyderasn import IA5String
68 from pyderasn import Integer
69 from pyderasn import InvalidLength
70 from pyderasn import InvalidOID
71 from pyderasn import InvalidValueType
72 from pyderasn import len_decode
73 from pyderasn import len_encode
74 from pyderasn import NotEnoughData
75 from pyderasn import Null
76 from pyderasn import NumericString
77 from pyderasn import ObjectIdentifier
78 from pyderasn import ObjNotReady
79 from pyderasn import ObjUnknown
80 from pyderasn import OctetString
81 from pyderasn import pp_console_row
82 from pyderasn import pprint
83 from pyderasn import PrintableString
84 from pyderasn import Sequence
85 from pyderasn import SequenceOf
86 from pyderasn import Set
87 from pyderasn import SetOf
88 from pyderasn import tag_ctxc
89 from pyderasn import tag_ctxp
90 from pyderasn import tag_decode
91 from pyderasn import tag_encode
92 from pyderasn import tag_strip
93 from pyderasn import TagClassApplication
94 from pyderasn import TagClassContext
95 from pyderasn import TagClassPrivate
96 from pyderasn import TagClassUniversal
97 from pyderasn import TagFormConstructed
98 from pyderasn import TagFormPrimitive
99 from pyderasn import TagMismatch
100 from pyderasn import TeletexString
101 from pyderasn import UniversalString
102 from pyderasn import UTCTime
103 from pyderasn import UTF8String
104 from pyderasn import VideotexString
105 from pyderasn import VisibleString
108 settings.register_profile('local', settings(
110 perform_health_check=False,
112 settings.load_profile('local')
113 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
115 tag_classes = sampled_from((
121 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
124 class TestHex(TestCase):
126 def test_symmetric(self, data):
127 self.assertEqual(hexdec(hexenc(data)), data)
130 class TestTagCoder(TestCase):
131 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
135 integers(min_value=0, max_value=30),
138 def test_short(self, klass, form, num, junk):
139 raw = tag_encode(klass=klass, form=form, num=num)
140 self.assertEqual(tag_decode(raw), (klass, form, num))
141 self.assertEqual(len(raw), 1)
143 byte2int(tag_encode(klass=klass, form=form, num=0)),
144 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
146 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
147 self.assertSequenceEqual(stripped.tobytes(), raw)
148 self.assertEqual(tlen, len(raw))
149 self.assertSequenceEqual(tail, junk)
151 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
155 integers(min_value=31),
158 def test_long(self, klass, form, num, junk):
159 raw = tag_encode(klass=klass, form=form, num=num)
160 self.assertEqual(tag_decode(raw), (klass, form, num))
161 self.assertGreater(len(raw), 1)
163 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
166 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
167 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
168 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
169 self.assertSequenceEqual(stripped.tobytes(), raw)
170 self.assertEqual(tlen, len(raw))
171 self.assertSequenceEqual(tail, junk)
173 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
174 @given(integers(min_value=31))
175 def test_unfinished_tag(self, num):
176 raw = bytearray(tag_encode(num=num))
177 for i in range(1, len(raw)):
179 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
180 tag_strip(bytes(raw))
182 def test_go_vectors_valid(self):
183 for data, (eklass, etag, elen, eform) in (
184 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
185 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
186 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
187 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
188 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
189 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
190 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
191 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
192 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
193 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
195 tag, _, len_encoded = tag_strip(memoryview(data))
196 klass, form, num = tag_decode(tag)
197 _len, _, tail = len_decode(len_encoded)
198 self.assertSequenceEqual(tail, b"")
199 self.assertEqual(klass, eklass)
200 self.assertEqual(num, etag)
201 self.assertEqual(_len, elen)
202 self.assertEqual(form, eform)
204 def test_go_vectors_invalid(self):
212 with self.assertRaises(DecodeError):
213 _, _, len_encoded = tag_strip(memoryview(data))
214 len_decode(len_encoded)
217 integers(min_value=0, max_value=127),
218 integers(min_value=0, max_value=2),
220 def test_long_instead_of_short(self, l, dummy_num):
221 octets = (b"\x00" * dummy_num) + int2byte(l)
222 octets = int2byte((dummy_num + 1) | 0x80) + octets
223 with self.assertRaises(DecodeError):
227 class TestLenCoder(TestCase):
228 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
230 integers(min_value=0, max_value=127),
233 def test_short(self, l, junk):
234 raw = len_encode(l) + junk
235 decoded, llen, tail = len_decode(memoryview(raw))
236 self.assertEqual(decoded, l)
237 self.assertEqual(llen, 1)
238 self.assertEqual(len(raw), 1 + len(junk))
239 self.assertEqual(tail.tobytes(), junk)
241 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
243 integers(min_value=128),
246 def test_long(self, l, junk):
247 raw = len_encode(l) + junk
248 decoded, llen, tail = len_decode(memoryview(raw))
249 self.assertEqual(decoded, l)
250 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
251 self.assertEqual(llen, len(raw) - len(junk))
252 self.assertNotEqual(indexbytes(raw, 1), 0)
253 self.assertSequenceEqual(tail.tobytes(), junk)
255 def test_empty(self):
256 with self.assertRaises(NotEnoughData):
259 @given(integers(min_value=128))
260 def test_stripped(self, _len):
261 with self.assertRaises(NotEnoughData):
262 len_decode(len_encode(_len)[:-1])
265 text_printable = text(alphabet=printable, min_size=1)
269 def text_letters(draw):
270 result = draw(text(alphabet=ascii_letters, min_size=1))
272 result = result.encode("ascii")
276 class CommonMixin(object):
277 def test_tag_default(self):
278 obj = self.base_klass()
279 self.assertEqual(obj.tag, obj.tag_default)
281 def test_simultaneous_impl_expl(self):
282 with self.assertRaises(ValueError):
283 self.base_klass(impl=b"whatever", expl=b"whenever")
285 @given(binary(), integers(), integers(), integers())
286 def test_decoded(self, impl, offset, llen, vlen):
287 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
288 self.assertEqual(obj.offset, offset)
289 self.assertEqual(obj.llen, llen)
290 self.assertEqual(obj.vlen, vlen)
291 self.assertEqual(obj.tlen, len(impl))
292 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
295 def test_impl_inherited(self, impl_tag):
296 class Inherited(self.base_klass):
299 self.assertSequenceEqual(obj.impl, impl_tag)
300 self.assertFalse(obj.expled)
303 def test_expl_inherited(self, expl_tag):
304 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_strategy(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 != obj2, value1 != value2)
378 self.assertEqual(obj1 == bool(obj2), value1 == value2)
379 obj1 = klass(value1, impl=tag1)
380 obj2 = klass(value1, impl=tag2)
381 self.assertEqual(obj1 == obj2, tag1 == tag2)
382 self.assertEqual(obj1 != obj2, tag1 != tag2)
384 @given(data_strategy())
385 def test_call(self, d):
386 for klass in (Boolean, BooleanInherited):
394 ) = d.draw(boolean_values_strategy())
400 optional_initial or False,
410 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
411 obj = obj_initial(value, impl, expl, default, optional)
413 value_expected = default if value is None else value
415 default_initial if value_expected is None
418 self.assertEqual(obj, value_expected)
419 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
420 self.assertEqual(obj.expl_tag, expl or expl_initial)
423 default_initial if default is None else default,
425 if obj.default is None:
426 optional = optional_initial if optional is None else optional
427 optional = False if optional is None else optional
430 self.assertEqual(obj.optional, optional)
432 @given(boolean_values_strategy())
433 def test_copy(self, values):
434 for klass in (Boolean, BooleanInherited):
436 obj_copied = obj.copy()
437 self.assert_copied_basic_fields(obj, obj_copied)
441 integers(min_value=1).map(tag_encode),
443 def test_stripped(self, value, tag_impl):
444 obj = Boolean(value, impl=tag_impl)
445 with self.assertRaises(NotEnoughData):
446 obj.decode(obj.encode()[:-1])
450 integers(min_value=1).map(tag_ctxc),
452 def test_stripped_expl(self, value, tag_expl):
453 obj = Boolean(value, expl=tag_expl)
454 with self.assertRaises(NotEnoughData):
455 obj.decode(obj.encode()[:-1])
458 integers(min_value=31),
459 integers(min_value=0),
462 def test_bad_tag(self, tag, offset, decode_path):
463 decode_path = tuple(str(i) for i in decode_path)
464 with self.assertRaises(DecodeError) as err:
466 tag_encode(tag)[:-1],
468 decode_path=decode_path,
471 self.assertEqual(err.exception.offset, offset)
472 self.assertEqual(err.exception.decode_path, decode_path)
475 integers(min_value=31),
476 integers(min_value=0),
479 def test_bad_expl_tag(self, tag, offset, decode_path):
480 decode_path = tuple(str(i) for i in decode_path)
481 with self.assertRaises(DecodeError) as err:
482 Boolean(expl=Boolean.tag_default).decode(
483 tag_encode(tag)[:-1],
485 decode_path=decode_path,
488 self.assertEqual(err.exception.offset, offset)
489 self.assertEqual(err.exception.decode_path, decode_path)
492 integers(min_value=128),
493 integers(min_value=0),
496 def test_bad_len(self, l, offset, decode_path):
497 decode_path = tuple(str(i) for i in decode_path)
498 with self.assertRaises(DecodeError) as err:
500 Boolean.tag_default + len_encode(l)[:-1],
502 decode_path=decode_path,
505 self.assertEqual(err.exception.offset, offset)
506 self.assertEqual(err.exception.decode_path, decode_path)
509 integers(min_value=128),
510 integers(min_value=0),
513 def test_bad_expl_len(self, l, offset, decode_path):
514 decode_path = tuple(str(i) for i in decode_path)
515 with self.assertRaises(DecodeError) as err:
516 Boolean(expl=Boolean.tag_default).decode(
517 Boolean.tag_default + len_encode(l)[:-1],
519 decode_path=decode_path,
522 self.assertEqual(err.exception.offset, offset)
523 self.assertEqual(err.exception.decode_path, decode_path)
525 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
527 boolean_values_strategy(),
529 integers(min_value=1).map(tag_ctxc),
530 integers(min_value=0),
532 def test_symmetric(self, values, value, tag_expl, offset):
533 for klass in (Boolean, BooleanInherited):
534 _, _, _, default, optional, _decoded = values
543 self.assertFalse(obj.expled)
544 obj_encoded = obj.encode()
545 obj_expled = obj(value, expl=tag_expl)
546 self.assertTrue(obj_expled.expled)
549 obj_expled_encoded = obj_expled.encode()
550 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
553 self.assertEqual(tail, b"")
554 self.assertEqual(obj_decoded, obj_expled)
555 self.assertNotEqual(obj_decoded, obj)
556 self.assertEqual(bool(obj_decoded), bool(obj_expled))
557 self.assertEqual(bool(obj_decoded), bool(obj))
558 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
559 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
560 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
562 obj_decoded.expl_llen,
563 len(len_encode(len(obj_encoded))),
565 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
566 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
569 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
571 self.assertEqual(obj_decoded.expl_offset, offset)
573 @given(integers(min_value=2))
574 def test_invalid_len(self, l):
575 with self.assertRaises(InvalidLength):
576 Boolean().decode(b"".join((
582 @given(integers(min_value=0 + 1, max_value=255 - 1))
583 def test_invalid_value(self, value):
584 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
585 Boolean().decode(b"".join((
593 def integer_values_strategy(draw, do_expl=False):
594 bound_min, value, default, bound_max = sorted(draw(sets(
603 _specs = draw(sets(text_letters()))
606 min_size=len(_specs),
607 max_size=len(_specs),
609 _specs = list(zip(_specs, values))
612 bounds = (bound_min, bound_max)
616 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
618 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
621 optional = draw(one_of(none(), booleans()))
623 draw(integers(min_value=0)),
624 draw(integers(min_value=0)),
625 draw(integers(min_value=0)),
627 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
630 class IntegerInherited(Integer):
634 class TestInteger(CommonMixin, TestCase):
637 def test_invalid_value_type(self):
638 with self.assertRaises(InvalidValueType) as err:
642 @given(sets(text_letters(), min_size=2))
643 def test_unknown_name(self, names_input):
644 missing = names_input.pop()
647 schema = [(n, 123) for n in names_input]
648 with self.assertRaises(ObjUnknown) as err:
652 @given(sets(text_letters(), min_size=2))
653 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 != obj2, value1 != value2)
685 self.assertEqual(obj1 == int(obj2), value1 == value2)
686 obj1 = klass(value1, impl=tag1)
687 obj2 = klass(value1, impl=tag2)
688 self.assertEqual(obj1 == obj2, tag1 == tag2)
689 self.assertEqual(obj1 != obj2, tag1 != tag2)
691 @given(lists(integers()))
692 def test_sorted_works(self, values):
693 self.assertSequenceEqual(
694 [int(v) for v in sorted(Integer(v) for v in values)],
698 @given(data_strategy())
699 def test_named(self, d):
700 names_input = list(d.draw(sets(text_letters(), min_size=1)))
701 values_input = list(d.draw(sets(
703 min_size=len(names_input),
704 max_size=len(names_input),
706 chosen_name = d.draw(sampled_from(names_input))
707 names_input = dict(zip(names_input, values_input))
711 _int = Int(chosen_name)
712 self.assertEqual(_int.named, chosen_name)
713 self.assertEqual(int(_int), names_input[chosen_name])
715 @given(integers(), integers(min_value=0), integers(min_value=0))
716 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
717 value = bound_min + value_delta
718 bound_max = value + bound_delta
719 Integer(value=value, bounds=(bound_min, bound_max))
721 @given(sets(integers(), min_size=3, max_size=3))
722 def test_bounds_unsatisfied(self, values):
723 values = sorted(values)
724 with self.assertRaises(BoundsError) as err:
725 Integer(value=values[0], bounds=(values[1], values[2]))
727 with self.assertRaises(BoundsError) as err:
728 Integer(value=values[2], bounds=(values[0], values[1]))
731 @given(data_strategy())
732 def test_call(self, d):
733 for klass in (Integer, IntegerInherited):
743 ) = d.draw(integer_values_strategy())
750 optional_initial or False,
763 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
764 if (default is None) and (obj_initial.default is not None):
768 (value is not None) and
769 (bounds_initial is not None) and
770 not (bounds_initial[0] <= value <= bounds_initial[1])
775 (default is not None) and
776 (bounds_initial is not None) and
777 not (bounds_initial[0] <= default <= bounds_initial[1])
780 obj = obj_initial(value, bounds, impl, expl, default, optional)
782 value_expected = default if value is None else value
784 default_initial if value_expected is None
787 self.assertEqual(obj, value_expected)
788 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
789 self.assertEqual(obj.expl_tag, expl or expl_initial)
792 default_initial if default is None else default,
794 if obj.default is None:
795 optional = optional_initial if optional is None else optional
796 optional = False if optional is None else optional
799 self.assertEqual(obj.optional, optional)
801 (obj._bound_min, obj._bound_max),
802 bounds or bounds_initial or (float("-inf"), float("+inf")),
806 {} if _specs_initial is None else dict(_specs_initial),
809 @given(integer_values_strategy())
810 def test_copy(self, values):
811 for klass in (Integer, IntegerInherited):
813 obj_copied = obj.copy()
814 self.assert_copied_basic_fields(obj, obj_copied)
815 self.assertEqual(obj.specs, obj_copied.specs)
816 self.assertEqual(obj._bound_min, obj_copied._bound_min)
817 self.assertEqual(obj._bound_max, obj_copied._bound_max)
818 self.assertEqual(obj._value, obj_copied._value)
822 integers(min_value=1).map(tag_encode),
824 def test_stripped(self, value, tag_impl):
825 obj = Integer(value, impl=tag_impl)
826 with self.assertRaises(NotEnoughData):
827 obj.decode(obj.encode()[:-1])
831 integers(min_value=1).map(tag_ctxc),
833 def test_stripped_expl(self, value, tag_expl):
834 obj = Integer(value, expl=tag_expl)
835 with self.assertRaises(NotEnoughData):
836 obj.decode(obj.encode()[:-1])
838 def test_zero_len(self):
839 with self.assertRaises(NotEnoughData):
840 Integer().decode(b"".join((
846 integers(min_value=31),
847 integers(min_value=0),
850 def test_bad_tag(self, tag, offset, decode_path):
851 decode_path = tuple(str(i) for i in decode_path)
852 with self.assertRaises(DecodeError) as err:
854 tag_encode(tag)[:-1],
856 decode_path=decode_path,
859 self.assertEqual(err.exception.offset, offset)
860 self.assertEqual(err.exception.decode_path, decode_path)
863 integers(min_value=128),
864 integers(min_value=0),
867 def test_bad_len(self, l, offset, decode_path):
868 decode_path = tuple(str(i) for i in decode_path)
869 with self.assertRaises(DecodeError) as err:
871 Integer.tag_default + len_encode(l)[:-1],
873 decode_path=decode_path,
876 self.assertEqual(err.exception.offset, offset)
877 self.assertEqual(err.exception.decode_path, decode_path)
880 sets(integers(), min_size=2, max_size=2),
881 integers(min_value=0),
884 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
885 decode_path = tuple(str(i) for i in decode_path)
886 value, bound_min = list(sorted(ints))
889 bounds = (bound_min, bound_min)
890 with self.assertRaises(DecodeError) as err:
892 Integer(value).encode(),
894 decode_path=decode_path,
897 self.assertEqual(err.exception.offset, offset)
898 self.assertEqual(err.exception.decode_path, decode_path)
900 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
902 integer_values_strategy(),
904 integers(min_value=1).map(tag_ctxc),
905 integers(min_value=0),
907 def test_symmetric(self, values, value, tag_expl, offset):
908 for klass in (Integer, IntegerInherited):
909 _, _, _, _, default, optional, _, _decoded = values
918 self.assertFalse(obj.expled)
919 obj_encoded = obj.encode()
920 obj_expled = obj(value, expl=tag_expl)
921 self.assertTrue(obj_expled.expled)
924 obj_expled_encoded = obj_expled.encode()
925 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
928 self.assertEqual(tail, b"")
929 self.assertEqual(obj_decoded, obj_expled)
930 self.assertNotEqual(obj_decoded, obj)
931 self.assertEqual(int(obj_decoded), int(obj_expled))
932 self.assertEqual(int(obj_decoded), int(obj))
933 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
934 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
935 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
937 obj_decoded.expl_llen,
938 len(len_encode(len(obj_encoded))),
940 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
941 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
944 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
946 self.assertEqual(obj_decoded.expl_offset, offset)
948 def test_go_vectors_valid(self):
949 for data, expect in ((
961 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
962 (b"\x80\x00\x00\x00", -2147483648),
965 Integer().decode(b"".join((
967 len_encode(len(data)),
973 def test_go_vectors_invalid(self):
978 with self.assertRaises(DecodeError):
979 Integer().decode(b"".join((
981 len_encode(len(data)),
987 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
991 schema = draw(sets(text_letters(), min_size=1, max_size=256))
993 integers(min_value=0, max_value=255),
994 min_size=len(schema),
995 max_size=len(schema),
997 schema = list(zip(schema, bits))
999 def _value(value_required):
1000 if not value_required and draw(booleans()):
1002 generation_choice = 0
1004 generation_choice = draw(sampled_from((1, 2, 3)))
1005 if generation_choice == 1 or draw(booleans()):
1006 return "'%s'B" % "".join(draw(lists(
1007 sampled_from(("0", "1")),
1008 max_size=len(schema),
1010 elif generation_choice == 2 or draw(booleans()):
1011 return draw(binary(max_size=len(schema) // 8))
1012 elif generation_choice == 3 or draw(booleans()):
1013 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1015 value = _value(value_required)
1016 default = _value(value_required=False)
1020 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1022 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1023 optional = draw(one_of(none(), booleans()))
1025 draw(integers(min_value=0)),
1026 draw(integers(min_value=0)),
1027 draw(integers(min_value=0)),
1029 return (schema, value, impl, expl, default, optional, _decoded)
1032 class BitStringInherited(BitString):
1036 class TestBitString(CommonMixin, TestCase):
1037 base_klass = BitString
1039 @given(lists(booleans()))
1040 def test_b_encoding(self, bits):
1041 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1042 self.assertEqual(obj.bit_len, len(bits))
1043 self.assertSequenceEqual(list(obj), bits)
1044 for i, bit in enumerate(bits):
1045 self.assertEqual(obj[i], bit)
1047 @given(lists(booleans()))
1048 def test_out_of_bounds_bits(self, bits):
1049 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1050 for i in range(len(bits), len(bits) * 2):
1051 self.assertFalse(obj[i])
1053 def test_bad_b_encoding(self):
1054 with self.assertRaises(ValueError):
1055 BitString("'010120101'B")
1058 integers(min_value=1, max_value=255),
1059 integers(min_value=1, max_value=255),
1061 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1062 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1063 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1064 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1066 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_type(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):
1103 schema = [(n, i) for i, n in enumerate(_schema)]
1104 with self.assertRaises(ObjUnknown) as err:
1109 def test_optional(self, optional):
1110 obj = BitString(default=BitString(b""), optional=optional)
1111 self.assertTrue(obj.optional)
1114 def test_ready(self, value):
1116 self.assertFalse(obj.ready)
1119 with self.assertRaises(ObjNotReady) as err:
1122 obj = BitString(value)
1123 self.assertTrue(obj.ready)
1128 tuples(integers(min_value=0), binary()),
1129 tuples(integers(min_value=0), binary()),
1133 def test_comparison(self, value1, value2, tag1, tag2):
1134 for klass in (BitString, BitStringInherited):
1135 obj1 = klass(value1)
1136 obj2 = klass(value2)
1137 self.assertEqual(obj1 == obj2, value1 == 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)
1143 self.assertEqual(obj1 != obj2, tag1 != tag2)
1145 @given(data_strategy())
1146 def test_call(self, d):
1147 for klass in (BitString, BitStringInherited):
1156 ) = d.draw(bit_string_values_strategy())
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_strategy(
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_strategy())
1198 def test_copy(self, values):
1199 for klass in (BitString, BitStringInherited):
1200 _schema, value, impl, expl, default, optional, _decoded = values
1209 optional=optional or False,
1212 obj_copied = obj.copy()
1213 self.assert_copied_basic_fields(obj, obj_copied)
1214 self.assertEqual(obj.specs, obj_copied.specs)
1215 self.assertEqual(obj._value, obj_copied._value)
1219 integers(min_value=1).map(tag_encode),
1221 def test_stripped(self, value, tag_impl):
1222 obj = BitString(value, impl=tag_impl)
1223 with self.assertRaises(NotEnoughData):
1224 obj.decode(obj.encode()[:-1])
1228 integers(min_value=1).map(tag_ctxc),
1230 def test_stripped_expl(self, value, tag_expl):
1231 obj = BitString(value, expl=tag_expl)
1232 with self.assertRaises(NotEnoughData):
1233 obj.decode(obj.encode()[:-1])
1236 integers(min_value=31),
1237 integers(min_value=0),
1240 def test_bad_tag(self, tag, offset, decode_path):
1241 decode_path = tuple(str(i) for i in decode_path)
1242 with self.assertRaises(DecodeError) as err:
1244 tag_encode(tag)[:-1],
1246 decode_path=decode_path,
1249 self.assertEqual(err.exception.offset, offset)
1250 self.assertEqual(err.exception.decode_path, decode_path)
1253 integers(min_value=128),
1254 integers(min_value=0),
1257 def test_bad_len(self, l, offset, decode_path):
1258 decode_path = tuple(str(i) for i in decode_path)
1259 with self.assertRaises(DecodeError) as err:
1261 BitString.tag_default + len_encode(l)[:-1],
1263 decode_path=decode_path,
1266 self.assertEqual(err.exception.offset, offset)
1267 self.assertEqual(err.exception.decode_path, decode_path)
1269 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1270 @given(data_strategy())
1271 def test_symmetric(self, d):
1280 ) = d.draw(bit_string_values_strategy(value_required=True))
1281 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1282 offset = d.draw(integers(min_value=0))
1283 for klass in (BitString, BitStringInherited):
1294 self.assertFalse(obj.expled)
1295 obj_encoded = obj.encode()
1296 obj_expled = obj(value, expl=tag_expl)
1297 self.assertTrue(obj_expled.expled)
1300 obj_expled_encoded = obj_expled.encode()
1301 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1304 self.assertEqual(tail, b"")
1305 self.assertEqual(obj_decoded, obj_expled)
1306 self.assertNotEqual(obj_decoded, obj)
1307 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1308 self.assertEqual(bytes(obj_decoded), bytes(obj))
1309 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1310 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1311 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1313 obj_decoded.expl_llen,
1314 len(len_encode(len(obj_encoded))),
1316 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1317 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1320 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1322 self.assertEqual(obj_decoded.expl_offset, offset)
1323 if isinstance(value, tuple):
1324 self.assertSetEqual(set(value), set(obj_decoded.named))
1328 @given(integers(min_value=1, max_value=255))
1329 def test_bad_zero_value(self, pad_size):
1330 with self.assertRaises(DecodeError):
1331 BitString().decode(b"".join((
1332 BitString.tag_default,
1337 def test_go_vectors_invalid(self):
1343 with self.assertRaises(DecodeError):
1344 BitString().decode(b"".join((
1345 BitString.tag_default,
1350 def test_go_vectors_valid(self):
1351 obj, _ = BitString().decode(b"".join((
1352 BitString.tag_default,
1356 self.assertEqual(bytes(obj), b"")
1357 self.assertEqual(obj.bit_len, 0)
1359 obj, _ = BitString().decode(b"".join((
1360 BitString.tag_default,
1364 self.assertEqual(bytes(obj), b"\x00")
1365 self.assertEqual(obj.bit_len, 1)
1367 obj = BitString((16, b"\x82\x40"))
1368 self.assertTrue(obj[0])
1369 self.assertFalse(obj[1])
1370 self.assertTrue(obj[6])
1371 self.assertTrue(obj[9])
1372 self.assertFalse(obj[17])
1376 def octet_string_values_strategy(draw, do_expl=False):
1377 bound_min, bound_max = sorted(draw(sets(
1378 integers(min_value=0, max_value=1 << 7),
1382 value = draw(one_of(
1384 binary(min_size=bound_min, max_size=bound_max),
1386 default = draw(one_of(
1388 binary(min_size=bound_min, max_size=bound_max),
1391 if draw(booleans()):
1392 bounds = (bound_min, bound_max)
1396 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1398 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1399 optional = draw(one_of(none(), booleans()))
1401 draw(integers(min_value=0)),
1402 draw(integers(min_value=0)),
1403 draw(integers(min_value=0)),
1405 return (value, bounds, impl, expl, default, optional, _decoded)
1408 class OctetStringInherited(OctetString):
1412 class TestOctetString(CommonMixin, TestCase):
1413 base_klass = OctetString
1415 def test_invalid_value_type(self):
1416 with self.assertRaises(InvalidValueType) as err:
1417 OctetString(text_type(123))
1421 def test_optional(self, optional):
1422 obj = OctetString(default=OctetString(b""), optional=optional)
1423 self.assertTrue(obj.optional)
1426 def test_ready(self, value):
1428 self.assertFalse(obj.ready)
1431 with self.assertRaises(ObjNotReady) as err:
1434 obj = OctetString(value)
1435 self.assertTrue(obj.ready)
1439 @given(binary(), binary(), binary(), binary())
1440 def test_comparison(self, value1, value2, tag1, tag2):
1441 for klass in (OctetString, OctetStringInherited):
1442 obj1 = klass(value1)
1443 obj2 = klass(value2)
1444 self.assertEqual(obj1 == obj2, value1 == value2)
1445 self.assertEqual(obj1 != obj2, value1 != value2)
1446 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1447 obj1 = klass(value1, impl=tag1)
1448 obj2 = klass(value1, impl=tag2)
1449 self.assertEqual(obj1 == obj2, tag1 == tag2)
1450 self.assertEqual(obj1 != obj2, tag1 != tag2)
1452 @given(lists(binary()))
1453 def test_sorted_works(self, values):
1454 self.assertSequenceEqual(
1455 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1459 @given(data_strategy())
1460 def test_bounds_satisfied(self, d):
1461 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1462 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1463 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1464 OctetString(value=value, bounds=(bound_min, bound_max))
1466 @given(data_strategy())
1467 def test_bounds_unsatisfied(self, d):
1468 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1469 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1470 value = d.draw(binary(max_size=bound_min - 1))
1471 with self.assertRaises(BoundsError) as err:
1472 OctetString(value=value, bounds=(bound_min, bound_max))
1474 value = d.draw(binary(min_size=bound_max + 1))
1475 with self.assertRaises(BoundsError) as err:
1476 OctetString(value=value, bounds=(bound_min, bound_max))
1479 @given(data_strategy())
1480 def test_call(self, d):
1481 for klass in (OctetString, OctetStringInherited):
1490 ) = d.draw(octet_string_values_strategy())
1491 obj_initial = klass(
1497 optional_initial or False,
1508 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1509 if (default is None) and (obj_initial.default is not None):
1512 (bounds is None) and
1513 (value is not None) and
1514 (bounds_initial is not None) and
1515 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1519 (bounds is None) and
1520 (default is not None) and
1521 (bounds_initial is not None) and
1522 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1525 obj = obj_initial(value, bounds, impl, expl, default, optional)
1527 value_expected = default if value is None else value
1529 default_initial if value_expected is None
1532 self.assertEqual(obj, value_expected)
1533 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1534 self.assertEqual(obj.expl_tag, expl or expl_initial)
1537 default_initial if default is None else default,
1539 if obj.default is None:
1540 optional = optional_initial if optional is None else optional
1541 optional = False if optional is None else optional
1544 self.assertEqual(obj.optional, optional)
1546 (obj._bound_min, obj._bound_max),
1547 bounds or bounds_initial or (0, float("+inf")),
1550 @given(octet_string_values_strategy())
1551 def test_copy(self, values):
1552 for klass in (OctetString, OctetStringInherited):
1553 obj = klass(*values)
1554 obj_copied = obj.copy()
1555 self.assert_copied_basic_fields(obj, obj_copied)
1556 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1557 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1558 self.assertEqual(obj._value, obj_copied._value)
1562 integers(min_value=1).map(tag_encode),
1564 def test_stripped(self, value, tag_impl):
1565 obj = OctetString(value, impl=tag_impl)
1566 with self.assertRaises(NotEnoughData):
1567 obj.decode(obj.encode()[:-1])
1571 integers(min_value=1).map(tag_ctxc),
1573 def test_stripped_expl(self, value, tag_expl):
1574 obj = OctetString(value, expl=tag_expl)
1575 with self.assertRaises(NotEnoughData):
1576 obj.decode(obj.encode()[:-1])
1579 integers(min_value=31),
1580 integers(min_value=0),
1583 def test_bad_tag(self, tag, offset, decode_path):
1584 decode_path = tuple(str(i) for i in decode_path)
1585 with self.assertRaises(DecodeError) as err:
1586 OctetString().decode(
1587 tag_encode(tag)[:-1],
1589 decode_path=decode_path,
1592 self.assertEqual(err.exception.offset, offset)
1593 self.assertEqual(err.exception.decode_path, decode_path)
1596 integers(min_value=128),
1597 integers(min_value=0),
1600 def test_bad_len(self, l, offset, decode_path):
1601 decode_path = tuple(str(i) for i in decode_path)
1602 with self.assertRaises(DecodeError) as err:
1603 OctetString().decode(
1604 OctetString.tag_default + len_encode(l)[:-1],
1606 decode_path=decode_path,
1609 self.assertEqual(err.exception.offset, offset)
1610 self.assertEqual(err.exception.decode_path, decode_path)
1613 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1614 integers(min_value=0),
1617 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1618 decode_path = tuple(str(i) for i in decode_path)
1619 value, bound_min = list(sorted(ints))
1621 class String(OctetString):
1622 bounds = (bound_min, bound_min)
1623 with self.assertRaises(DecodeError) as err:
1625 OctetString(b"\x00" * value).encode(),
1627 decode_path=decode_path,
1630 self.assertEqual(err.exception.offset, offset)
1631 self.assertEqual(err.exception.decode_path, decode_path)
1633 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1635 octet_string_values_strategy(),
1637 integers(min_value=1).map(tag_ctxc),
1638 integers(min_value=0),
1640 def test_symmetric(self, values, value, tag_expl, offset):
1641 for klass in (OctetString, OctetStringInherited):
1642 _, _, _, _, default, optional, _decoded = values
1651 self.assertFalse(obj.expled)
1652 obj_encoded = obj.encode()
1653 obj_expled = obj(value, expl=tag_expl)
1654 self.assertTrue(obj_expled.expled)
1657 obj_expled_encoded = obj_expled.encode()
1658 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1661 self.assertEqual(tail, b"")
1662 self.assertEqual(obj_decoded, obj_expled)
1663 self.assertNotEqual(obj_decoded, obj)
1664 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1665 self.assertEqual(bytes(obj_decoded), bytes(obj))
1666 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1667 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1668 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1670 obj_decoded.expl_llen,
1671 len(len_encode(len(obj_encoded))),
1673 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1674 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1677 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1679 self.assertEqual(obj_decoded.expl_offset, offset)
1683 def null_values_strategy(draw, do_expl=False):
1687 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1689 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1690 optional = draw(one_of(none(), booleans()))
1692 draw(integers(min_value=0)),
1693 draw(integers(min_value=0)),
1694 draw(integers(min_value=0)),
1696 return (impl, expl, optional, _decoded)
1699 class NullInherited(Null):
1703 class TestNull(CommonMixin, TestCase):
1706 def test_ready(self):
1708 self.assertTrue(obj.ready)
1712 @given(binary(), binary())
1713 def test_comparison(self, tag1, tag2):
1714 for klass in (Null, NullInherited):
1715 obj1 = klass(impl=tag1)
1716 obj2 = klass(impl=tag2)
1717 self.assertEqual(obj1 == obj2, tag1 == tag2)
1718 self.assertEqual(obj1 != obj2, tag1 != tag2)
1719 self.assertNotEqual(obj1, tag2)
1721 @given(data_strategy())
1722 def test_call(self, d):
1723 for klass in (Null, NullInherited):
1729 ) = d.draw(null_values_strategy())
1730 obj_initial = klass(
1733 optional=optional_initial or False,
1734 _decoded=_decoded_initial,
1741 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
1742 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1743 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1744 self.assertEqual(obj.expl_tag, expl or expl_initial)
1745 optional = optional_initial if optional is None else optional
1746 optional = False if optional is None else optional
1747 self.assertEqual(obj.optional, optional)
1749 @given(null_values_strategy())
1750 def test_copy(self, values):
1751 for klass in (Null, NullInherited):
1752 impl, expl, optional, _decoded = values
1756 optional=optional or False,
1759 obj_copied = obj.copy()
1760 self.assert_copied_basic_fields(obj, obj_copied)
1762 @given(integers(min_value=1).map(tag_encode))
1763 def test_stripped(self, tag_impl):
1764 obj = Null(impl=tag_impl)
1765 with self.assertRaises(NotEnoughData):
1766 obj.decode(obj.encode()[:-1])
1768 @given(integers(min_value=1).map(tag_ctxc))
1769 def test_stripped_expl(self, tag_expl):
1770 obj = Null(expl=tag_expl)
1771 with self.assertRaises(NotEnoughData):
1772 obj.decode(obj.encode()[:-1])
1775 integers(min_value=31),
1776 integers(min_value=0),
1779 def test_bad_tag(self, tag, offset, decode_path):
1780 decode_path = tuple(str(i) for i in decode_path)
1781 with self.assertRaises(DecodeError) as err:
1783 tag_encode(tag)[:-1],
1785 decode_path=decode_path,
1788 self.assertEqual(err.exception.offset, offset)
1789 self.assertEqual(err.exception.decode_path, decode_path)
1792 integers(min_value=128),
1793 integers(min_value=0),
1796 def test_bad_len(self, l, offset, decode_path):
1797 decode_path = tuple(str(i) for i in decode_path)
1798 with self.assertRaises(DecodeError) as err:
1800 Null.tag_default + len_encode(l)[:-1],
1802 decode_path=decode_path,
1805 self.assertEqual(err.exception.offset, offset)
1806 self.assertEqual(err.exception.decode_path, decode_path)
1808 @given(binary(min_size=1))
1809 def test_tag_mismatch(self, impl):
1810 assume(impl != Null.tag_default)
1811 with self.assertRaises(TagMismatch):
1812 Null(impl=impl).decode(Null().encode())
1815 null_values_strategy(),
1816 integers(min_value=1).map(tag_ctxc),
1817 integers(min_value=0),
1819 def test_symmetric(self, values, tag_expl, offset):
1820 for klass in (Null, NullInherited):
1821 _, _, optional, _decoded = values
1822 obj = klass(optional=optional, _decoded=_decoded)
1825 self.assertFalse(obj.expled)
1826 obj_encoded = obj.encode()
1827 obj_expled = obj(expl=tag_expl)
1828 self.assertTrue(obj_expled.expled)
1831 obj_expled_encoded = obj_expled.encode()
1832 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1835 self.assertEqual(tail, b"")
1836 self.assertEqual(obj_decoded, obj_expled)
1837 self.assertNotEqual(obj_decoded, obj)
1838 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1839 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1840 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1842 obj_decoded.expl_llen,
1843 len(len_encode(len(obj_encoded))),
1845 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1846 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1849 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1851 self.assertEqual(obj_decoded.expl_offset, offset)
1853 @given(integers(min_value=1))
1854 def test_invalid_len(self, l):
1855 with self.assertRaises(InvalidLength):
1856 Null().decode(b"".join((
1863 def oid_strategy(draw):
1864 first_arc = draw(integers(min_value=0, max_value=2))
1866 if first_arc in (0, 1):
1867 second_arc = draw(integers(min_value=0, max_value=39))
1869 second_arc = draw(integers(min_value=0))
1870 other_arcs = draw(lists(integers(min_value=0)))
1871 return tuple([first_arc, second_arc] + other_arcs)
1875 def oid_values_strategy(draw, do_expl=False):
1876 value = draw(one_of(none(), oid_strategy()))
1880 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1882 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1883 default = draw(one_of(none(), oid_strategy()))
1884 optional = draw(one_of(none(), booleans()))
1886 draw(integers(min_value=0)),
1887 draw(integers(min_value=0)),
1888 draw(integers(min_value=0)),
1890 return (value, impl, expl, default, optional, _decoded)
1893 class ObjectIdentifierInherited(ObjectIdentifier):
1897 class TestObjectIdentifier(CommonMixin, TestCase):
1898 base_klass = ObjectIdentifier
1900 def test_invalid_value_type(self):
1901 with self.assertRaises(InvalidValueType) as err:
1902 ObjectIdentifier(123)
1906 def test_optional(self, optional):
1907 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
1908 self.assertTrue(obj.optional)
1910 @given(oid_strategy())
1911 def test_ready(self, value):
1912 obj = ObjectIdentifier()
1913 self.assertFalse(obj.ready)
1916 with self.assertRaises(ObjNotReady) as err:
1919 obj = ObjectIdentifier(value)
1920 self.assertTrue(obj.ready)
1925 @given(oid_strategy(), oid_strategy(), binary(), binary())
1926 def test_comparison(self, value1, value2, tag1, tag2):
1927 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1928 obj1 = klass(value1)
1929 obj2 = klass(value2)
1930 self.assertEqual(obj1 == obj2, value1 == value2)
1931 self.assertEqual(obj1 != obj2, value1 != value2)
1932 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
1933 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
1934 obj1 = klass(value1, impl=tag1)
1935 obj2 = klass(value1, impl=tag2)
1936 self.assertEqual(obj1 == obj2, tag1 == tag2)
1937 self.assertEqual(obj1 != obj2, tag1 != tag2)
1939 @given(lists(oid_strategy()))
1940 def test_sorted_works(self, values):
1941 self.assertSequenceEqual(
1942 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
1946 @given(data_strategy())
1947 def test_call(self, d):
1948 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1956 ) = d.draw(oid_values_strategy())
1957 obj_initial = klass(
1958 value=value_initial,
1961 default=default_initial,
1962 optional=optional_initial or False,
1963 _decoded=_decoded_initial,
1972 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
1981 value_expected = default if value is None else value
1983 default_initial if value_expected is None
1986 self.assertEqual(obj, value_expected)
1987 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1988 self.assertEqual(obj.expl_tag, expl or expl_initial)
1991 default_initial if default is None else default,
1993 if obj.default is None:
1994 optional = optional_initial if optional is None else optional
1995 optional = False if optional is None else optional
1998 self.assertEqual(obj.optional, optional)
2000 @given(oid_values_strategy())
2001 def test_copy(self, values):
2002 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2019 obj_copied = obj.copy()
2020 self.assert_copied_basic_fields(obj, obj_copied)
2021 self.assertEqual(obj._value, obj_copied._value)
2023 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2026 integers(min_value=1).map(tag_encode),
2028 def test_stripped(self, value, tag_impl):
2029 obj = ObjectIdentifier(value, impl=tag_impl)
2030 with self.assertRaises(NotEnoughData):
2031 obj.decode(obj.encode()[:-1])
2035 integers(min_value=1).map(tag_ctxc),
2037 def test_stripped_expl(self, value, tag_expl):
2038 obj = ObjectIdentifier(value, expl=tag_expl)
2039 with self.assertRaises(NotEnoughData):
2040 obj.decode(obj.encode()[:-1])
2043 integers(min_value=31),
2044 integers(min_value=0),
2047 def test_bad_tag(self, tag, offset, decode_path):
2048 decode_path = tuple(str(i) for i in decode_path)
2049 with self.assertRaises(DecodeError) as err:
2050 ObjectIdentifier().decode(
2051 tag_encode(tag)[:-1],
2053 decode_path=decode_path,
2056 self.assertEqual(err.exception.offset, offset)
2057 self.assertEqual(err.exception.decode_path, decode_path)
2060 integers(min_value=128),
2061 integers(min_value=0),
2064 def test_bad_len(self, l, offset, decode_path):
2065 decode_path = tuple(str(i) for i in decode_path)
2066 with self.assertRaises(DecodeError) as err:
2067 ObjectIdentifier().decode(
2068 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2070 decode_path=decode_path,
2073 self.assertEqual(err.exception.offset, offset)
2074 self.assertEqual(err.exception.decode_path, decode_path)
2076 def test_zero_oid(self):
2077 with self.assertRaises(NotEnoughData):
2078 ObjectIdentifier().decode(
2079 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2082 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2083 @given(oid_strategy())
2084 def test_unfinished_oid(self, value):
2085 assume(list(value)[-1] > 255)
2086 obj_encoded = ObjectIdentifier(value).encode()
2087 obj, _ = ObjectIdentifier().decode(obj_encoded)
2088 data = obj_encoded[obj.tlen + obj.llen:-1]
2090 ObjectIdentifier.tag_default,
2091 len_encode(len(data)),
2094 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2097 @given(integers(min_value=0))
2098 def test_invalid_short(self, value):
2099 with self.assertRaises(InvalidOID):
2100 ObjectIdentifier((value,))
2101 with self.assertRaises(InvalidOID):
2102 ObjectIdentifier("%d" % value)
2104 @given(integers(min_value=3), integers(min_value=0))
2105 def test_invalid_first_arc(self, first_arc, second_arc):
2106 with self.assertRaises(InvalidOID):
2107 ObjectIdentifier((first_arc, second_arc))
2108 with self.assertRaises(InvalidOID):
2109 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2111 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2112 def test_invalid_second_arc(self, first_arc, second_arc):
2113 with self.assertRaises(InvalidOID):
2114 ObjectIdentifier((first_arc, second_arc))
2115 with self.assertRaises(InvalidOID):
2116 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2118 @given(text(alphabet=ascii_letters + ".", min_size=1))
2119 def test_junk(self, oid):
2120 with self.assertRaises(InvalidOID):
2121 ObjectIdentifier(oid)
2123 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2124 @given(oid_strategy())
2125 def test_validness(self, oid):
2126 obj = ObjectIdentifier(oid)
2127 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2132 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2134 oid_values_strategy(),
2136 integers(min_value=1).map(tag_ctxc),
2137 integers(min_value=0),
2139 def test_symmetric(self, values, value, tag_expl, offset):
2140 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2141 _, _, _, default, optional, _decoded = values
2150 self.assertFalse(obj.expled)
2151 obj_encoded = obj.encode()
2152 obj_expled = obj(value, expl=tag_expl)
2153 self.assertTrue(obj_expled.expled)
2156 obj_expled_encoded = obj_expled.encode()
2157 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2160 self.assertEqual(tail, b"")
2161 self.assertEqual(obj_decoded, obj_expled)
2162 self.assertNotEqual(obj_decoded, obj)
2163 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2164 self.assertEqual(tuple(obj_decoded), tuple(obj))
2165 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2166 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2167 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2169 obj_decoded.expl_llen,
2170 len(len_encode(len(obj_encoded))),
2172 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2173 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2176 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2178 self.assertEqual(obj_decoded.expl_offset, offset)
2181 oid_strategy().map(ObjectIdentifier),
2182 oid_strategy().map(ObjectIdentifier),
2184 def test_add(self, oid1, oid2):
2185 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2186 for oid_to_add in (oid2, tuple(oid2)):
2187 self.assertEqual(oid1 + oid_to_add, oid_expect)
2188 with self.assertRaises(InvalidValueType):
2191 def test_go_vectors_valid(self):
2192 for data, expect in (
2194 (b"\x55\x02", (2, 5, 2)),
2195 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2196 (b"\x81\x34\x03", (2, 100, 3)),
2199 ObjectIdentifier().decode(b"".join((
2200 ObjectIdentifier.tag_default,
2201 len_encode(len(data)),
2207 def test_go_vectors_invalid(self):
2208 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2209 with self.assertRaises(DecodeError):
2210 ObjectIdentifier().decode(b"".join((
2211 Integer.tag_default,
2212 len_encode(len(data)),
2218 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2220 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2221 values = list(draw(sets(
2223 min_size=len(schema),
2224 max_size=len(schema),
2226 schema = list(zip(schema, values))
2227 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2231 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2233 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2234 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2235 optional = draw(one_of(none(), booleans()))
2237 draw(integers(min_value=0)),
2238 draw(integers(min_value=0)),
2239 draw(integers(min_value=0)),
2241 return (schema, value, impl, expl, default, optional, _decoded)
2244 class TestEnumerated(CommonMixin, TestCase):
2245 class EWhatever(Enumerated):
2246 schema = (("whatever", 0),)
2248 base_klass = EWhatever
2250 def test_schema_required(self):
2251 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2254 def test_invalid_value_type(self):
2255 with self.assertRaises(InvalidValueType) as err:
2256 self.base_klass((1, 2))
2259 @given(sets(text_letters(), min_size=2))
2260 def test_unknown_name(self, schema_input):
2261 missing = schema_input.pop()
2263 class E(Enumerated):
2264 schema = [(n, 123) for n in schema_input]
2265 with self.assertRaises(ObjUnknown) as err:
2270 sets(text_letters(), min_size=2),
2271 sets(integers(), min_size=2),
2273 def test_unknown_value(self, schema_input, values_input):
2275 missing_value = values_input.pop()
2276 _input = list(zip(schema_input, values_input))
2278 class E(Enumerated):
2280 with self.assertRaises(DecodeError) as err:
2285 def test_optional(self, optional):
2286 obj = self.base_klass(default="whatever", optional=optional)
2287 self.assertTrue(obj.optional)
2289 def test_ready(self):
2290 obj = self.base_klass()
2291 self.assertFalse(obj.ready)
2294 with self.assertRaises(ObjNotReady) as err:
2297 obj = self.base_klass("whatever")
2298 self.assertTrue(obj.ready)
2302 @given(integers(), integers(), binary(), binary())
2303 def test_comparison(self, value1, value2, tag1, tag2):
2304 class E(Enumerated):
2306 ("whatever0", value1),
2307 ("whatever1", value2),
2310 class EInherited(E):
2312 for klass in (E, EInherited):
2313 obj1 = klass(value1)
2314 obj2 = klass(value2)
2315 self.assertEqual(obj1 == obj2, value1 == value2)
2316 self.assertEqual(obj1 != obj2, value1 != value2)
2317 self.assertEqual(obj1 == int(obj2), value1 == value2)
2318 obj1 = klass(value1, impl=tag1)
2319 obj2 = klass(value1, impl=tag2)
2320 self.assertEqual(obj1 == obj2, tag1 == tag2)
2321 self.assertEqual(obj1 != obj2, tag1 != tag2)
2323 @given(data_strategy())
2324 def test_call(self, d):
2333 ) = d.draw(enumerated_values_strategy())
2335 class E(Enumerated):
2336 schema = schema_initial
2338 value=value_initial,
2341 default=default_initial,
2342 optional=optional_initial or False,
2343 _decoded=_decoded_initial,
2353 ) = d.draw(enumerated_values_strategy(
2354 schema=schema_initial,
2355 do_expl=impl_initial is None,
2365 value_expected = default if value is None else value
2367 default_initial if value_expected is None
2372 dict(schema_initial).get(value_expected, value_expected),
2374 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2375 self.assertEqual(obj.expl_tag, expl or expl_initial)
2378 default_initial if default is None else default,
2380 if obj.default is None:
2381 optional = optional_initial if optional is None else optional
2382 optional = False if optional is None else optional
2385 self.assertEqual(obj.optional, optional)
2386 self.assertEqual(obj.specs, dict(schema_initial))
2388 @given(enumerated_values_strategy())
2389 def test_copy(self, values):
2390 schema_input, value, impl, expl, default, optional, _decoded = values
2392 class E(Enumerated):
2393 schema = schema_input
2402 obj_copied = obj.copy()
2403 self.assert_copied_basic_fields(obj, obj_copied)
2404 self.assertEqual(obj.specs, obj_copied.specs)
2406 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2407 @given(data_strategy())
2408 def test_symmetric(self, d):
2409 schema_input, _, _, _, default, optional, _decoded = d.draw(
2410 enumerated_values_strategy(),
2412 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2413 offset = d.draw(integers(min_value=0))
2414 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2416 class E(Enumerated):
2417 schema = schema_input
2426 self.assertFalse(obj.expled)
2427 obj_encoded = obj.encode()
2428 obj_expled = obj(value, expl=tag_expl)
2429 self.assertTrue(obj_expled.expled)
2432 obj_expled_encoded = obj_expled.encode()
2433 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2436 self.assertEqual(tail, b"")
2437 self.assertEqual(obj_decoded, obj_expled)
2438 self.assertNotEqual(obj_decoded, obj)
2439 self.assertEqual(int(obj_decoded), int(obj_expled))
2440 self.assertEqual(int(obj_decoded), int(obj))
2441 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2442 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2443 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2445 obj_decoded.expl_llen,
2446 len(len_encode(len(obj_encoded))),
2448 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2449 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2452 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2454 self.assertEqual(obj_decoded.expl_offset, offset)
2458 def string_values_strategy(draw, alphabet, do_expl=False):
2459 bound_min, bound_max = sorted(draw(sets(
2460 integers(min_value=0, max_value=1 << 7),
2464 value = draw(one_of(
2466 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2468 default = draw(one_of(
2470 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2473 if draw(booleans()):
2474 bounds = (bound_min, bound_max)
2478 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2480 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2481 optional = draw(one_of(none(), booleans()))
2483 draw(integers(min_value=0)),
2484 draw(integers(min_value=0)),
2485 draw(integers(min_value=0)),
2487 return (value, bounds, impl, expl, default, optional, _decoded)
2490 class StringMixin(object):
2491 def test_invalid_value_type(self):
2492 with self.assertRaises(InvalidValueType) as err:
2493 self.base_klass((1, 2))
2496 def text_alphabet(self):
2497 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2498 return printable + whitespace
2502 def test_optional(self, optional):
2503 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2504 self.assertTrue(obj.optional)
2506 @given(data_strategy())
2507 def test_ready(self, d):
2508 obj = self.base_klass()
2509 self.assertFalse(obj.ready)
2513 with self.assertRaises(ObjNotReady) as err:
2516 value = d.draw(text(alphabet=self.text_alphabet()))
2517 obj = self.base_klass(value)
2518 self.assertTrue(obj.ready)
2523 @given(data_strategy())
2524 def test_comparison(self, d):
2525 value1 = d.draw(text(alphabet=self.text_alphabet()))
2526 value2 = d.draw(text(alphabet=self.text_alphabet()))
2527 tag1 = d.draw(binary())
2528 tag2 = d.draw(binary())
2529 obj1 = self.base_klass(value1)
2530 obj2 = self.base_klass(value2)
2531 self.assertEqual(obj1 == obj2, value1 == value2)
2532 self.assertEqual(obj1 != obj2, value1 != value2)
2533 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2534 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2535 obj1 = self.base_klass(value1, impl=tag1)
2536 obj2 = self.base_klass(value1, impl=tag2)
2537 self.assertEqual(obj1 == obj2, tag1 == tag2)
2538 self.assertEqual(obj1 != obj2, tag1 != tag2)
2540 @given(data_strategy())
2541 def test_bounds_satisfied(self, d):
2542 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2543 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2544 value = d.draw(text(
2545 alphabet=self.text_alphabet(),
2549 self.base_klass(value=value, bounds=(bound_min, bound_max))
2551 @given(data_strategy())
2552 def test_bounds_unsatisfied(self, d):
2553 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2554 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2555 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2556 with self.assertRaises(BoundsError) as err:
2557 self.base_klass(value=value, bounds=(bound_min, bound_max))
2559 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2560 with self.assertRaises(BoundsError) as err:
2561 self.base_klass(value=value, bounds=(bound_min, bound_max))
2564 @given(data_strategy())
2565 def test_call(self, d):
2574 ) = d.draw(string_values_strategy(self.text_alphabet()))
2575 obj_initial = self.base_klass(
2581 optional_initial or False,
2592 ) = d.draw(string_values_strategy(
2593 self.text_alphabet(),
2594 do_expl=impl_initial is None,
2596 if (default is None) and (obj_initial.default is not None):
2599 (bounds is None) and
2600 (value is not None) and
2601 (bounds_initial is not None) and
2602 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2606 (bounds is None) and
2607 (default is not None) and
2608 (bounds_initial is not None) and
2609 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2612 obj = obj_initial(value, bounds, impl, expl, default, optional)
2614 value_expected = default if value is None else value
2616 default_initial if value_expected is None
2619 self.assertEqual(obj, value_expected)
2620 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2621 self.assertEqual(obj.expl_tag, expl or expl_initial)
2624 default_initial if default is None else default,
2626 if obj.default is None:
2627 optional = optional_initial if optional is None else optional
2628 optional = False if optional is None else optional
2631 self.assertEqual(obj.optional, optional)
2633 (obj._bound_min, obj._bound_max),
2634 bounds or bounds_initial or (0, float("+inf")),
2637 @given(data_strategy())
2638 def test_copy(self, d):
2639 values = d.draw(string_values_strategy(self.text_alphabet()))
2640 obj = self.base_klass(*values)
2641 obj_copied = obj.copy()
2642 self.assert_copied_basic_fields(obj, obj_copied)
2643 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2644 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2645 self.assertEqual(obj._value, obj_copied._value)
2647 @given(data_strategy())
2648 def test_stripped(self, d):
2649 value = d.draw(text(alphabet=self.text_alphabet()))
2650 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2651 obj = self.base_klass(value, impl=tag_impl)
2652 with self.assertRaises(NotEnoughData):
2653 obj.decode(obj.encode()[:-1])
2655 @given(data_strategy())
2656 def test_stripped_expl(self, d):
2657 value = d.draw(text(alphabet=self.text_alphabet()))
2658 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2659 obj = self.base_klass(value, expl=tag_expl)
2660 with self.assertRaises(NotEnoughData):
2661 obj.decode(obj.encode()[:-1])
2664 integers(min_value=31),
2665 integers(min_value=0),
2668 def test_bad_tag(self, tag, offset, decode_path):
2669 decode_path = tuple(str(i) for i in decode_path)
2670 with self.assertRaises(DecodeError) as err:
2671 self.base_klass().decode(
2672 tag_encode(tag)[:-1],
2674 decode_path=decode_path,
2677 self.assertEqual(err.exception.offset, offset)
2678 self.assertEqual(err.exception.decode_path, decode_path)
2681 integers(min_value=128),
2682 integers(min_value=0),
2685 def test_bad_len(self, l, offset, decode_path):
2686 decode_path = tuple(str(i) for i in decode_path)
2687 with self.assertRaises(DecodeError) as err:
2688 self.base_klass().decode(
2689 self.base_klass.tag_default + len_encode(l)[:-1],
2691 decode_path=decode_path,
2694 self.assertEqual(err.exception.offset, offset)
2695 self.assertEqual(err.exception.decode_path, decode_path)
2698 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2699 integers(min_value=0),
2702 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2703 decode_path = tuple(str(i) for i in decode_path)
2704 value, bound_min = list(sorted(ints))
2706 class String(self.base_klass):
2707 # Multiply this value by four, to satisfy UTF-32 bounds
2708 # (4 bytes per character) validation
2709 bounds = (bound_min * 4, bound_min * 4)
2710 with self.assertRaises(DecodeError) as err:
2712 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2714 decode_path=decode_path,
2717 self.assertEqual(err.exception.offset, offset)
2718 self.assertEqual(err.exception.decode_path, decode_path)
2720 @given(data_strategy())
2721 def test_symmetric(self, d):
2722 values = d.draw(string_values_strategy(self.text_alphabet()))
2723 value = d.draw(text(alphabet=self.text_alphabet()))
2724 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2725 offset = d.draw(integers(min_value=0))
2726 _, _, _, _, default, optional, _decoded = values
2727 obj = self.base_klass(
2735 self.assertFalse(obj.expled)
2736 obj_encoded = obj.encode()
2737 obj_expled = obj(value, expl=tag_expl)
2738 self.assertTrue(obj_expled.expled)
2741 obj_expled_encoded = obj_expled.encode()
2742 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2745 self.assertEqual(tail, b"")
2746 self.assertEqual(obj_decoded, obj_expled)
2747 self.assertNotEqual(obj_decoded, obj)
2748 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2749 self.assertEqual(bytes(obj_decoded), bytes(obj))
2750 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2751 self.assertEqual(text_type(obj_decoded), text_type(obj))
2752 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2753 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2754 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2756 obj_decoded.expl_llen,
2757 len(len_encode(len(obj_encoded))),
2759 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2760 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2763 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2765 self.assertEqual(obj_decoded.expl_offset, offset)
2768 class TestUTF8String(StringMixin, CommonMixin, TestCase):
2769 base_klass = UTF8String
2772 class TestNumericString(StringMixin, CommonMixin, TestCase):
2773 base_klass = NumericString
2776 class TestPrintableString(StringMixin, CommonMixin, TestCase):
2777 base_klass = PrintableString
2780 class TestTeletexString(StringMixin, CommonMixin, TestCase):
2781 base_klass = TeletexString
2784 class TestVideotexString(StringMixin, CommonMixin, TestCase):
2785 base_klass = VideotexString
2788 class TestIA5String(StringMixin, CommonMixin, TestCase):
2789 base_klass = IA5String
2792 class TestGraphicString(StringMixin, CommonMixin, TestCase):
2793 base_klass = GraphicString
2796 class TestVisibleString(StringMixin, CommonMixin, TestCase):
2797 base_klass = VisibleString
2800 class TestGeneralString(StringMixin, CommonMixin, TestCase):
2801 base_klass = GeneralString
2804 class TestUniversalString(StringMixin, CommonMixin, TestCase):
2805 base_klass = UniversalString
2808 class TestBMPString(StringMixin, CommonMixin, TestCase):
2809 base_klass = BMPString
2813 def generalized_time_values_strategy(
2821 if draw(booleans()):
2822 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2824 value = value.replace(microsecond=0)
2826 if draw(booleans()):
2827 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2829 default = default.replace(microsecond=0)
2833 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2835 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2836 optional = draw(one_of(none(), booleans()))
2838 draw(integers(min_value=0)),
2839 draw(integers(min_value=0)),
2840 draw(integers(min_value=0)),
2842 return (value, impl, expl, default, optional, _decoded)
2845 class TimeMixin(object):
2846 def test_invalid_value_type(self):
2847 with self.assertRaises(InvalidValueType) as err:
2848 self.base_klass(datetime.now().timetuple())
2851 @given(data_strategy())
2852 def test_optional(self, d):
2853 default = d.draw(datetimes(
2854 min_value=self.min_datetime,
2855 max_value=self.max_datetime,
2857 optional = d.draw(booleans())
2858 obj = self.base_klass(default=default, optional=optional)
2859 self.assertTrue(obj.optional)
2861 @given(data_strategy())
2862 def test_ready(self, d):
2863 obj = self.base_klass()
2864 self.assertFalse(obj.ready)
2867 with self.assertRaises(ObjNotReady) as err:
2870 value = d.draw(datetimes(min_value=self.min_datetime))
2871 obj = self.base_klass(value)
2872 self.assertTrue(obj.ready)
2876 @given(data_strategy())
2877 def test_comparison(self, d):
2878 value1 = d.draw(datetimes(
2879 min_value=self.min_datetime,
2880 max_value=self.max_datetime,
2882 value2 = d.draw(datetimes(
2883 min_value=self.min_datetime,
2884 max_value=self.max_datetime,
2886 tag1 = d.draw(binary())
2887 tag2 = d.draw(binary())
2889 value1 = value1.replace(microsecond=0)
2890 value2 = value2.replace(microsecond=0)
2891 obj1 = self.base_klass(value1)
2892 obj2 = self.base_klass(value2)
2893 self.assertEqual(obj1 == obj2, value1 == value2)
2894 self.assertEqual(obj1 != obj2, value1 != value2)
2895 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
2896 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2897 obj1 = self.base_klass(value1, impl=tag1)
2898 obj2 = self.base_klass(value1, impl=tag2)
2899 self.assertEqual(obj1 == obj2, tag1 == tag2)
2900 self.assertEqual(obj1 != obj2, tag1 != tag2)
2902 @given(data_strategy())
2903 def test_call(self, d):
2911 ) = d.draw(generalized_time_values_strategy(
2912 min_datetime=self.min_datetime,
2913 max_datetime=self.max_datetime,
2914 omit_ms=self.omit_ms,
2916 obj_initial = self.base_klass(
2917 value=value_initial,
2920 default=default_initial,
2921 optional=optional_initial or False,
2922 _decoded=_decoded_initial,
2931 ) = d.draw(generalized_time_values_strategy(
2932 min_datetime=self.min_datetime,
2933 max_datetime=self.max_datetime,
2934 omit_ms=self.omit_ms,
2935 do_expl=impl_initial is None,
2945 value_expected = default if value is None else value
2947 default_initial if value_expected is None
2950 self.assertEqual(obj, value_expected)
2951 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2952 self.assertEqual(obj.expl_tag, expl or expl_initial)
2955 default_initial if default is None else default,
2957 if obj.default is None:
2958 optional = optional_initial if optional is None else optional
2959 optional = False if optional is None else optional
2962 self.assertEqual(obj.optional, optional)
2964 @given(data_strategy())
2965 def test_copy(self, d):
2966 values = d.draw(generalized_time_values_strategy(
2967 min_datetime=self.min_datetime,
2968 max_datetime=self.max_datetime,
2970 obj = self.base_klass(*values)
2971 obj_copied = obj.copy()
2972 self.assert_copied_basic_fields(obj, obj_copied)
2973 self.assertEqual(obj._value, obj_copied._value)
2975 @given(data_strategy())
2976 def test_stripped(self, d):
2977 value = d.draw(datetimes(
2978 min_value=self.min_datetime,
2979 max_value=self.max_datetime,
2981 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2982 obj = self.base_klass(value, impl=tag_impl)
2983 with self.assertRaises(NotEnoughData):
2984 obj.decode(obj.encode()[:-1])
2986 @given(data_strategy())
2987 def test_stripped_expl(self, d):
2988 value = d.draw(datetimes(
2989 min_value=self.min_datetime,
2990 max_value=self.max_datetime,
2992 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2993 obj = self.base_klass(value, expl=tag_expl)
2994 with self.assertRaises(NotEnoughData):
2995 obj.decode(obj.encode()[:-1])
2997 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2998 @given(data_strategy())
2999 def test_symmetric(self, d):
3000 values = d.draw(generalized_time_values_strategy(
3001 min_datetime=self.min_datetime,
3002 max_datetime=self.max_datetime,
3004 value = d.draw(datetimes(
3005 min_value=self.min_datetime,
3006 max_value=self.max_datetime,
3008 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3009 offset = d.draw(integers(min_value=0))
3010 _, _, _, default, optional, _decoded = values
3011 obj = self.base_klass(
3019 self.assertFalse(obj.expled)
3020 obj_encoded = obj.encode()
3021 obj_expled = obj(value, expl=tag_expl)
3022 self.assertTrue(obj_expled.expled)
3025 obj_expled_encoded = obj_expled.encode()
3026 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
3029 self.assertEqual(tail, b"")
3030 self.assertEqual(obj_decoded, obj_expled)
3031 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3032 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3033 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3034 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3035 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3037 obj_decoded.expl_llen,
3038 len(len_encode(len(obj_encoded))),
3040 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3041 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3044 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3046 self.assertEqual(obj_decoded.expl_offset, offset)
3049 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3050 base_klass = GeneralizedTime
3052 min_datetime = datetime(1900, 1, 1)
3053 max_datetime = datetime(9999, 12, 31)
3055 def test_go_vectors_invalid(self):
3067 b"-20100102030410Z",
3068 b"2010-0102030410Z",
3069 b"2010-0002030410Z",
3070 b"201001-02030410Z",
3071 b"20100102-030410Z",
3072 b"2010010203-0410Z",
3073 b"201001020304-10Z",
3074 # These ones are INVALID in *DER*, but accepted
3075 # by Go's encoding/asn1
3076 b"20100102030405+0607",
3077 b"20100102030405-0607",
3079 with self.assertRaises(DecodeError) as err:
3080 GeneralizedTime(data)
3083 def test_go_vectors_valid(self):
3085 GeneralizedTime(b"20100102030405Z").todatetime(),
3086 datetime(2010, 1, 2, 3, 4, 5, 0),
3090 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3091 base_klass = UTCTime
3093 min_datetime = datetime(2000, 1, 1)
3094 max_datetime = datetime(2049, 12, 31)
3096 def test_go_vectors_invalid(self):
3122 # These ones are INVALID in *DER*, but accepted
3123 # by Go's encoding/asn1
3124 b"910506164540-0700",
3125 b"910506164540+0730",
3129 with self.assertRaises(DecodeError) as err:
3133 def test_go_vectors_valid(self):
3135 UTCTime(b"910506234540Z").todatetime(),
3136 datetime(1991, 5, 6, 23, 45, 40, 0),
3139 @given(integers(min_value=0, max_value=49))
3140 def test_pre50(self, year):
3142 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3146 @given(integers(min_value=50, max_value=99))
3147 def test_post50(self, year):
3149 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3155 def any_values_strategy(draw, do_expl=False):
3156 value = draw(one_of(none(), binary()))
3159 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3160 optional = draw(one_of(none(), booleans()))
3162 draw(integers(min_value=0)),
3163 draw(integers(min_value=0)),
3164 draw(integers(min_value=0)),
3166 return (value, expl, optional, _decoded)
3169 class AnyInherited(Any):
3173 class TestAny(CommonMixin, TestCase):
3176 def test_invalid_value_type(self):
3177 with self.assertRaises(InvalidValueType) as err:
3182 def test_optional(self, optional):
3183 obj = Any(optional=optional)
3184 self.assertEqual(obj.optional, optional)
3187 def test_ready(self, value):
3189 self.assertFalse(obj.ready)
3192 with self.assertRaises(ObjNotReady) as err:
3196 self.assertTrue(obj.ready)
3201 def test_basic(self, value):
3202 integer_encoded = Integer(value).encode()
3204 Any(integer_encoded),
3205 Any(Integer(value)),
3206 Any(Any(Integer(value))),
3208 self.assertSequenceEqual(bytes(obj), integer_encoded)
3210 obj.decode(obj.encode())[0].vlen,
3211 len(integer_encoded),
3215 self.assertSequenceEqual(obj.encode(), integer_encoded)
3217 @given(binary(), binary())
3218 def test_comparison(self, value1, value2):
3219 for klass in (Any, AnyInherited):
3220 obj1 = klass(value1)
3221 obj2 = klass(value2)
3222 self.assertEqual(obj1 == obj2, value1 == value2)
3223 self.assertEqual(obj1 != obj2, value1 != value2)
3224 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3226 @given(data_strategy())
3227 def test_call(self, d):
3228 for klass in (Any, AnyInherited):
3234 ) = d.draw(any_values_strategy())
3235 obj_initial = klass(
3238 optional_initial or False,
3246 ) = d.draw(any_values_strategy(do_expl=True))
3247 obj = obj_initial(value, expl, optional)
3249 value_expected = None if value is None else value
3250 self.assertEqual(obj, value_expected)
3251 self.assertEqual(obj.expl_tag, expl or expl_initial)
3252 if obj.default is None:
3253 optional = optional_initial if optional is None else optional
3254 optional = False if optional is None else optional
3255 self.assertEqual(obj.optional, optional)
3257 def test_simultaneous_impl_expl(self):
3258 # override it, as Any does not have implicit tag
3261 def test_decoded(self):
3262 # override it, as Any does not have implicit tag
3265 @given(any_values_strategy())
3266 def test_copy(self, values):
3267 for klass in (Any, AnyInherited):
3268 obj = klass(*values)
3269 obj_copied = obj.copy()
3270 self.assert_copied_basic_fields(obj, obj_copied)
3271 self.assertEqual(obj._value, obj_copied._value)
3273 @given(binary().map(OctetString))
3274 def test_stripped(self, value):
3276 with self.assertRaises(NotEnoughData):
3277 obj.decode(obj.encode()[:-1])
3281 integers(min_value=1).map(tag_ctxc),
3283 def test_stripped_expl(self, value, tag_expl):
3284 obj = Any(value, expl=tag_expl)
3285 with self.assertRaises(NotEnoughData):
3286 obj.decode(obj.encode()[:-1])
3289 integers(min_value=31),
3290 integers(min_value=0),
3293 def test_bad_tag(self, tag, offset, decode_path):
3294 decode_path = tuple(str(i) for i in decode_path)
3295 with self.assertRaises(DecodeError) as err:
3297 tag_encode(tag)[:-1],
3299 decode_path=decode_path,
3302 self.assertEqual(err.exception.offset, offset)
3303 self.assertEqual(err.exception.decode_path, decode_path)
3306 integers(min_value=128),
3307 integers(min_value=0),
3310 def test_bad_len(self, l, offset, decode_path):
3311 decode_path = tuple(str(i) for i in decode_path)
3312 with self.assertRaises(DecodeError) as err:
3314 Any.tag_default + len_encode(l)[:-1],
3316 decode_path=decode_path,
3319 self.assertEqual(err.exception.offset, offset)
3320 self.assertEqual(err.exception.decode_path, decode_path)
3322 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3324 any_values_strategy(),
3325 integers().map(lambda x: Integer(x).encode()),
3326 integers(min_value=1).map(tag_ctxc),
3327 integers(min_value=0),
3329 def test_symmetric(self, values, value, tag_expl, offset):
3330 for klass in (Any, AnyInherited):
3331 _, _, optional, _decoded = values
3332 obj = klass(value=value, optional=optional, _decoded=_decoded)
3335 self.assertFalse(obj.expled)
3336 obj_encoded = obj.encode()
3337 obj_expled = obj(value, expl=tag_expl)
3338 self.assertTrue(obj_expled.expled)
3341 obj_expled_encoded = obj_expled.encode()
3342 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
3345 self.assertEqual(tail, b"")
3346 self.assertEqual(obj_decoded, obj_expled)
3347 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3348 self.assertEqual(bytes(obj_decoded), bytes(obj))
3349 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3350 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3351 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3353 obj_decoded.expl_llen,
3354 len(len_encode(len(obj_encoded))),
3356 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3357 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3360 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3362 self.assertEqual(obj_decoded.expl_offset, offset)
3363 self.assertEqual(obj_decoded.tlen, 0)
3364 self.assertEqual(obj_decoded.llen, 0)
3365 self.assertEqual(obj_decoded.vlen, len(value))
3369 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3371 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3372 tags = [tag_encode(tag) for tag in draw(sets(
3373 integers(min_value=0),
3374 min_size=len(names),
3375 max_size=len(names),
3377 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3379 if value_required or draw(booleans()):
3380 value = draw(tuples(
3381 sampled_from([name for name, _ in schema]),
3382 integers().map(Integer),
3386 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3387 default = draw(one_of(
3389 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3391 optional = draw(one_of(none(), booleans()))
3393 draw(integers(min_value=0)),
3394 draw(integers(min_value=0)),
3395 draw(integers(min_value=0)),
3397 return (schema, value, expl, default, optional, _decoded)
3400 class ChoiceInherited(Choice):
3404 class TestChoice(CommonMixin, TestCase):
3406 schema = (("whatever", Boolean()),)
3409 def test_schema_required(self):
3410 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3413 def test_impl_forbidden(self):
3414 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3415 Choice(impl=b"whatever")
3417 def test_invalid_value_type(self):
3418 with self.assertRaises(InvalidValueType) as err:
3419 self.base_klass(123)
3421 with self.assertRaises(ObjUnknown) as err:
3422 self.base_klass(("whenever", Boolean(False)))
3424 with self.assertRaises(InvalidValueType) as err:
3425 self.base_klass(("whatever", Integer(123)))
3429 def test_optional(self, optional):
3430 obj = self.base_klass(
3431 default=self.base_klass(("whatever", Boolean(False))),
3434 self.assertTrue(obj.optional)
3437 def test_ready(self, value):
3438 obj = self.base_klass()
3439 self.assertFalse(obj.ready)
3442 self.assertIsNone(obj["whatever"])
3443 with self.assertRaises(ObjNotReady) as err:
3446 obj["whatever"] = Boolean()
3447 self.assertFalse(obj.ready)
3450 obj["whatever"] = Boolean(value)
3451 self.assertTrue(obj.ready)
3455 @given(booleans(), booleans())
3456 def test_comparison(self, value1, value2):
3457 class WahlInherited(self.base_klass):
3459 for klass in (self.base_klass, WahlInherited):
3460 obj1 = klass(("whatever", Boolean(value1)))
3461 obj2 = klass(("whatever", Boolean(value2)))
3462 self.assertEqual(obj1 == obj2, value1 == value2)
3463 self.assertEqual(obj1 != obj2, value1 != value2)
3464 self.assertEqual(obj1 == obj2._value, value1 == value2)
3465 self.assertFalse(obj1 == obj2._value[1])
3467 @given(data_strategy())
3468 def test_call(self, d):
3469 for klass in (Choice, ChoiceInherited):
3477 ) = d.draw(choice_values_strategy())
3480 schema = schema_initial
3482 value=value_initial,
3484 default=default_initial,
3485 optional=optional_initial or False,
3486 _decoded=_decoded_initial,
3495 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
3496 obj = obj_initial(value, expl, default, optional)
3498 value_expected = default if value is None else value
3500 default_initial if value_expected is None
3503 self.assertEqual(obj.choice, value_expected[0])
3504 self.assertEqual(obj.value, int(value_expected[1]))
3505 self.assertEqual(obj.expl_tag, expl or expl_initial)
3506 default_expect = default_initial if default is None else default
3507 if default_expect is not None:
3508 self.assertEqual(obj.default.choice, default_expect[0])
3509 self.assertEqual(obj.default.value, int(default_expect[1]))
3510 if obj.default is None:
3511 optional = optional_initial if optional is None else optional
3512 optional = False if optional is None else optional
3515 self.assertEqual(obj.optional, optional)
3516 self.assertEqual(obj.specs, obj_initial.specs)
3518 def test_simultaneous_impl_expl(self):
3519 # override it, as Any does not have implicit tag
3522 def test_decoded(self):
3523 # override it, as Any does not have implicit tag
3526 @given(choice_values_strategy())
3527 def test_copy(self, values):
3528 _schema, value, expl, default, optional, _decoded = values
3530 class Wahl(self.base_klass):
3536 optional=optional or False,
3539 obj_copied = obj.copy()
3540 self.assertIsNone(obj.tag)
3541 self.assertIsNone(obj_copied.tag)
3542 # hack for assert_copied_basic_fields
3543 obj.tag = "whatever"
3544 obj_copied.tag = "whatever"
3545 self.assert_copied_basic_fields(obj, obj_copied)
3546 self.assertEqual(obj._value, obj_copied._value)
3547 self.assertEqual(obj.specs, obj_copied.specs)
3550 def test_stripped(self, value):
3551 obj = self.base_klass(("whatever", Boolean(value)))
3552 with self.assertRaises(NotEnoughData):
3553 obj.decode(obj.encode()[:-1])
3557 integers(min_value=1).map(tag_ctxc),
3559 def test_stripped_expl(self, value, tag_expl):
3560 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3561 with self.assertRaises(NotEnoughData):
3562 obj.decode(obj.encode()[:-1])
3564 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3565 @given(data_strategy())
3566 def test_symmetric(self, d):
3567 _schema, value, _, default, optional, _decoded = d.draw(
3568 choice_values_strategy(value_required=True)
3570 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3571 offset = d.draw(integers(min_value=0))
3573 class Wahl(self.base_klass):
3583 self.assertFalse(obj.expled)
3584 obj_encoded = obj.encode()
3585 obj_expled = obj(value, expl=tag_expl)
3586 self.assertTrue(obj_expled.expled)
3589 obj_expled_encoded = obj_expled.encode()
3590 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
3593 self.assertEqual(tail, b"")
3594 self.assertEqual(obj_decoded, obj_expled)
3595 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3596 self.assertEqual(obj_decoded.value, obj_expled.value)
3597 self.assertEqual(obj_decoded.choice, obj.choice)
3598 self.assertEqual(obj_decoded.value, obj.value)
3599 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3600 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3601 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3603 obj_decoded.expl_llen,
3604 len(len_encode(len(obj_encoded))),
3606 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3607 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3610 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3612 self.assertEqual(obj_decoded.expl_offset, offset)
3613 self.assertSequenceEqual(
3615 obj_decoded.value.offset - offset:
3616 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3622 def test_set_get(self, value):
3625 ("erste", Boolean()),
3626 ("zweite", Integer()),
3629 with self.assertRaises(ObjUnknown) as err:
3630 obj["whatever"] = "whenever"
3631 with self.assertRaises(InvalidValueType) as err:
3632 obj["zweite"] = Boolean(False)
3633 obj["zweite"] = Integer(value)
3635 with self.assertRaises(ObjUnknown) as err:
3638 self.assertIsNone(obj["erste"])
3639 self.assertEqual(obj["zweite"], Integer(value))
3641 def test_tag_mismatch(self):
3644 ("erste", Boolean()),
3646 int_encoded = Integer(123).encode()
3647 bool_encoded = Boolean(False).encode()
3649 obj.decode(bool_encoded)
3650 with self.assertRaises(TagMismatch):
3651 obj.decode(int_encoded)
3655 def seq_values_strategy(draw, seq_klass, do_expl=False):
3657 if draw(booleans()):
3660 k: v for k, v in draw(dictionaries(
3663 booleans().map(Boolean),
3664 integers().map(Integer),
3669 if draw(booleans()):
3670 schema = list(draw(dictionaries(
3673 booleans().map(Boolean),
3674 integers().map(Integer),
3680 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3682 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3684 if draw(booleans()):
3685 default = seq_klass()
3687 k: v for k, v in draw(dictionaries(
3690 booleans().map(Boolean),
3691 integers().map(Integer),
3695 optional = draw(one_of(none(), booleans()))
3697 draw(integers(min_value=0)),
3698 draw(integers(min_value=0)),
3699 draw(integers(min_value=0)),
3701 return (value, schema, impl, expl, default, optional, _decoded)
3705 def sequence_strategy(draw, seq_klass):
3706 inputs = draw(lists(
3708 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
3709 tuples(just(Integer), integers(), one_of(none(), integers())),
3714 integers(min_value=1),
3715 min_size=len(inputs),
3716 max_size=len(inputs),
3719 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3720 for tag, expled in zip(tags, draw(lists(
3722 min_size=len(inputs),
3723 max_size=len(inputs),
3727 for i, optional in enumerate(draw(lists(
3728 sampled_from(("required", "optional", "empty")),
3729 min_size=len(inputs),
3730 max_size=len(inputs),
3732 if optional in ("optional", "empty"):
3733 inits[i]["optional"] = True
3734 if optional == "empty":
3736 empties = set(empties)
3737 names = list(draw(sets(
3739 min_size=len(inputs),
3740 max_size=len(inputs),
3743 for i, (klass, value, default) in enumerate(inputs):
3744 schema.append((names[i], klass(default=default, **inits[i])))
3745 seq_name = draw(text_letters())
3746 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3749 for i, (klass, value, default) in enumerate(inputs):
3756 "default_value": None if spec.default is None else default,
3760 expect["optional"] = True
3762 expect["presented"] = True
3763 expect["value"] = value
3765 expect["optional"] = True
3766 if default is not None and default == value:
3767 expect["presented"] = False
3768 seq[name] = klass(value)
3769 expects.append(expect)
3774 def sequences_strategy(draw, seq_klass):
3775 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
3777 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3778 for tag, expled in zip(tags, draw(lists(
3785 i for i, is_default in enumerate(draw(lists(
3791 names = list(draw(sets(
3796 seq_expectses = draw(lists(
3797 sequence_strategy(seq_klass=seq_klass),
3801 seqs = [seq for seq, _ in seq_expectses]
3803 for i, (name, seq) in enumerate(zip(names, seqs)):
3806 seq(default=(seq if i in defaulted else None), **inits[i]),
3808 seq_name = draw(text_letters())
3809 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3812 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
3815 "expects": expects_inner,
3818 seq_outer[name] = seq_inner
3819 if seq_outer.specs[name].default is None:
3820 expect["presented"] = True
3821 expect_outers.append(expect)
3822 return seq_outer, expect_outers
3825 class SeqMixing(object):
3826 def test_invalid_value_type(self):
3827 with self.assertRaises(InvalidValueType) as err:
3828 self.base_klass((1, 2, 3))
3831 def test_invalid_value_type_set(self):
3832 class Seq(self.base_klass):
3833 schema = (("whatever", Boolean()),)
3835 with self.assertRaises(InvalidValueType) as err:
3836 seq["whatever"] = Integer(123)
3840 def test_optional(self, optional):
3841 obj = self.base_klass(default=self.base_klass(), optional=optional)
3842 self.assertTrue(obj.optional)
3844 @given(data_strategy())
3845 def test_ready(self, d):
3847 str(i): v for i, v in enumerate(d.draw(lists(
3854 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
3861 for name in d.draw(permutations(
3862 list(ready.keys()) + list(non_ready.keys()),
3864 schema_input.append((name, Boolean()))
3866 class Seq(self.base_klass):
3867 schema = tuple(schema_input)
3869 for name in ready.keys():
3871 seq[name] = Boolean()
3872 self.assertFalse(seq.ready)
3875 for name, value in ready.items():
3876 seq[name] = Boolean(value)
3877 self.assertFalse(seq.ready)
3880 with self.assertRaises(ObjNotReady) as err:
3883 for name, value in non_ready.items():
3884 seq[name] = Boolean(value)
3885 self.assertTrue(seq.ready)
3889 @given(data_strategy())
3890 def test_call(self, d):
3891 class SeqInherited(self.base_klass):
3893 for klass in (self.base_klass, SeqInherited):
3902 ) = d.draw(seq_values_strategy(seq_klass=klass))
3903 obj_initial = klass(
3909 optional_initial or False,
3920 ) = d.draw(seq_values_strategy(
3922 do_expl=impl_initial is None,
3924 obj = obj_initial(value, impl, expl, default, optional)
3925 value_expected = default if value is None else value
3927 default_initial if value_expected is None
3930 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
3931 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3932 self.assertEqual(obj.expl_tag, expl or expl_initial)
3934 {} if obj.default is None else obj.default._value,
3935 getattr(default_initial if default is None else default, "_value", {}),
3937 if obj.default is None:
3938 optional = optional_initial if optional is None else optional
3939 optional = False if optional is None else optional
3942 self.assertEqual(list(obj.specs.items()), schema_initial or [])
3943 self.assertEqual(obj.optional, optional)
3945 @given(data_strategy())
3946 def test_copy(self, d):
3947 class SeqInherited(self.base_klass):
3949 for klass in (self.base_klass, SeqInherited):
3950 values = d.draw(seq_values_strategy(seq_klass=klass))
3951 obj = klass(*values)
3952 obj_copied = obj.copy()
3953 self.assert_copied_basic_fields(obj, obj_copied)
3954 self.assertEqual(obj.specs, obj_copied.specs)
3955 self.assertEqual(obj._value, obj_copied._value)
3957 @given(data_strategy())
3958 def test_stripped(self, d):
3959 value = d.draw(integers())
3960 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3962 class Seq(self.base_klass):
3964 schema = (("whatever", Integer()),)
3966 seq["whatever"] = Integer(value)
3967 with self.assertRaises(NotEnoughData):
3968 seq.decode(seq.encode()[:-1])
3970 @given(data_strategy())
3971 def test_stripped_expl(self, d):
3972 value = d.draw(integers())
3973 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3975 class Seq(self.base_klass):
3977 schema = (("whatever", Integer()),)
3979 seq["whatever"] = Integer(value)
3980 with self.assertRaises(NotEnoughData):
3981 seq.decode(seq.encode()[:-1])
3983 @given(binary(min_size=2))
3984 def test_non_tag_mismatch_raised(self, junk):
3986 _, _, len_encoded = tag_strip(memoryview(junk))
3987 len_decode(len_encoded)
3993 class Seq(self.base_klass):
3995 ("whatever", Integer()),
3997 ("whenever", Integer()),
4000 seq["whatever"] = Integer(123)
4001 seq["junk"] = Any(junk)
4002 seq["whenever"] = Integer(123)
4003 with self.assertRaises(DecodeError):
4004 seq.decode(seq.encode())
4007 integers(min_value=31),
4008 integers(min_value=0),
4011 def test_bad_tag(self, tag, offset, decode_path):
4012 decode_path = tuple(str(i) for i in decode_path)
4013 with self.assertRaises(DecodeError) as err:
4014 self.base_klass().decode(
4015 tag_encode(tag)[:-1],
4017 decode_path=decode_path,
4020 self.assertEqual(err.exception.offset, offset)
4021 self.assertEqual(err.exception.decode_path, decode_path)
4024 integers(min_value=128),
4025 integers(min_value=0),
4028 def test_bad_len(self, l, offset, decode_path):
4029 decode_path = tuple(str(i) for i in decode_path)
4030 with self.assertRaises(DecodeError) as err:
4031 self.base_klass().decode(
4032 self.base_klass.tag_default + len_encode(l)[:-1],
4034 decode_path=decode_path,
4037 self.assertEqual(err.exception.offset, offset)
4038 self.assertEqual(err.exception.decode_path, decode_path)
4040 def _assert_expects(self, seq, expects):
4041 for expect in expects:
4043 seq.specs[expect["name"]].optional,
4046 if expect["default_value"] is not None:
4048 seq.specs[expect["name"]].default,
4049 expect["default_value"],
4051 if expect["presented"]:
4052 self.assertIn(expect["name"], seq)
4053 self.assertEqual(seq[expect["name"]], expect["value"])
4055 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4056 @given(data_strategy())
4057 def test_symmetric(self, d):
4058 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4059 self.assertTrue(seq.ready)
4060 self.assertFalse(seq.decoded)
4061 self._assert_expects(seq, expects)
4064 seq_encoded = seq.encode()
4065 seq_decoded, tail = seq.decode(seq_encoded)
4066 self.assertEqual(tail, b"")
4067 self.assertTrue(seq.ready)
4068 self._assert_expects(seq_decoded, expects)
4069 self.assertEqual(seq, seq_decoded)
4070 self.assertEqual(seq_decoded.encode(), seq_encoded)
4071 for expect in expects:
4072 if not expect["presented"]:
4073 self.assertNotIn(expect["name"], seq_decoded)
4075 self.assertIn(expect["name"], seq_decoded)
4076 obj = seq_decoded[expect["name"]]
4077 self.assertTrue(obj.decoded)
4078 offset = obj.expl_offset if obj.expled else obj.offset
4079 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4080 self.assertSequenceEqual(
4081 seq_encoded[offset:offset + tlvlen],
4085 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4086 @given(data_strategy())
4087 def test_symmetric_with_seq(self, d):
4088 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4089 self.assertTrue(seq.ready)
4090 seq_encoded = seq.encode()
4091 seq_decoded, tail = seq.decode(seq_encoded)
4092 self.assertEqual(tail, b"")
4093 self.assertTrue(seq.ready)
4094 self.assertEqual(seq, seq_decoded)
4095 self.assertEqual(seq_decoded.encode(), seq_encoded)
4096 for expect_outer in expect_outers:
4097 if not expect_outer["presented"]:
4098 self.assertNotIn(expect_outer["name"], seq_decoded)
4100 self.assertIn(expect_outer["name"], seq_decoded)
4101 obj = seq_decoded[expect_outer["name"]]
4102 self.assertTrue(obj.decoded)
4103 offset = obj.expl_offset if obj.expled else obj.offset
4104 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4105 self.assertSequenceEqual(
4106 seq_encoded[offset:offset + tlvlen],
4109 self._assert_expects(obj, expect_outer["expects"])
4111 @given(data_strategy())
4112 def test_default_disappears(self, d):
4113 _schema = list(d.draw(dictionaries(
4115 sets(integers(), min_size=2, max_size=2),
4119 class Seq(self.base_klass):
4121 (n, Integer(default=d))
4122 for n, (_, d) in _schema
4125 for name, (value, _) in _schema:
4126 seq[name] = Integer(value)
4127 self.assertEqual(len(seq._value), len(_schema))
4128 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4129 self.assertGreater(len(seq.encode()), len(empty_seq))
4130 for name, (_, default) in _schema:
4131 seq[name] = Integer(default)
4132 self.assertEqual(len(seq._value), 0)
4133 self.assertSequenceEqual(seq.encode(), empty_seq)
4135 @given(data_strategy())
4136 def test_encoded_default_accepted(self, d):
4137 _schema = list(d.draw(dictionaries(
4142 tags = [tag_encode(tag) for tag in d.draw(sets(
4143 integers(min_value=0),
4144 min_size=len(_schema),
4145 max_size=len(_schema),
4148 class SeqWithoutDefault(self.base_klass):
4150 (n, Integer(impl=t))
4151 for (n, _), t in zip(_schema, tags)
4153 seq_without_default = SeqWithoutDefault()
4154 for name, value in _schema:
4155 seq_without_default[name] = Integer(value)
4156 seq_encoded = seq_without_default.encode()
4158 class SeqWithDefault(self.base_klass):
4160 (n, Integer(default=v, impl=t))
4161 for (n, v), t in zip(_schema, tags)
4163 seq_with_default = SeqWithDefault()
4164 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4165 for name, value in _schema:
4166 self.assertEqual(seq_decoded[name], seq_with_default[name])
4167 self.assertEqual(seq_decoded[name], value)
4169 @given(data_strategy())
4170 def test_missing_from_spec(self, d):
4171 names = list(d.draw(sets(text_letters(), min_size=2)))
4172 tags = [tag_encode(tag) for tag in d.draw(sets(
4173 integers(min_value=0),
4174 min_size=len(names),
4175 max_size=len(names),
4177 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4179 class SeqFull(self.base_klass):
4180 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4181 seq_full = SeqFull()
4182 for i, name in enumerate(names):
4183 seq_full[name] = Integer(i)
4184 seq_encoded = seq_full.encode()
4185 altered = names_tags[:-2] + names_tags[-1:]
4187 class SeqMissing(self.base_klass):
4188 schema = [(n, Integer(impl=t)) for n, t in altered]
4189 seq_missing = SeqMissing()
4190 with self.assertRaises(TagMismatch):
4191 seq_missing.decode(seq_encoded)
4194 class TestSequence(SeqMixing, CommonMixin, TestCase):
4195 base_klass = Sequence
4201 def test_remaining(self, value, junk):
4202 class Seq(Sequence):
4204 ("whatever", Integer()),
4206 int_encoded = Integer(value).encode()
4208 Sequence.tag_default,
4209 len_encode(len(int_encoded + junk)),
4212 with assertRaisesRegex(self, DecodeError, "remaining"):
4213 Seq().decode(junked)
4215 @given(sets(text_letters(), min_size=2))
4216 def test_obj_unknown(self, names):
4217 missing = names.pop()
4219 class Seq(Sequence):
4220 schema = [(n, Boolean()) for n in names]
4222 with self.assertRaises(ObjUnknown) as err:
4225 with self.assertRaises(ObjUnknown) as err:
4226 seq[missing] = Boolean()
4230 class TestSet(SeqMixing, CommonMixin, TestCase):
4233 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4234 @given(data_strategy())
4235 def test_sorted(self, d):
4237 tag_encode(tag) for tag in
4238 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4242 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4244 for name, _ in Seq.schema:
4245 seq[name] = OctetString(b"")
4246 seq_encoded = seq.encode()
4247 seq_decoded, _ = seq.decode(seq_encoded)
4248 self.assertSequenceEqual(
4249 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4250 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4255 def seqof_values_strategy(draw, schema=None, do_expl=False):
4257 schema = draw(sampled_from((Boolean(), Integer())))
4258 bound_min, bound_max = sorted(draw(sets(
4259 integers(min_value=0, max_value=10),
4263 if isinstance(schema, Boolean):
4264 values_generator = booleans().map(Boolean)
4265 elif isinstance(schema, Integer):
4266 values_generator = integers().map(Integer)
4267 values_generator = lists(
4272 values = draw(one_of(none(), values_generator))
4276 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4278 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4279 default = draw(one_of(none(), values_generator))
4280 optional = draw(one_of(none(), booleans()))
4282 draw(integers(min_value=0)),
4283 draw(integers(min_value=0)),
4284 draw(integers(min_value=0)),
4289 (bound_min, bound_max),
4298 class SeqOfMixing(object):
4299 def test_invalid_value_type(self):
4300 with self.assertRaises(InvalidValueType) as err:
4301 self.base_klass(123)
4304 def test_invalid_values_type(self):
4305 class SeqOf(self.base_klass):
4307 with self.assertRaises(InvalidValueType) as err:
4308 SeqOf([Integer(123), Boolean(False), Integer(234)])
4311 def test_schema_required(self):
4312 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4313 self.base_klass.__mro__[1]()
4315 @given(booleans(), booleans(), binary(), binary())
4316 def test_comparison(self, value1, value2, tag1, tag2):
4317 class SeqOf(self.base_klass):
4319 obj1 = SeqOf([Boolean(value1)])
4320 obj2 = SeqOf([Boolean(value2)])
4321 self.assertEqual(obj1 == obj2, value1 == value2)
4322 self.assertEqual(obj1 != obj2, value1 != value2)
4323 self.assertEqual(obj1 == list(obj2), value1 == value2)
4324 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4325 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4326 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4327 self.assertEqual(obj1 == obj2, tag1 == tag2)
4328 self.assertEqual(obj1 != obj2, tag1 != tag2)
4330 @given(lists(booleans()))
4331 def test_iter(self, values):
4332 class SeqOf(self.base_klass):
4334 obj = SeqOf([Boolean(value) for value in values])
4335 self.assertEqual(len(obj), len(values))
4336 for i, value in enumerate(obj):
4337 self.assertEqual(value, values[i])
4339 @given(data_strategy())
4340 def test_ready(self, d):
4341 ready = [Integer(v) for v in d.draw(lists(
4348 range(d.draw(integers(min_value=1, max_value=5)))
4351 class SeqOf(self.base_klass):
4353 values = d.draw(permutations(ready + non_ready))
4355 for value in values:
4357 self.assertFalse(seqof.ready)
4360 with self.assertRaises(ObjNotReady) as err:
4363 for i, value in enumerate(values):
4364 self.assertEqual(seqof[i], value)
4365 if not seqof[i].ready:
4366 seqof[i] = Integer(i)
4367 self.assertTrue(seqof.ready)
4371 def test_spec_mismatch(self):
4372 class SeqOf(self.base_klass):
4375 seqof.append(Integer(123))
4376 with self.assertRaises(ValueError):
4377 seqof.append(Boolean(False))
4378 with self.assertRaises(ValueError):
4379 seqof[0] = Boolean(False)
4381 @given(data_strategy())
4382 def test_bounds_satisfied(self, d):
4383 class SeqOf(self.base_klass):
4385 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4386 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4387 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4388 SeqOf(value=value, bounds=(bound_min, bound_max))
4390 @given(data_strategy())
4391 def test_bounds_unsatisfied(self, d):
4392 class SeqOf(self.base_klass):
4394 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4395 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4396 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4397 with self.assertRaises(BoundsError) as err:
4398 SeqOf(value=value, bounds=(bound_min, bound_max))
4400 value = [Boolean()] * d.draw(integers(
4401 min_value=bound_max + 1,
4402 max_value=bound_max + 10,
4404 with self.assertRaises(BoundsError) as err:
4405 SeqOf(value=value, bounds=(bound_min, bound_max))
4408 @given(integers(min_value=1, max_value=10))
4409 def test_out_of_bounds(self, bound_max):
4410 class SeqOf(self.base_klass):
4412 bounds = (0, bound_max)
4414 for _ in range(bound_max):
4415 seqof.append(Integer(123))
4416 with self.assertRaises(BoundsError):
4417 seqof.append(Integer(123))
4419 @given(data_strategy())
4420 def test_call(self, d):
4430 ) = d.draw(seqof_values_strategy())
4432 class SeqOf(self.base_klass):
4433 schema = schema_initial
4434 obj_initial = SeqOf(
4435 value=value_initial,
4436 bounds=bounds_initial,
4439 default=default_initial,
4440 optional=optional_initial or False,
4441 _decoded=_decoded_initial,
4452 ) = d.draw(seqof_values_strategy(
4453 schema=schema_initial,
4454 do_expl=impl_initial is None,
4456 if (default is None) and (obj_initial.default is not None):
4459 (bounds is None) and
4460 (value is not None) and
4461 (bounds_initial is not None) and
4462 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4466 (bounds is None) and
4467 (default is not None) and
4468 (bounds_initial is not None) and
4469 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4481 value_expected = default if value is None else value
4483 default_initial if value_expected is None
4486 value_expected = () if value_expected is None else value_expected
4487 self.assertEqual(obj, value_expected)
4488 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4489 self.assertEqual(obj.expl_tag, expl or expl_initial)
4492 default_initial if default is None else default,
4494 if obj.default is None:
4495 optional = optional_initial if optional is None else optional
4496 optional = False if optional is None else optional
4499 self.assertEqual(obj.optional, optional)
4501 (obj._bound_min, obj._bound_max),
4502 bounds or bounds_initial or (0, float("+inf")),
4505 @given(seqof_values_strategy())
4506 def test_copy(self, values):
4507 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4509 class SeqOf(self.base_klass):
4517 optional=optional or False,
4520 obj_copied = obj.copy()
4521 self.assert_copied_basic_fields(obj, obj_copied)
4522 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4523 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4524 self.assertEqual(obj._value, obj_copied._value)
4528 integers(min_value=1).map(tag_encode),
4530 def test_stripped(self, values, tag_impl):
4531 class SeqOf(self.base_klass):
4532 schema = OctetString()
4533 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4534 with self.assertRaises(NotEnoughData):
4535 obj.decode(obj.encode()[:-1])
4539 integers(min_value=1).map(tag_ctxc),
4541 def test_stripped_expl(self, values, tag_expl):
4542 class SeqOf(self.base_klass):
4543 schema = OctetString()
4544 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4545 with self.assertRaises(NotEnoughData):
4546 obj.decode(obj.encode()[:-1])
4549 integers(min_value=31),
4550 integers(min_value=0),
4553 def test_bad_tag(self, tag, offset, decode_path):
4554 decode_path = tuple(str(i) for i in decode_path)
4555 with self.assertRaises(DecodeError) as err:
4556 self.base_klass().decode(
4557 tag_encode(tag)[:-1],
4559 decode_path=decode_path,
4562 self.assertEqual(err.exception.offset, offset)
4563 self.assertEqual(err.exception.decode_path, decode_path)
4566 integers(min_value=128),
4567 integers(min_value=0),
4570 def test_bad_len(self, l, offset, decode_path):
4571 decode_path = tuple(str(i) for i in decode_path)
4572 with self.assertRaises(DecodeError) as err:
4573 self.base_klass().decode(
4574 self.base_klass.tag_default + len_encode(l)[:-1],
4576 decode_path=decode_path,
4579 self.assertEqual(err.exception.offset, offset)
4580 self.assertEqual(err.exception.decode_path, decode_path)
4582 @given(binary(min_size=1))
4583 def test_tag_mismatch(self, impl):
4584 assume(impl != self.base_klass.tag_default)
4585 with self.assertRaises(TagMismatch):
4586 self.base_klass(impl=impl).decode(self.base_klass().encode())
4588 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4590 seqof_values_strategy(schema=Integer()),
4591 lists(integers().map(Integer)),
4592 integers(min_value=1).map(tag_ctxc),
4593 integers(min_value=0),
4595 def test_symmetric(self, values, value, tag_expl, offset):
4596 _, _, _, _, _, default, optional, _decoded = values
4598 class SeqOf(self.base_klass):
4608 self.assertFalse(obj.expled)
4609 obj_encoded = obj.encode()
4610 obj_expled = obj(value, expl=tag_expl)
4611 self.assertTrue(obj_expled.expled)
4614 obj_expled_encoded = obj_expled.encode()
4615 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
4618 self.assertEqual(tail, b"")
4619 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
4620 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4621 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4622 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4624 obj_decoded.expl_llen,
4625 len(len_encode(len(obj_encoded))),
4627 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4628 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4631 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4633 self.assertEqual(obj_decoded.expl_offset, offset)
4634 for obj_inner in obj_decoded:
4635 self.assertIn(obj_inner, obj_decoded)
4636 self.assertSequenceEqual(
4639 obj_inner.offset - offset:
4640 obj_inner.offset + obj_inner.tlvlen - offset
4645 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
4646 class SeqOf(SequenceOf):
4650 def _test_symmetric_compare_objs(self, obj1, obj2):
4651 self.assertEqual(obj1, obj2)
4652 self.assertSequenceEqual(list(obj1), list(obj2))
4655 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
4660 def _test_symmetric_compare_objs(self, obj1, obj2):
4661 self.assertSetEqual(
4662 set(int(v) for v in obj1),
4663 set(int(v) for v in obj2),
4666 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4667 @given(data_strategy())
4668 def test_sorted(self, d):
4669 values = [OctetString(v) for v in d.draw(lists(binary()))]
4672 schema = OctetString()
4674 seq_encoded = seq.encode()
4675 seq_decoded, _ = seq.decode(seq_encoded)
4676 self.assertSequenceEqual(
4677 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4678 b"".join(sorted([v.encode() for v in values])),
4682 class TestGoMarshalVectors(TestCase):
4684 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
4685 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
4686 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
4687 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
4688 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
4690 class Seq(Sequence):
4692 ("erste", Integer()),
4693 ("zweite", Integer(optional=True))
4696 seq["erste"] = Integer(64)
4697 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4698 seq["erste"] = Integer(0x123456)
4699 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
4700 seq["erste"] = Integer(64)
4701 seq["zweite"] = Integer(65)
4702 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
4704 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):
4721 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
4724 seq["erste"] = Integer(64)
4725 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
4727 class Seq(Sequence):
4729 ("erste", Integer(expl=tag_ctxc(5))),
4732 seq["erste"] = Integer(64)
4733 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
4735 class Seq(Sequence):
4738 impl=tag_encode(0, klass=TagClassContext),
4743 seq["erste"] = Null()
4744 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
4746 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4748 self.assertSequenceEqual(
4749 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
4750 hexdec("170d3730303130313030303030305a"),
4752 self.assertSequenceEqual(
4753 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
4754 hexdec("170d3039313131353232353631365a"),
4756 self.assertSequenceEqual(
4757 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
4758 hexdec("180f32313030303430353132303130315a"),
4761 class Seq(Sequence):
4763 ("erste", GeneralizedTime()),
4766 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
4767 self.assertSequenceEqual(
4769 hexdec("3011180f32303039313131353232353631365a"),
4772 self.assertSequenceEqual(
4773 BitString((1, b"\x80")).encode(),
4776 self.assertSequenceEqual(
4777 BitString((12, b"\x81\xF0")).encode(),
4778 hexdec("03030481f0"),
4781 self.assertSequenceEqual(
4782 ObjectIdentifier("1.2.3.4").encode(),
4783 hexdec("06032a0304"),
4785 self.assertSequenceEqual(
4786 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
4787 hexdec("06092a864888932d010105"),
4789 self.assertSequenceEqual(
4790 ObjectIdentifier("2.100.3").encode(),
4791 hexdec("0603813403"),
4794 self.assertSequenceEqual(
4795 PrintableString("test").encode(),
4796 hexdec("130474657374"),
4798 self.assertSequenceEqual(
4799 PrintableString("x" * 127).encode(),
4800 hexdec("137F" + "78" * 127),
4802 self.assertSequenceEqual(
4803 PrintableString("x" * 128).encode(),
4804 hexdec("138180" + "78" * 128),
4806 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
4808 class Seq(Sequence):
4810 ("erste", IA5String()),
4813 seq["erste"] = IA5String("test")
4814 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
4816 class Seq(Sequence):
4818 ("erste", PrintableString()),
4821 seq["erste"] = PrintableString("test")
4822 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
4823 seq["erste"] = PrintableString("test*")
4824 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
4826 class Seq(Sequence):
4828 ("erste", Any(optional=True)),
4829 ("zweite", Integer()),
4832 seq["zweite"] = Integer(64)
4833 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4838 seq.append(Integer(10))
4839 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
4841 class _SeqOf(SequenceOf):
4842 schema = PrintableString()
4844 class SeqOf(SequenceOf):
4847 _seqof.append(PrintableString("1"))
4849 seqof.append(_seqof)
4850 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
4852 class Seq(Sequence):
4854 ("erste", Integer(default=1)),
4857 seq["erste"] = Integer(0)
4858 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
4859 seq["erste"] = Integer(1)
4860 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4861 seq["erste"] = Integer(2)
4862 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
4865 class TestPP(TestCase):
4866 @given(data_strategy())
4867 def test_oid_printing(self, d):
4869 str(ObjectIdentifier(k)): v * 2
4870 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
4872 chosen = d.draw(sampled_from(sorted(oids)))
4873 chosen_id = oids[chosen]
4874 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
4875 self.assertNotIn(chosen_id, pp_console_row(pp))
4876 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
4879 class TestAutoAddSlots(TestCase):
4881 class Inher(Integer):
4884 with self.assertRaises(AttributeError):
4886 inher.unexistent = "whatever"
4889 class TestOIDDefines(TestCase):
4890 @given(data_strategy())
4891 def runTest(self, d):
4892 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
4893 value_name_chosen = d.draw(sampled_from(value_names))
4895 ObjectIdentifier(oid)
4896 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
4898 oid_chosen = d.draw(sampled_from(oids))
4899 values = d.draw(lists(
4901 min_size=len(value_names),
4902 max_size=len(value_names),
4905 ("type", ObjectIdentifier(defines=(value_name_chosen, {
4906 oid: Integer() for oid in oids[:-1]
4909 for i, value_name in enumerate(value_names):
4910 _schema.append((value_name, Any(expl=tag_ctxp(i))))
4912 class Seq(Sequence):
4915 for value_name, value in zip(value_names, values):
4916 seq[value_name] = Any(Integer(value).encode())
4917 seq["type"] = oid_chosen
4918 seq, _ = Seq().decode(seq.encode())
4919 for value_name in value_names:
4920 if value_name == value_name_chosen:
4922 self.assertIsNone(seq[value_name].defined)
4923 if value_name_chosen in oids[:-1]:
4924 self.assertIsNotNone(seq[value_name_chosen].defined)
4925 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
4926 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
4929 class TestDefinesByPath(TestCase):
4931 class Seq(Sequence):
4933 ("type", ObjectIdentifier()),
4934 ("value", OctetString(expl=tag_ctxc(123))),
4937 class SeqInner(Sequence):
4939 ("typeInner", ObjectIdentifier()),
4940 ("valueInner", Any()),
4943 class PairValue(SetOf):
4946 class Pair(Sequence):
4948 ("type", ObjectIdentifier()),
4949 ("value", PairValue()),
4952 class Pairs(SequenceOf):
4959 type_octet_stringed,
4961 ObjectIdentifier(oid)
4962 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
4964 seq_integered = Seq()
4965 seq_integered["type"] = type_integered
4966 seq_integered["value"] = OctetString(Integer(123).encode())
4967 seq_integered_raw = seq_integered.encode()
4971 (type_octet_stringed, OctetString(b"whatever")),
4972 (type_integered, Integer(123)),
4973 (type_octet_stringed, OctetString(b"whenever")),
4974 (type_integered, Integer(234)),
4976 for t, v in pairs_input:
4979 pair["value"] = PairValue((Any(v),))
4981 seq_inner = SeqInner()
4982 seq_inner["typeInner"] = type_innered
4983 seq_inner["valueInner"] = Any(pairs)
4984 seq_sequenced = Seq()
4985 seq_sequenced["type"] = type_sequenced
4986 seq_sequenced["value"] = OctetString(seq_inner.encode())
4987 seq_sequenced_raw = seq_sequenced.encode()
4989 defines_by_path = []
4990 seq_integered, _ = Seq().decode(seq_integered_raw)
4991 self.assertIsNone(seq_integered["value"].defined)
4992 defines_by_path.append(
4993 (("type",), ("value", {
4994 type_integered: Integer(),
4995 type_sequenced: SeqInner(),
4998 seq_integered, _ = Seq().decode(seq_integered_raw, defines_by_path=defines_by_path)
4999 self.assertIsNotNone(seq_integered["value"].defined)
5000 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5001 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5003 seq_sequenced, _ = Seq().decode(seq_sequenced_raw, defines_by_path=defines_by_path)
5004 self.assertIsNotNone(seq_sequenced["value"].defined)
5005 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5006 seq_inner = seq_sequenced["value"].defined[1]
5007 self.assertIsNone(seq_inner["valueInner"].defined)
5009 defines_by_path.append((
5010 ("value", decode_path_defby(type_sequenced), "typeInner"),
5011 ("valueInner", {type_innered: Pairs()}),
5013 seq_sequenced, _ = Seq().decode(seq_sequenced_raw, defines_by_path=defines_by_path)
5014 self.assertIsNotNone(seq_sequenced["value"].defined)
5015 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5016 seq_inner = seq_sequenced["value"].defined[1]
5017 self.assertIsNotNone(seq_inner["valueInner"].defined)
5018 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5019 pairs = seq_inner["valueInner"].defined[1]
5021 self.assertIsNone(pair["value"][0].defined)
5023 defines_by_path.append((
5026 decode_path_defby(type_sequenced),
5028 decode_path_defby(type_innered),
5033 type_integered: Integer(),
5034 type_octet_stringed: OctetString(),
5037 seq_sequenced, _ = Seq().decode(seq_sequenced_raw, defines_by_path=defines_by_path)
5038 self.assertIsNotNone(seq_sequenced["value"].defined)
5039 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5040 seq_inner = seq_sequenced["value"].defined[1]
5041 self.assertIsNotNone(seq_inner["valueInner"].defined)
5042 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5043 pairs_got = seq_inner["valueInner"].defined[1]
5044 for pair_input, pair_got in zip(pairs_input, pairs_got):
5045 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5046 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])