2 # PyDERASN -- Python ASN.1 DER codec with abstract structures
3 # Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from datetime import datetime
20 from string import ascii_letters
21 from string import digits
22 from string import printable
23 from string import whitespace
24 from unittest import TestCase
26 from hypothesis import assume
27 from hypothesis import given
28 from hypothesis import settings
29 from hypothesis.strategies import binary
30 from hypothesis.strategies import booleans
31 from hypothesis.strategies import composite
32 from hypothesis.strategies import data as data_strategy
33 from hypothesis.strategies import datetimes
34 from hypothesis.strategies import dictionaries
35 from hypothesis.strategies import integers
36 from hypothesis.strategies import just
37 from hypothesis.strategies import lists
38 from hypothesis.strategies import none
39 from hypothesis.strategies import one_of
40 from hypothesis.strategies import permutations
41 from hypothesis.strategies import sampled_from
42 from hypothesis.strategies import sets
43 from hypothesis.strategies import text
44 from hypothesis.strategies import tuples
45 from six import assertRaisesRegex
46 from six import byte2int
47 from six import indexbytes
48 from six import int2byte
49 from six import iterbytes
51 from six import text_type
52 from six import unichr as six_unichr
54 from pyderasn import _pp
55 from pyderasn import abs_decode_path
56 from pyderasn import Any
57 from pyderasn import BitString
58 from pyderasn import BMPString
59 from pyderasn import Boolean
60 from pyderasn import BoundsError
61 from pyderasn import Choice
62 from pyderasn import DecodeError
63 from pyderasn import DecodePathDefBy
64 from pyderasn import Enumerated
65 from pyderasn import GeneralizedTime
66 from pyderasn import GeneralString
67 from pyderasn import GraphicString
68 from pyderasn import hexdec
69 from pyderasn import hexenc
70 from pyderasn import IA5String
71 from pyderasn import Integer
72 from pyderasn import InvalidLength
73 from pyderasn import InvalidOID
74 from pyderasn import InvalidValueType
75 from pyderasn import len_decode
76 from pyderasn import len_encode
77 from pyderasn import NotEnoughData
78 from pyderasn import Null
79 from pyderasn import NumericString
80 from pyderasn import ObjectIdentifier
81 from pyderasn import ObjNotReady
82 from pyderasn import ObjUnknown
83 from pyderasn import OctetString
84 from pyderasn import pp_console_row
85 from pyderasn import pprint
86 from pyderasn import PrintableString
87 from pyderasn import Sequence
88 from pyderasn import SequenceOf
89 from pyderasn import Set
90 from pyderasn import SetOf
91 from pyderasn import tag_ctxc
92 from pyderasn import tag_ctxp
93 from pyderasn import tag_decode
94 from pyderasn import tag_encode
95 from pyderasn import tag_strip
96 from pyderasn import TagClassApplication
97 from pyderasn import TagClassContext
98 from pyderasn import TagClassPrivate
99 from pyderasn import TagClassUniversal
100 from pyderasn import TagFormConstructed
101 from pyderasn import TagFormPrimitive
102 from pyderasn import TagMismatch
103 from pyderasn import TeletexString
104 from pyderasn import UniversalString
105 from pyderasn import UTCTime
106 from pyderasn import UTF8String
107 from pyderasn import VideotexString
108 from pyderasn import VisibleString
111 settings.register_profile("local", settings(
113 perform_health_check=False,
115 settings.load_profile("local")
116 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
118 tag_classes = sampled_from((
124 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
127 class TestHex(TestCase):
129 def test_symmetric(self, data):
130 self.assertEqual(hexdec(hexenc(data)), data)
133 class TestTagCoder(TestCase):
134 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
138 integers(min_value=0, max_value=30),
141 def test_short(self, klass, form, num, junk):
142 raw = tag_encode(klass=klass, form=form, num=num)
143 self.assertEqual(tag_decode(raw), (klass, form, num))
144 self.assertEqual(len(raw), 1)
146 byte2int(tag_encode(klass=klass, form=form, num=0)),
147 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
149 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
150 self.assertSequenceEqual(stripped.tobytes(), raw)
151 self.assertEqual(tlen, len(raw))
152 self.assertSequenceEqual(tail, junk)
154 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
158 integers(min_value=31),
161 def test_long(self, klass, form, num, junk):
162 raw = tag_encode(klass=klass, form=form, num=num)
163 self.assertEqual(tag_decode(raw), (klass, form, num))
164 self.assertGreater(len(raw), 1)
166 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
169 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
170 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
171 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
172 self.assertSequenceEqual(stripped.tobytes(), raw)
173 self.assertEqual(tlen, len(raw))
174 self.assertSequenceEqual(tail, junk)
176 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
177 @given(integers(min_value=31))
178 def test_unfinished_tag(self, num):
179 raw = bytearray(tag_encode(num=num))
180 for i in range(1, len(raw)):
182 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
183 tag_strip(bytes(raw))
185 def test_go_vectors_valid(self):
186 for data, (eklass, etag, elen, eform) in (
187 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
188 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
189 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
190 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
191 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
192 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
193 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
194 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
195 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
196 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
198 tag, _, len_encoded = tag_strip(memoryview(data))
199 klass, form, num = tag_decode(tag)
200 _len, _, tail = len_decode(len_encoded)
201 self.assertSequenceEqual(tail, b"")
202 self.assertEqual(klass, eklass)
203 self.assertEqual(num, etag)
204 self.assertEqual(_len, elen)
205 self.assertEqual(form, eform)
207 def test_go_vectors_invalid(self):
215 with self.assertRaises(DecodeError):
216 _, _, len_encoded = tag_strip(memoryview(data))
217 len_decode(len_encoded)
220 integers(min_value=0, max_value=127),
221 integers(min_value=0, max_value=2),
223 def test_long_instead_of_short(self, l, dummy_num):
224 octets = (b"\x00" * dummy_num) + int2byte(l)
225 octets = int2byte((dummy_num + 1) | 0x80) + octets
226 with self.assertRaises(DecodeError):
230 class TestLenCoder(TestCase):
231 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
233 integers(min_value=0, max_value=127),
236 def test_short(self, l, junk):
237 raw = len_encode(l) + junk
238 decoded, llen, tail = len_decode(memoryview(raw))
239 self.assertEqual(decoded, l)
240 self.assertEqual(llen, 1)
241 self.assertEqual(len(raw), 1 + len(junk))
242 self.assertEqual(tail.tobytes(), junk)
244 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
246 integers(min_value=128),
249 def test_long(self, l, junk):
250 raw = len_encode(l) + junk
251 decoded, llen, tail = len_decode(memoryview(raw))
252 self.assertEqual(decoded, l)
253 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
254 self.assertEqual(llen, len(raw) - len(junk))
255 self.assertNotEqual(indexbytes(raw, 1), 0)
256 self.assertSequenceEqual(tail.tobytes(), junk)
258 def test_empty(self):
259 with self.assertRaises(NotEnoughData):
262 @given(integers(min_value=128))
263 def test_stripped(self, _len):
264 with self.assertRaises(NotEnoughData):
265 len_decode(len_encode(_len)[:-1])
268 text_printable = text(alphabet=printable, min_size=1)
272 def text_letters(draw):
273 result = draw(text(alphabet=ascii_letters, min_size=1))
275 result = result.encode("ascii")
279 class CommonMixin(object):
280 def test_tag_default(self):
281 obj = self.base_klass()
282 self.assertEqual(obj.tag, obj.tag_default)
284 def test_simultaneous_impl_expl(self):
285 with self.assertRaises(ValueError):
286 self.base_klass(impl=b"whatever", expl=b"whenever")
288 @given(binary(min_size=1), integers(), integers(), integers())
289 def test_decoded(self, impl, offset, llen, vlen):
290 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
291 self.assertEqual(obj.offset, offset)
292 self.assertEqual(obj.llen, llen)
293 self.assertEqual(obj.vlen, vlen)
294 self.assertEqual(obj.tlen, len(impl))
295 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
297 @given(binary(min_size=1))
298 def test_impl_inherited(self, impl_tag):
299 class Inherited(self.base_klass):
302 self.assertSequenceEqual(obj.impl, impl_tag)
303 self.assertFalse(obj.expled)
306 def test_expl_inherited(self, expl_tag):
307 class Inherited(self.base_klass):
310 self.assertSequenceEqual(obj.expl, expl_tag)
311 self.assertTrue(obj.expled)
313 def assert_copied_basic_fields(self, obj, obj_copied):
314 self.assertEqual(obj, obj_copied)
315 self.assertSequenceEqual(obj.tag, obj_copied.tag)
316 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
317 self.assertEqual(obj.default, obj_copied.default)
318 self.assertEqual(obj.optional, obj_copied.optional)
319 self.assertEqual(obj.offset, obj_copied.offset)
320 self.assertEqual(obj.llen, obj_copied.llen)
321 self.assertEqual(obj.vlen, obj_copied.vlen)
325 def boolean_values_strategy(draw, do_expl=False):
326 value = draw(one_of(none(), booleans()))
330 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
332 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
333 default = draw(one_of(none(), booleans()))
334 optional = draw(one_of(none(), booleans()))
336 draw(integers(min_value=0)),
337 draw(integers(min_value=0)),
338 draw(integers(min_value=0)),
340 return (value, impl, expl, default, optional, _decoded)
343 class BooleanInherited(Boolean):
347 class TestBoolean(CommonMixin, TestCase):
350 def test_invalid_value_type(self):
351 with self.assertRaises(InvalidValueType) as err:
356 def test_optional(self, optional):
357 obj = Boolean(default=Boolean(False), optional=optional)
358 self.assertTrue(obj.optional)
361 def test_ready(self, value):
363 self.assertFalse(obj.ready)
366 with self.assertRaises(ObjNotReady) as err:
370 self.assertTrue(obj.ready)
374 @given(booleans(), booleans(), binary(), binary())
375 def test_comparison(self, value1, value2, tag1, tag2):
376 for klass in (Boolean, BooleanInherited):
379 self.assertEqual(obj1 == obj2, value1 == value2)
380 self.assertEqual(obj1 != obj2, value1 != value2)
381 self.assertEqual(obj1 == bool(obj2), value1 == value2)
382 obj1 = klass(value1, impl=tag1)
383 obj2 = klass(value1, impl=tag2)
384 self.assertEqual(obj1 == obj2, tag1 == tag2)
385 self.assertEqual(obj1 != obj2, tag1 != tag2)
387 @given(data_strategy())
388 def test_call(self, d):
389 for klass in (Boolean, BooleanInherited):
397 ) = d.draw(boolean_values_strategy())
403 optional_initial or False,
413 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
414 obj = obj_initial(value, impl, expl, default, optional)
416 value_expected = default if value is None else value
418 default_initial if value_expected is None
421 self.assertEqual(obj, value_expected)
422 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
423 self.assertEqual(obj.expl_tag, expl or expl_initial)
426 default_initial if default is None else default,
428 if obj.default is None:
429 optional = optional_initial if optional is None else optional
430 optional = False if optional is None else optional
433 self.assertEqual(obj.optional, optional)
435 @given(boolean_values_strategy())
436 def test_copy(self, values):
437 for klass in (Boolean, BooleanInherited):
439 obj_copied = obj.copy()
440 self.assert_copied_basic_fields(obj, obj_copied)
444 integers(min_value=1).map(tag_encode),
446 def test_stripped(self, value, tag_impl):
447 obj = Boolean(value, impl=tag_impl)
448 with self.assertRaises(NotEnoughData):
449 obj.decode(obj.encode()[:-1])
453 integers(min_value=1).map(tag_ctxc),
455 def test_stripped_expl(self, value, tag_expl):
456 obj = Boolean(value, expl=tag_expl)
457 with self.assertRaises(NotEnoughData):
458 obj.decode(obj.encode()[:-1])
461 integers(min_value=31),
462 integers(min_value=0),
465 def test_bad_tag(self, tag, offset, decode_path):
466 decode_path = tuple(str(i) for i in decode_path)
467 with self.assertRaises(DecodeError) as err:
469 tag_encode(tag)[:-1],
471 decode_path=decode_path,
474 self.assertEqual(err.exception.offset, offset)
475 self.assertEqual(err.exception.decode_path, decode_path)
478 integers(min_value=31),
479 integers(min_value=0),
482 def test_bad_expl_tag(self, tag, offset, decode_path):
483 decode_path = tuple(str(i) for i in decode_path)
484 with self.assertRaises(DecodeError) as err:
485 Boolean(expl=Boolean.tag_default).decode(
486 tag_encode(tag)[:-1],
488 decode_path=decode_path,
491 self.assertEqual(err.exception.offset, offset)
492 self.assertEqual(err.exception.decode_path, decode_path)
495 integers(min_value=128),
496 integers(min_value=0),
499 def test_bad_len(self, l, offset, decode_path):
500 decode_path = tuple(str(i) for i in decode_path)
501 with self.assertRaises(DecodeError) as err:
503 Boolean.tag_default + len_encode(l)[:-1],
505 decode_path=decode_path,
508 self.assertEqual(err.exception.offset, offset)
509 self.assertEqual(err.exception.decode_path, decode_path)
512 integers(min_value=128),
513 integers(min_value=0),
516 def test_bad_expl_len(self, l, offset, decode_path):
517 decode_path = tuple(str(i) for i in decode_path)
518 with self.assertRaises(DecodeError) as err:
519 Boolean(expl=Boolean.tag_default).decode(
520 Boolean.tag_default + len_encode(l)[:-1],
522 decode_path=decode_path,
525 self.assertEqual(err.exception.offset, offset)
526 self.assertEqual(err.exception.decode_path, decode_path)
528 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
530 boolean_values_strategy(),
532 integers(min_value=1).map(tag_ctxc),
533 integers(min_value=0),
536 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
537 for klass in (Boolean, BooleanInherited):
538 _, _, _, default, optional, _decoded = values
547 self.assertFalse(obj.expled)
548 obj_encoded = obj.encode()
549 obj_expled = obj(value, expl=tag_expl)
550 self.assertTrue(obj_expled.expled)
553 obj_expled_encoded = obj_expled.encode()
554 obj_decoded, tail = obj_expled.decode(
555 obj_expled_encoded + tail_junk,
560 self.assertEqual(tail, tail_junk)
561 self.assertEqual(obj_decoded, obj_expled)
562 self.assertNotEqual(obj_decoded, obj)
563 self.assertEqual(bool(obj_decoded), bool(obj_expled))
564 self.assertEqual(bool(obj_decoded), bool(obj))
565 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
566 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
567 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
569 obj_decoded.expl_llen,
570 len(len_encode(len(obj_encoded))),
572 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
573 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
576 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
578 self.assertEqual(obj_decoded.expl_offset, offset)
580 @given(integers(min_value=2))
581 def test_invalid_len(self, l):
582 with self.assertRaises(InvalidLength):
583 Boolean().decode(b"".join((
589 @given(integers(min_value=0 + 1, max_value=255 - 1))
590 def test_ber_value(self, value):
591 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
592 Boolean().decode(b"".join((
597 obj, _ = Boolean().decode(
605 self.assertTrue(bool(obj))
606 self.assertTrue(obj.bered)
610 def integer_values_strategy(draw, do_expl=False):
611 bound_min, value, default, bound_max = sorted(draw(sets(
620 _specs = draw(sets(text_letters()))
623 min_size=len(_specs),
624 max_size=len(_specs),
626 _specs = list(zip(_specs, values))
629 bounds = (bound_min, bound_max)
633 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
635 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
638 optional = draw(one_of(none(), booleans()))
640 draw(integers(min_value=0)),
641 draw(integers(min_value=0)),
642 draw(integers(min_value=0)),
644 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
647 class IntegerInherited(Integer):
651 class TestInteger(CommonMixin, TestCase):
654 def test_invalid_value_type(self):
655 with self.assertRaises(InvalidValueType) as err:
659 @given(sets(text_letters(), min_size=2))
660 def test_unknown_name(self, names_input):
661 missing = names_input.pop()
664 schema = [(n, 123) for n in names_input]
665 with self.assertRaises(ObjUnknown) as err:
669 @given(sets(text_letters(), min_size=2))
670 def test_known_name(self, names_input):
672 schema = [(n, 123) for n in names_input]
673 Int(names_input.pop())
676 def test_optional(self, optional):
677 obj = Integer(default=Integer(0), optional=optional)
678 self.assertTrue(obj.optional)
681 def test_ready(self, value):
683 self.assertFalse(obj.ready)
686 with self.assertRaises(ObjNotReady) as err:
690 self.assertTrue(obj.ready)
695 @given(integers(), integers(), binary(), binary())
696 def test_comparison(self, value1, value2, tag1, tag2):
697 for klass in (Integer, IntegerInherited):
700 self.assertEqual(obj1 == obj2, value1 == value2)
701 self.assertEqual(obj1 != obj2, value1 != value2)
702 self.assertEqual(obj1 == int(obj2), value1 == value2)
703 obj1 = klass(value1, impl=tag1)
704 obj2 = klass(value1, impl=tag2)
705 self.assertEqual(obj1 == obj2, tag1 == tag2)
706 self.assertEqual(obj1 != obj2, tag1 != tag2)
708 @given(lists(integers()))
709 def test_sorted_works(self, values):
710 self.assertSequenceEqual(
711 [int(v) for v in sorted(Integer(v) for v in values)],
715 @given(data_strategy())
716 def test_named(self, d):
717 names_input = list(d.draw(sets(text_letters(), min_size=1)))
718 values_input = list(d.draw(sets(
720 min_size=len(names_input),
721 max_size=len(names_input),
723 chosen_name = d.draw(sampled_from(names_input))
724 names_input = dict(zip(names_input, values_input))
728 _int = Int(chosen_name)
729 self.assertEqual(_int.named, chosen_name)
730 self.assertEqual(int(_int), names_input[chosen_name])
732 @given(integers(), integers(min_value=0), integers(min_value=0))
733 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
734 value = bound_min + value_delta
735 bound_max = value + bound_delta
736 Integer(value=value, bounds=(bound_min, bound_max))
738 @given(sets(integers(), min_size=3, max_size=3))
739 def test_bounds_unsatisfied(self, values):
740 values = sorted(values)
741 with self.assertRaises(BoundsError) as err:
742 Integer(value=values[0], bounds=(values[1], values[2]))
744 with self.assertRaises(BoundsError) as err:
745 Integer(value=values[2], bounds=(values[0], values[1]))
748 @given(data_strategy())
749 def test_call(self, d):
750 for klass in (Integer, IntegerInherited):
760 ) = d.draw(integer_values_strategy())
767 optional_initial or False,
780 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
781 if (default is None) and (obj_initial.default is not None):
785 (value is not None) and
786 (bounds_initial is not None) and
787 not (bounds_initial[0] <= value <= bounds_initial[1])
792 (default is not None) and
793 (bounds_initial is not None) and
794 not (bounds_initial[0] <= default <= bounds_initial[1])
797 obj = obj_initial(value, bounds, impl, expl, default, optional)
799 value_expected = default if value is None else value
801 default_initial if value_expected is None
804 self.assertEqual(obj, value_expected)
805 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
806 self.assertEqual(obj.expl_tag, expl or expl_initial)
809 default_initial if default is None else default,
811 if obj.default is None:
812 optional = optional_initial if optional is None else optional
813 optional = False if optional is None else optional
816 self.assertEqual(obj.optional, optional)
818 (obj._bound_min, obj._bound_max),
819 bounds or bounds_initial or (float("-inf"), float("+inf")),
823 {} if _specs_initial is None else dict(_specs_initial),
826 @given(integer_values_strategy())
827 def test_copy(self, values):
828 for klass in (Integer, IntegerInherited):
830 obj_copied = obj.copy()
831 self.assert_copied_basic_fields(obj, obj_copied)
832 self.assertEqual(obj.specs, obj_copied.specs)
833 self.assertEqual(obj._bound_min, obj_copied._bound_min)
834 self.assertEqual(obj._bound_max, obj_copied._bound_max)
835 self.assertEqual(obj._value, obj_copied._value)
839 integers(min_value=1).map(tag_encode),
841 def test_stripped(self, value, tag_impl):
842 obj = Integer(value, impl=tag_impl)
843 with self.assertRaises(NotEnoughData):
844 obj.decode(obj.encode()[:-1])
848 integers(min_value=1).map(tag_ctxc),
850 def test_stripped_expl(self, value, tag_expl):
851 obj = Integer(value, expl=tag_expl)
852 with self.assertRaises(NotEnoughData):
853 obj.decode(obj.encode()[:-1])
855 def test_zero_len(self):
856 with self.assertRaises(NotEnoughData):
857 Integer().decode(b"".join((
863 integers(min_value=31),
864 integers(min_value=0),
867 def test_bad_tag(self, tag, offset, decode_path):
868 decode_path = tuple(str(i) for i in decode_path)
869 with self.assertRaises(DecodeError) as err:
871 tag_encode(tag)[:-1],
873 decode_path=decode_path,
876 self.assertEqual(err.exception.offset, offset)
877 self.assertEqual(err.exception.decode_path, decode_path)
880 integers(min_value=128),
881 integers(min_value=0),
884 def test_bad_len(self, l, offset, decode_path):
885 decode_path = tuple(str(i) for i in decode_path)
886 with self.assertRaises(DecodeError) as err:
888 Integer.tag_default + len_encode(l)[:-1],
890 decode_path=decode_path,
893 self.assertEqual(err.exception.offset, offset)
894 self.assertEqual(err.exception.decode_path, decode_path)
897 sets(integers(), min_size=2, max_size=2),
898 integers(min_value=0),
901 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
902 decode_path = tuple(str(i) for i in decode_path)
903 value, bound_min = list(sorted(ints))
906 bounds = (bound_min, bound_min)
907 with self.assertRaises(DecodeError) as err:
909 Integer(value).encode(),
911 decode_path=decode_path,
914 self.assertEqual(err.exception.offset, offset)
915 self.assertEqual(err.exception.decode_path, decode_path)
917 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
919 integer_values_strategy(),
921 integers(min_value=1).map(tag_ctxc),
922 integers(min_value=0),
925 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
926 for klass in (Integer, IntegerInherited):
927 _, _, _, _, default, optional, _, _decoded = values
936 self.assertFalse(obj.expled)
937 obj_encoded = obj.encode()
938 obj_expled = obj(value, expl=tag_expl)
939 self.assertTrue(obj_expled.expled)
942 obj_expled_encoded = obj_expled.encode()
943 obj_decoded, tail = obj_expled.decode(
944 obj_expled_encoded + tail_junk,
949 self.assertEqual(tail, tail_junk)
950 self.assertEqual(obj_decoded, obj_expled)
951 self.assertNotEqual(obj_decoded, obj)
952 self.assertEqual(int(obj_decoded), int(obj_expled))
953 self.assertEqual(int(obj_decoded), int(obj))
954 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
955 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
956 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
958 obj_decoded.expl_llen,
959 len(len_encode(len(obj_encoded))),
961 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
962 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
965 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
967 self.assertEqual(obj_decoded.expl_offset, offset)
969 def test_go_vectors_valid(self):
970 for data, expect in ((
982 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
983 (b"\x80\x00\x00\x00", -2147483648),
986 Integer().decode(b"".join((
988 len_encode(len(data)),
994 def test_go_vectors_invalid(self):
999 with self.assertRaises(DecodeError):
1000 Integer().decode(b"".join((
1001 Integer.tag_default,
1002 len_encode(len(data)),
1008 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1011 if draw(booleans()):
1012 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1014 integers(min_value=0, max_value=255),
1015 min_size=len(schema),
1016 max_size=len(schema),
1018 schema = list(zip(schema, bits))
1020 def _value(value_required):
1021 if not value_required and draw(booleans()):
1023 generation_choice = 0
1025 generation_choice = draw(sampled_from((1, 2, 3)))
1026 if generation_choice == 1 or draw(booleans()):
1027 return "'%s'B" % "".join(draw(lists(
1028 sampled_from(("0", "1")),
1029 max_size=len(schema),
1031 elif generation_choice == 2 or draw(booleans()):
1032 return draw(binary(max_size=len(schema) // 8))
1033 elif generation_choice == 3 or draw(booleans()):
1034 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1036 value = _value(value_required)
1037 default = _value(value_required=False)
1041 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1043 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1044 optional = draw(one_of(none(), booleans()))
1046 draw(integers(min_value=0)),
1047 draw(integers(min_value=0)),
1048 draw(integers(min_value=0)),
1050 return (schema, value, impl, expl, default, optional, _decoded)
1053 class BitStringInherited(BitString):
1057 class TestBitString(CommonMixin, TestCase):
1058 base_klass = BitString
1060 @given(lists(booleans()))
1061 def test_b_encoding(self, bits):
1062 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1063 self.assertEqual(obj.bit_len, len(bits))
1064 self.assertSequenceEqual(list(obj), bits)
1065 for i, bit in enumerate(bits):
1066 self.assertEqual(obj[i], bit)
1068 @given(lists(booleans()))
1069 def test_out_of_bounds_bits(self, bits):
1070 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1071 for i in range(len(bits), len(bits) * 2):
1072 self.assertFalse(obj[i])
1074 def test_bad_b_encoding(self):
1075 with self.assertRaises(ValueError):
1076 BitString("'010120101'B")
1079 integers(min_value=1, max_value=255),
1080 integers(min_value=1, max_value=255),
1082 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1083 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1084 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1085 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1087 class BS(BitString):
1088 schema = (("whatever", 0),)
1089 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1090 self.assertEqual(obj.bit_len, leading_zeros + 1)
1091 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1093 def test_zero_len(self):
1094 with self.assertRaises(NotEnoughData):
1095 BitString().decode(b"".join((
1096 BitString.tag_default,
1100 def test_invalid_value_type(self):
1101 with self.assertRaises(InvalidValueType) as err:
1104 with self.assertRaises(InvalidValueType) as err:
1108 def test_obj_unknown(self):
1109 with self.assertRaises(ObjUnknown) as err:
1110 BitString(b"whatever")["whenever"]
1113 def test_get_invalid_type(self):
1114 with self.assertRaises(InvalidValueType) as err:
1115 BitString(b"whatever")[(1, 2, 3)]
1118 @given(data_strategy())
1119 def test_unknown_name(self, d):
1120 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1121 missing = _schema.pop()
1123 class BS(BitString):
1124 schema = [(n, i) for i, n in enumerate(_schema)]
1125 with self.assertRaises(ObjUnknown) as err:
1130 def test_optional(self, optional):
1131 obj = BitString(default=BitString(b""), optional=optional)
1132 self.assertTrue(obj.optional)
1135 def test_ready(self, value):
1137 self.assertFalse(obj.ready)
1140 with self.assertRaises(ObjNotReady) as err:
1143 obj = BitString(value)
1144 self.assertTrue(obj.ready)
1149 tuples(integers(min_value=0), binary()),
1150 tuples(integers(min_value=0), binary()),
1154 def test_comparison(self, value1, value2, tag1, tag2):
1155 for klass in (BitString, BitStringInherited):
1156 obj1 = klass(value1)
1157 obj2 = klass(value2)
1158 self.assertEqual(obj1 == obj2, value1 == value2)
1159 self.assertEqual(obj1 != obj2, value1 != value2)
1160 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1161 obj1 = klass(value1, impl=tag1)
1162 obj2 = klass(value1, impl=tag2)
1163 self.assertEqual(obj1 == obj2, tag1 == tag2)
1164 self.assertEqual(obj1 != obj2, tag1 != tag2)
1166 @given(data_strategy())
1167 def test_call(self, d):
1168 for klass in (BitString, BitStringInherited):
1177 ) = d.draw(bit_string_values_strategy())
1180 schema = schema_initial
1182 value=value_initial,
1185 default=default_initial,
1186 optional=optional_initial or False,
1187 _decoded=_decoded_initial,
1197 ) = d.draw(bit_string_values_strategy(
1198 schema=schema_initial,
1199 do_expl=impl_initial is None,
1208 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1209 self.assertEqual(obj.expl_tag, expl or expl_initial)
1210 if obj.default is None:
1211 optional = optional_initial if optional is None else optional
1212 optional = False if optional is None else optional
1215 self.assertEqual(obj.optional, optional)
1216 self.assertEqual(obj.specs, obj_initial.specs)
1218 @given(bit_string_values_strategy())
1219 def test_copy(self, values):
1220 for klass in (BitString, BitStringInherited):
1221 _schema, value, impl, expl, default, optional, _decoded = values
1230 optional=optional or False,
1233 obj_copied = obj.copy()
1234 self.assert_copied_basic_fields(obj, obj_copied)
1235 self.assertEqual(obj.specs, obj_copied.specs)
1236 self.assertEqual(obj._value, obj_copied._value)
1240 integers(min_value=1).map(tag_encode),
1242 def test_stripped(self, value, tag_impl):
1243 obj = BitString(value, impl=tag_impl)
1244 with self.assertRaises(NotEnoughData):
1245 obj.decode(obj.encode()[:-1])
1249 integers(min_value=1).map(tag_ctxc),
1251 def test_stripped_expl(self, value, tag_expl):
1252 obj = BitString(value, expl=tag_expl)
1253 with self.assertRaises(NotEnoughData):
1254 obj.decode(obj.encode()[:-1])
1257 integers(min_value=31),
1258 integers(min_value=0),
1261 def test_bad_tag(self, tag, offset, decode_path):
1262 decode_path = tuple(str(i) for i in decode_path)
1263 with self.assertRaises(DecodeError) as err:
1265 tag_encode(tag)[:-1],
1267 decode_path=decode_path,
1270 self.assertEqual(err.exception.offset, offset)
1271 self.assertEqual(err.exception.decode_path, decode_path)
1274 integers(min_value=128),
1275 integers(min_value=0),
1278 def test_bad_len(self, l, offset, decode_path):
1279 decode_path = tuple(str(i) for i in decode_path)
1280 with self.assertRaises(DecodeError) as err:
1282 BitString.tag_default + len_encode(l)[:-1],
1284 decode_path=decode_path,
1287 self.assertEqual(err.exception.offset, offset)
1288 self.assertEqual(err.exception.decode_path, decode_path)
1290 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1291 @given(data_strategy())
1292 def test_symmetric(self, d):
1301 ) = d.draw(bit_string_values_strategy(value_required=True))
1302 tail_junk = d.draw(binary(max_size=5))
1303 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1304 offset = d.draw(integers(min_value=0))
1305 for klass in (BitString, BitStringInherited):
1316 self.assertFalse(obj.expled)
1317 obj_encoded = obj.encode()
1318 obj_expled = obj(value, expl=tag_expl)
1319 self.assertTrue(obj_expled.expled)
1322 obj_expled_encoded = obj_expled.encode()
1323 obj_decoded, tail = obj_expled.decode(
1324 obj_expled_encoded + tail_junk,
1329 self.assertEqual(tail, tail_junk)
1330 self.assertEqual(obj_decoded, obj_expled)
1331 self.assertNotEqual(obj_decoded, obj)
1332 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1333 self.assertEqual(bytes(obj_decoded), bytes(obj))
1334 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1335 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1336 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1338 obj_decoded.expl_llen,
1339 len(len_encode(len(obj_encoded))),
1341 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1342 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1345 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1347 self.assertEqual(obj_decoded.expl_offset, offset)
1348 if isinstance(value, tuple):
1349 self.assertSetEqual(set(value), set(obj_decoded.named))
1353 @given(integers(min_value=1, max_value=255))
1354 def test_bad_zero_value(self, pad_size):
1355 with self.assertRaises(DecodeError):
1356 BitString().decode(b"".join((
1357 BitString.tag_default,
1362 def test_go_vectors_invalid(self):
1368 with self.assertRaises(DecodeError):
1369 BitString().decode(b"".join((
1370 BitString.tag_default,
1375 def test_go_vectors_valid(self):
1376 obj, _ = BitString().decode(b"".join((
1377 BitString.tag_default,
1381 self.assertEqual(bytes(obj), b"")
1382 self.assertEqual(obj.bit_len, 0)
1384 obj, _ = BitString().decode(b"".join((
1385 BitString.tag_default,
1389 self.assertEqual(bytes(obj), b"\x00")
1390 self.assertEqual(obj.bit_len, 1)
1392 obj = BitString((16, b"\x82\x40"))
1393 self.assertTrue(obj[0])
1394 self.assertFalse(obj[1])
1395 self.assertTrue(obj[6])
1396 self.assertTrue(obj[9])
1397 self.assertFalse(obj[17])
1401 def octet_string_values_strategy(draw, do_expl=False):
1402 bound_min, bound_max = sorted(draw(sets(
1403 integers(min_value=0, max_value=1 << 7),
1407 value = draw(one_of(
1409 binary(min_size=bound_min, max_size=bound_max),
1411 default = draw(one_of(
1413 binary(min_size=bound_min, max_size=bound_max),
1416 if draw(booleans()):
1417 bounds = (bound_min, bound_max)
1421 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1423 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1424 optional = draw(one_of(none(), booleans()))
1426 draw(integers(min_value=0)),
1427 draw(integers(min_value=0)),
1428 draw(integers(min_value=0)),
1430 return (value, bounds, impl, expl, default, optional, _decoded)
1433 class OctetStringInherited(OctetString):
1437 class TestOctetString(CommonMixin, TestCase):
1438 base_klass = OctetString
1440 def test_invalid_value_type(self):
1441 with self.assertRaises(InvalidValueType) as err:
1442 OctetString(text_type(123))
1446 def test_optional(self, optional):
1447 obj = OctetString(default=OctetString(b""), optional=optional)
1448 self.assertTrue(obj.optional)
1451 def test_ready(self, value):
1453 self.assertFalse(obj.ready)
1456 with self.assertRaises(ObjNotReady) as err:
1459 obj = OctetString(value)
1460 self.assertTrue(obj.ready)
1464 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1465 def test_comparison(self, value1, value2, tag1, tag2):
1466 for klass in (OctetString, OctetStringInherited):
1467 obj1 = klass(value1)
1468 obj2 = klass(value2)
1469 self.assertEqual(obj1 == obj2, value1 == value2)
1470 self.assertEqual(obj1 != obj2, value1 != value2)
1471 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1472 obj1 = klass(value1, impl=tag1)
1473 obj2 = klass(value1, impl=tag2)
1474 self.assertEqual(obj1 == obj2, tag1 == tag2)
1475 self.assertEqual(obj1 != obj2, tag1 != tag2)
1477 @given(lists(binary()))
1478 def test_sorted_works(self, values):
1479 self.assertSequenceEqual(
1480 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1484 @given(data_strategy())
1485 def test_bounds_satisfied(self, d):
1486 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1487 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1488 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1489 OctetString(value=value, bounds=(bound_min, bound_max))
1491 @given(data_strategy())
1492 def test_bounds_unsatisfied(self, d):
1493 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1494 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1495 value = d.draw(binary(max_size=bound_min - 1))
1496 with self.assertRaises(BoundsError) as err:
1497 OctetString(value=value, bounds=(bound_min, bound_max))
1499 value = d.draw(binary(min_size=bound_max + 1))
1500 with self.assertRaises(BoundsError) as err:
1501 OctetString(value=value, bounds=(bound_min, bound_max))
1504 @given(data_strategy())
1505 def test_call(self, d):
1506 for klass in (OctetString, OctetStringInherited):
1515 ) = d.draw(octet_string_values_strategy())
1516 obj_initial = klass(
1522 optional_initial or False,
1533 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1534 if (default is None) and (obj_initial.default is not None):
1537 (bounds is None) and
1538 (value is not None) and
1539 (bounds_initial is not None) and
1540 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1544 (bounds is None) and
1545 (default is not None) and
1546 (bounds_initial is not None) and
1547 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1550 obj = obj_initial(value, bounds, impl, expl, default, optional)
1552 value_expected = default if value is None else value
1554 default_initial if value_expected is None
1557 self.assertEqual(obj, value_expected)
1558 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1559 self.assertEqual(obj.expl_tag, expl or expl_initial)
1562 default_initial if default is None else default,
1564 if obj.default is None:
1565 optional = optional_initial if optional is None else optional
1566 optional = False if optional is None else optional
1569 self.assertEqual(obj.optional, optional)
1571 (obj._bound_min, obj._bound_max),
1572 bounds or bounds_initial or (0, float("+inf")),
1575 @given(octet_string_values_strategy())
1576 def test_copy(self, values):
1577 for klass in (OctetString, OctetStringInherited):
1578 obj = klass(*values)
1579 obj_copied = obj.copy()
1580 self.assert_copied_basic_fields(obj, obj_copied)
1581 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1582 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1583 self.assertEqual(obj._value, obj_copied._value)
1587 integers(min_value=1).map(tag_encode),
1589 def test_stripped(self, value, tag_impl):
1590 obj = OctetString(value, impl=tag_impl)
1591 with self.assertRaises(NotEnoughData):
1592 obj.decode(obj.encode()[:-1])
1596 integers(min_value=1).map(tag_ctxc),
1598 def test_stripped_expl(self, value, tag_expl):
1599 obj = OctetString(value, expl=tag_expl)
1600 with self.assertRaises(NotEnoughData):
1601 obj.decode(obj.encode()[:-1])
1604 integers(min_value=31),
1605 integers(min_value=0),
1608 def test_bad_tag(self, tag, offset, decode_path):
1609 decode_path = tuple(str(i) for i in decode_path)
1610 with self.assertRaises(DecodeError) as err:
1611 OctetString().decode(
1612 tag_encode(tag)[:-1],
1614 decode_path=decode_path,
1617 self.assertEqual(err.exception.offset, offset)
1618 self.assertEqual(err.exception.decode_path, decode_path)
1621 integers(min_value=128),
1622 integers(min_value=0),
1625 def test_bad_len(self, l, offset, decode_path):
1626 decode_path = tuple(str(i) for i in decode_path)
1627 with self.assertRaises(DecodeError) as err:
1628 OctetString().decode(
1629 OctetString.tag_default + len_encode(l)[:-1],
1631 decode_path=decode_path,
1634 self.assertEqual(err.exception.offset, offset)
1635 self.assertEqual(err.exception.decode_path, decode_path)
1638 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1639 integers(min_value=0),
1642 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1643 decode_path = tuple(str(i) for i in decode_path)
1644 value, bound_min = list(sorted(ints))
1646 class String(OctetString):
1647 bounds = (bound_min, bound_min)
1648 with self.assertRaises(DecodeError) as err:
1650 OctetString(b"\x00" * value).encode(),
1652 decode_path=decode_path,
1655 self.assertEqual(err.exception.offset, offset)
1656 self.assertEqual(err.exception.decode_path, decode_path)
1658 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1660 octet_string_values_strategy(),
1662 integers(min_value=1).map(tag_ctxc),
1663 integers(min_value=0),
1666 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1667 for klass in (OctetString, OctetStringInherited):
1668 _, _, _, _, default, optional, _decoded = values
1677 self.assertFalse(obj.expled)
1678 obj_encoded = obj.encode()
1679 obj_expled = obj(value, expl=tag_expl)
1680 self.assertTrue(obj_expled.expled)
1683 obj_expled_encoded = obj_expled.encode()
1684 obj_decoded, tail = obj_expled.decode(
1685 obj_expled_encoded + tail_junk,
1690 self.assertEqual(tail, tail_junk)
1691 self.assertEqual(obj_decoded, obj_expled)
1692 self.assertNotEqual(obj_decoded, obj)
1693 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1694 self.assertEqual(bytes(obj_decoded), bytes(obj))
1695 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1696 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1697 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1699 obj_decoded.expl_llen,
1700 len(len_encode(len(obj_encoded))),
1702 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1703 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1706 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1708 self.assertEqual(obj_decoded.expl_offset, offset)
1712 def null_values_strategy(draw, do_expl=False):
1716 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1718 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1719 optional = draw(one_of(none(), booleans()))
1721 draw(integers(min_value=0)),
1722 draw(integers(min_value=0)),
1723 draw(integers(min_value=0)),
1725 return (impl, expl, optional, _decoded)
1728 class NullInherited(Null):
1732 class TestNull(CommonMixin, TestCase):
1735 def test_ready(self):
1737 self.assertTrue(obj.ready)
1741 @given(binary(), binary())
1742 def test_comparison(self, tag1, tag2):
1743 for klass in (Null, NullInherited):
1744 obj1 = klass(impl=tag1)
1745 obj2 = klass(impl=tag2)
1746 self.assertEqual(obj1 == obj2, tag1 == tag2)
1747 self.assertEqual(obj1 != obj2, tag1 != tag2)
1748 self.assertNotEqual(obj1, tag2)
1750 @given(data_strategy())
1751 def test_call(self, d):
1752 for klass in (Null, NullInherited):
1758 ) = d.draw(null_values_strategy())
1759 obj_initial = klass(
1762 optional=optional_initial or False,
1763 _decoded=_decoded_initial,
1770 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
1771 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1772 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1773 self.assertEqual(obj.expl_tag, expl or expl_initial)
1774 optional = optional_initial if optional is None else optional
1775 optional = False if optional is None else optional
1776 self.assertEqual(obj.optional, optional)
1778 @given(null_values_strategy())
1779 def test_copy(self, values):
1780 for klass in (Null, NullInherited):
1781 impl, expl, optional, _decoded = values
1785 optional=optional or False,
1788 obj_copied = obj.copy()
1789 self.assert_copied_basic_fields(obj, obj_copied)
1791 @given(integers(min_value=1).map(tag_encode))
1792 def test_stripped(self, tag_impl):
1793 obj = Null(impl=tag_impl)
1794 with self.assertRaises(NotEnoughData):
1795 obj.decode(obj.encode()[:-1])
1797 @given(integers(min_value=1).map(tag_ctxc))
1798 def test_stripped_expl(self, tag_expl):
1799 obj = Null(expl=tag_expl)
1800 with self.assertRaises(NotEnoughData):
1801 obj.decode(obj.encode()[:-1])
1804 integers(min_value=31),
1805 integers(min_value=0),
1808 def test_bad_tag(self, tag, offset, decode_path):
1809 decode_path = tuple(str(i) for i in decode_path)
1810 with self.assertRaises(DecodeError) as err:
1812 tag_encode(tag)[:-1],
1814 decode_path=decode_path,
1817 self.assertEqual(err.exception.offset, offset)
1818 self.assertEqual(err.exception.decode_path, decode_path)
1821 integers(min_value=128),
1822 integers(min_value=0),
1825 def test_bad_len(self, l, offset, decode_path):
1826 decode_path = tuple(str(i) for i in decode_path)
1827 with self.assertRaises(DecodeError) as err:
1829 Null.tag_default + len_encode(l)[:-1],
1831 decode_path=decode_path,
1834 self.assertEqual(err.exception.offset, offset)
1835 self.assertEqual(err.exception.decode_path, decode_path)
1837 @given(binary(min_size=1))
1838 def test_tag_mismatch(self, impl):
1839 assume(impl != Null.tag_default)
1840 with self.assertRaises(TagMismatch):
1841 Null(impl=impl).decode(Null().encode())
1844 null_values_strategy(),
1845 integers(min_value=1).map(tag_ctxc),
1846 integers(min_value=0),
1849 def test_symmetric(self, values, tag_expl, offset, tail_junk):
1850 for klass in (Null, NullInherited):
1851 _, _, optional, _decoded = values
1852 obj = klass(optional=optional, _decoded=_decoded)
1855 self.assertFalse(obj.expled)
1856 obj_encoded = obj.encode()
1857 obj_expled = obj(expl=tag_expl)
1858 self.assertTrue(obj_expled.expled)
1861 obj_expled_encoded = obj_expled.encode()
1862 obj_decoded, tail = obj_expled.decode(
1863 obj_expled_encoded + tail_junk,
1868 self.assertEqual(tail, tail_junk)
1869 self.assertEqual(obj_decoded, obj_expled)
1870 self.assertNotEqual(obj_decoded, obj)
1871 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1872 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1873 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1875 obj_decoded.expl_llen,
1876 len(len_encode(len(obj_encoded))),
1878 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1879 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1882 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1884 self.assertEqual(obj_decoded.expl_offset, offset)
1886 @given(integers(min_value=1))
1887 def test_invalid_len(self, l):
1888 with self.assertRaises(InvalidLength):
1889 Null().decode(b"".join((
1896 def oid_strategy(draw):
1897 first_arc = draw(integers(min_value=0, max_value=2))
1899 if first_arc in (0, 1):
1900 second_arc = draw(integers(min_value=0, max_value=39))
1902 second_arc = draw(integers(min_value=0))
1903 other_arcs = draw(lists(integers(min_value=0)))
1904 return tuple([first_arc, second_arc] + other_arcs)
1908 def oid_values_strategy(draw, do_expl=False):
1909 value = draw(one_of(none(), oid_strategy()))
1913 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1915 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1916 default = draw(one_of(none(), oid_strategy()))
1917 optional = draw(one_of(none(), booleans()))
1919 draw(integers(min_value=0)),
1920 draw(integers(min_value=0)),
1921 draw(integers(min_value=0)),
1923 return (value, impl, expl, default, optional, _decoded)
1926 class ObjectIdentifierInherited(ObjectIdentifier):
1930 class TestObjectIdentifier(CommonMixin, TestCase):
1931 base_klass = ObjectIdentifier
1933 def test_invalid_value_type(self):
1934 with self.assertRaises(InvalidValueType) as err:
1935 ObjectIdentifier(123)
1939 def test_optional(self, optional):
1940 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
1941 self.assertTrue(obj.optional)
1943 @given(oid_strategy())
1944 def test_ready(self, value):
1945 obj = ObjectIdentifier()
1946 self.assertFalse(obj.ready)
1949 with self.assertRaises(ObjNotReady) as err:
1952 obj = ObjectIdentifier(value)
1953 self.assertTrue(obj.ready)
1958 @given(oid_strategy(), oid_strategy(), binary(), binary())
1959 def test_comparison(self, value1, value2, tag1, tag2):
1960 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1961 obj1 = klass(value1)
1962 obj2 = klass(value2)
1963 self.assertEqual(obj1 == obj2, value1 == value2)
1964 self.assertEqual(obj1 != obj2, value1 != value2)
1965 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
1966 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
1967 obj1 = klass(value1, impl=tag1)
1968 obj2 = klass(value1, impl=tag2)
1969 self.assertEqual(obj1 == obj2, tag1 == tag2)
1970 self.assertEqual(obj1 != obj2, tag1 != tag2)
1972 @given(lists(oid_strategy()))
1973 def test_sorted_works(self, values):
1974 self.assertSequenceEqual(
1975 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
1979 @given(data_strategy())
1980 def test_call(self, d):
1981 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1989 ) = d.draw(oid_values_strategy())
1990 obj_initial = klass(
1991 value=value_initial,
1994 default=default_initial,
1995 optional=optional_initial or False,
1996 _decoded=_decoded_initial,
2005 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2014 value_expected = default if value is None else value
2016 default_initial if value_expected is None
2019 self.assertEqual(obj, value_expected)
2020 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2021 self.assertEqual(obj.expl_tag, expl or expl_initial)
2024 default_initial if default is None else default,
2026 if obj.default is None:
2027 optional = optional_initial if optional is None else optional
2028 optional = False if optional is None else optional
2031 self.assertEqual(obj.optional, optional)
2033 @given(oid_values_strategy())
2034 def test_copy(self, values):
2035 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2052 obj_copied = obj.copy()
2053 self.assert_copied_basic_fields(obj, obj_copied)
2054 self.assertEqual(obj._value, obj_copied._value)
2056 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2059 integers(min_value=1).map(tag_encode),
2061 def test_stripped(self, value, tag_impl):
2062 obj = ObjectIdentifier(value, impl=tag_impl)
2063 with self.assertRaises(NotEnoughData):
2064 obj.decode(obj.encode()[:-1])
2068 integers(min_value=1).map(tag_ctxc),
2070 def test_stripped_expl(self, value, tag_expl):
2071 obj = ObjectIdentifier(value, expl=tag_expl)
2072 with self.assertRaises(NotEnoughData):
2073 obj.decode(obj.encode()[:-1])
2076 integers(min_value=31),
2077 integers(min_value=0),
2080 def test_bad_tag(self, tag, offset, decode_path):
2081 decode_path = tuple(str(i) for i in decode_path)
2082 with self.assertRaises(DecodeError) as err:
2083 ObjectIdentifier().decode(
2084 tag_encode(tag)[:-1],
2086 decode_path=decode_path,
2089 self.assertEqual(err.exception.offset, offset)
2090 self.assertEqual(err.exception.decode_path, decode_path)
2093 integers(min_value=128),
2094 integers(min_value=0),
2097 def test_bad_len(self, l, offset, decode_path):
2098 decode_path = tuple(str(i) for i in decode_path)
2099 with self.assertRaises(DecodeError) as err:
2100 ObjectIdentifier().decode(
2101 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2103 decode_path=decode_path,
2106 self.assertEqual(err.exception.offset, offset)
2107 self.assertEqual(err.exception.decode_path, decode_path)
2109 def test_zero_oid(self):
2110 with self.assertRaises(NotEnoughData):
2111 ObjectIdentifier().decode(
2112 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2115 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2116 @given(oid_strategy())
2117 def test_unfinished_oid(self, value):
2118 assume(list(value)[-1] > 255)
2119 obj_encoded = ObjectIdentifier(value).encode()
2120 obj, _ = ObjectIdentifier().decode(obj_encoded)
2121 data = obj_encoded[obj.tlen + obj.llen:-1]
2123 ObjectIdentifier.tag_default,
2124 len_encode(len(data)),
2127 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2130 @given(integers(min_value=0))
2131 def test_invalid_short(self, value):
2132 with self.assertRaises(InvalidOID):
2133 ObjectIdentifier((value,))
2134 with self.assertRaises(InvalidOID):
2135 ObjectIdentifier("%d" % value)
2137 @given(integers(min_value=3), integers(min_value=0))
2138 def test_invalid_first_arc(self, first_arc, second_arc):
2139 with self.assertRaises(InvalidOID):
2140 ObjectIdentifier((first_arc, second_arc))
2141 with self.assertRaises(InvalidOID):
2142 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2144 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2145 def test_invalid_second_arc(self, first_arc, second_arc):
2146 with self.assertRaises(InvalidOID):
2147 ObjectIdentifier((first_arc, second_arc))
2148 with self.assertRaises(InvalidOID):
2149 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2151 @given(text(alphabet=ascii_letters + ".", min_size=1))
2152 def test_junk(self, oid):
2153 with self.assertRaises(InvalidOID):
2154 ObjectIdentifier(oid)
2156 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2157 @given(oid_strategy())
2158 def test_validness(self, oid):
2159 obj = ObjectIdentifier(oid)
2160 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2165 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2167 oid_values_strategy(),
2169 integers(min_value=1).map(tag_ctxc),
2170 integers(min_value=0),
2173 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2174 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2175 _, _, _, default, optional, _decoded = values
2184 self.assertFalse(obj.expled)
2185 obj_encoded = obj.encode()
2186 obj_expled = obj(value, expl=tag_expl)
2187 self.assertTrue(obj_expled.expled)
2190 obj_expled_encoded = obj_expled.encode()
2191 obj_decoded, tail = obj_expled.decode(
2192 obj_expled_encoded + tail_junk,
2197 self.assertEqual(tail, tail_junk)
2198 self.assertEqual(obj_decoded, obj_expled)
2199 self.assertNotEqual(obj_decoded, obj)
2200 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2201 self.assertEqual(tuple(obj_decoded), tuple(obj))
2202 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2203 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2204 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2206 obj_decoded.expl_llen,
2207 len(len_encode(len(obj_encoded))),
2209 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2210 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2213 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2215 self.assertEqual(obj_decoded.expl_offset, offset)
2218 oid_strategy().map(ObjectIdentifier),
2219 oid_strategy().map(ObjectIdentifier),
2221 def test_add(self, oid1, oid2):
2222 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2223 for oid_to_add in (oid2, tuple(oid2)):
2224 self.assertEqual(oid1 + oid_to_add, oid_expect)
2225 with self.assertRaises(InvalidValueType):
2228 def test_go_vectors_valid(self):
2229 for data, expect in (
2231 (b"\x55\x02", (2, 5, 2)),
2232 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2233 (b"\x81\x34\x03", (2, 100, 3)),
2236 ObjectIdentifier().decode(b"".join((
2237 ObjectIdentifier.tag_default,
2238 len_encode(len(data)),
2244 def test_go_vectors_invalid(self):
2245 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2246 with self.assertRaises(DecodeError):
2247 ObjectIdentifier().decode(b"".join((
2248 Integer.tag_default,
2249 len_encode(len(data)),
2253 def test_x690_vector(self):
2255 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2256 ObjectIdentifier((2, 999, 3)),
2261 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2263 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2264 values = list(draw(sets(
2266 min_size=len(schema),
2267 max_size=len(schema),
2269 schema = list(zip(schema, values))
2270 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2274 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2276 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2277 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2278 optional = draw(one_of(none(), booleans()))
2280 draw(integers(min_value=0)),
2281 draw(integers(min_value=0)),
2282 draw(integers(min_value=0)),
2284 return (schema, value, impl, expl, default, optional, _decoded)
2287 class TestEnumerated(CommonMixin, TestCase):
2288 class EWhatever(Enumerated):
2289 schema = (("whatever", 0),)
2291 base_klass = EWhatever
2293 def test_schema_required(self):
2294 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2297 def test_invalid_value_type(self):
2298 with self.assertRaises(InvalidValueType) as err:
2299 self.base_klass((1, 2))
2302 @given(sets(text_letters(), min_size=2))
2303 def test_unknown_name(self, schema_input):
2304 missing = schema_input.pop()
2306 class E(Enumerated):
2307 schema = [(n, 123) for n in schema_input]
2308 with self.assertRaises(ObjUnknown) as err:
2313 sets(text_letters(), min_size=2),
2314 sets(integers(), min_size=2),
2316 def test_unknown_value(self, schema_input, values_input):
2318 missing_value = values_input.pop()
2319 _input = list(zip(schema_input, values_input))
2321 class E(Enumerated):
2323 with self.assertRaises(DecodeError) as err:
2328 def test_optional(self, optional):
2329 obj = self.base_klass(default="whatever", optional=optional)
2330 self.assertTrue(obj.optional)
2332 def test_ready(self):
2333 obj = self.base_klass()
2334 self.assertFalse(obj.ready)
2337 with self.assertRaises(ObjNotReady) as err:
2340 obj = self.base_klass("whatever")
2341 self.assertTrue(obj.ready)
2345 @given(integers(), integers(), binary(), binary())
2346 def test_comparison(self, value1, value2, tag1, tag2):
2347 class E(Enumerated):
2349 ("whatever0", value1),
2350 ("whatever1", value2),
2353 class EInherited(E):
2355 for klass in (E, EInherited):
2356 obj1 = klass(value1)
2357 obj2 = klass(value2)
2358 self.assertEqual(obj1 == obj2, value1 == value2)
2359 self.assertEqual(obj1 != obj2, value1 != value2)
2360 self.assertEqual(obj1 == int(obj2), value1 == value2)
2361 obj1 = klass(value1, impl=tag1)
2362 obj2 = klass(value1, impl=tag2)
2363 self.assertEqual(obj1 == obj2, tag1 == tag2)
2364 self.assertEqual(obj1 != obj2, tag1 != tag2)
2366 @given(data_strategy())
2367 def test_call(self, d):
2376 ) = d.draw(enumerated_values_strategy())
2378 class E(Enumerated):
2379 schema = schema_initial
2381 value=value_initial,
2384 default=default_initial,
2385 optional=optional_initial or False,
2386 _decoded=_decoded_initial,
2396 ) = d.draw(enumerated_values_strategy(
2397 schema=schema_initial,
2398 do_expl=impl_initial is None,
2408 value_expected = default if value is None else value
2410 default_initial if value_expected is None
2415 dict(schema_initial).get(value_expected, value_expected),
2417 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2418 self.assertEqual(obj.expl_tag, expl or expl_initial)
2421 default_initial if default is None else default,
2423 if obj.default is None:
2424 optional = optional_initial if optional is None else optional
2425 optional = False if optional is None else optional
2428 self.assertEqual(obj.optional, optional)
2429 self.assertEqual(obj.specs, dict(schema_initial))
2431 @given(enumerated_values_strategy())
2432 def test_copy(self, values):
2433 schema_input, value, impl, expl, default, optional, _decoded = values
2435 class E(Enumerated):
2436 schema = schema_input
2445 obj_copied = obj.copy()
2446 self.assert_copied_basic_fields(obj, obj_copied)
2447 self.assertEqual(obj.specs, obj_copied.specs)
2449 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2450 @given(data_strategy())
2451 def test_symmetric(self, d):
2452 schema_input, _, _, _, default, optional, _decoded = d.draw(
2453 enumerated_values_strategy(),
2455 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2456 offset = d.draw(integers(min_value=0))
2457 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2458 tail_junk = d.draw(binary(max_size=5))
2460 class E(Enumerated):
2461 schema = schema_input
2470 self.assertFalse(obj.expled)
2471 obj_encoded = obj.encode()
2472 obj_expled = obj(value, expl=tag_expl)
2473 self.assertTrue(obj_expled.expled)
2476 obj_expled_encoded = obj_expled.encode()
2477 obj_decoded, tail = obj_expled.decode(
2478 obj_expled_encoded + tail_junk,
2483 self.assertEqual(tail, tail_junk)
2484 self.assertEqual(obj_decoded, obj_expled)
2485 self.assertNotEqual(obj_decoded, obj)
2486 self.assertEqual(int(obj_decoded), int(obj_expled))
2487 self.assertEqual(int(obj_decoded), int(obj))
2488 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2489 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2490 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2492 obj_decoded.expl_llen,
2493 len(len_encode(len(obj_encoded))),
2495 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2496 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2499 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2501 self.assertEqual(obj_decoded.expl_offset, offset)
2505 def string_values_strategy(draw, alphabet, do_expl=False):
2506 bound_min, bound_max = sorted(draw(sets(
2507 integers(min_value=0, max_value=1 << 7),
2511 value = draw(one_of(
2513 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2515 default = draw(one_of(
2517 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2520 if draw(booleans()):
2521 bounds = (bound_min, bound_max)
2525 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2527 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2528 optional = draw(one_of(none(), booleans()))
2530 draw(integers(min_value=0)),
2531 draw(integers(min_value=0)),
2532 draw(integers(min_value=0)),
2534 return (value, bounds, impl, expl, default, optional, _decoded)
2537 class StringMixin(object):
2538 def test_invalid_value_type(self):
2539 with self.assertRaises(InvalidValueType) as err:
2540 self.base_klass((1, 2))
2543 def text_alphabet(self):
2544 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2545 return printable + whitespace
2549 def test_optional(self, optional):
2550 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2551 self.assertTrue(obj.optional)
2553 @given(data_strategy())
2554 def test_ready(self, d):
2555 obj = self.base_klass()
2556 self.assertFalse(obj.ready)
2560 with self.assertRaises(ObjNotReady) as err:
2563 value = d.draw(text(alphabet=self.text_alphabet()))
2564 obj = self.base_klass(value)
2565 self.assertTrue(obj.ready)
2570 @given(data_strategy())
2571 def test_comparison(self, d):
2572 value1 = d.draw(text(alphabet=self.text_alphabet()))
2573 value2 = d.draw(text(alphabet=self.text_alphabet()))
2574 tag1 = d.draw(binary(min_size=1))
2575 tag2 = d.draw(binary(min_size=1))
2576 obj1 = self.base_klass(value1)
2577 obj2 = self.base_klass(value2)
2578 self.assertEqual(obj1 == obj2, value1 == value2)
2579 self.assertEqual(obj1 != obj2, value1 != value2)
2580 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2581 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2582 obj1 = self.base_klass(value1, impl=tag1)
2583 obj2 = self.base_klass(value1, impl=tag2)
2584 self.assertEqual(obj1 == obj2, tag1 == tag2)
2585 self.assertEqual(obj1 != obj2, tag1 != tag2)
2587 @given(data_strategy())
2588 def test_bounds_satisfied(self, d):
2589 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2590 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2591 value = d.draw(text(
2592 alphabet=self.text_alphabet(),
2596 self.base_klass(value=value, bounds=(bound_min, bound_max))
2598 @given(data_strategy())
2599 def test_bounds_unsatisfied(self, d):
2600 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2601 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2602 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2603 with self.assertRaises(BoundsError) as err:
2604 self.base_klass(value=value, bounds=(bound_min, bound_max))
2606 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2607 with self.assertRaises(BoundsError) as err:
2608 self.base_klass(value=value, bounds=(bound_min, bound_max))
2611 @given(data_strategy())
2612 def test_call(self, d):
2621 ) = d.draw(string_values_strategy(self.text_alphabet()))
2622 obj_initial = self.base_klass(
2628 optional_initial or False,
2639 ) = d.draw(string_values_strategy(
2640 self.text_alphabet(),
2641 do_expl=impl_initial is None,
2643 if (default is None) and (obj_initial.default is not None):
2646 (bounds is None) and
2647 (value is not None) and
2648 (bounds_initial is not None) and
2649 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2653 (bounds is None) and
2654 (default is not None) and
2655 (bounds_initial is not None) and
2656 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2659 obj = obj_initial(value, bounds, impl, expl, default, optional)
2661 value_expected = default if value is None else value
2663 default_initial if value_expected is None
2666 self.assertEqual(obj, value_expected)
2667 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2668 self.assertEqual(obj.expl_tag, expl or expl_initial)
2671 default_initial if default is None else default,
2673 if obj.default is None:
2674 optional = optional_initial if optional is None else optional
2675 optional = False if optional is None else optional
2678 self.assertEqual(obj.optional, optional)
2680 (obj._bound_min, obj._bound_max),
2681 bounds or bounds_initial or (0, float("+inf")),
2684 @given(data_strategy())
2685 def test_copy(self, d):
2686 values = d.draw(string_values_strategy(self.text_alphabet()))
2687 obj = self.base_klass(*values)
2688 obj_copied = obj.copy()
2689 self.assert_copied_basic_fields(obj, obj_copied)
2690 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2691 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2692 self.assertEqual(obj._value, obj_copied._value)
2694 @given(data_strategy())
2695 def test_stripped(self, d):
2696 value = d.draw(text(alphabet=self.text_alphabet()))
2697 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2698 obj = self.base_klass(value, impl=tag_impl)
2699 with self.assertRaises(NotEnoughData):
2700 obj.decode(obj.encode()[:-1])
2702 @given(data_strategy())
2703 def test_stripped_expl(self, d):
2704 value = d.draw(text(alphabet=self.text_alphabet()))
2705 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2706 obj = self.base_klass(value, expl=tag_expl)
2707 with self.assertRaises(NotEnoughData):
2708 obj.decode(obj.encode()[:-1])
2711 integers(min_value=31),
2712 integers(min_value=0),
2715 def test_bad_tag(self, tag, offset, decode_path):
2716 decode_path = tuple(str(i) for i in decode_path)
2717 with self.assertRaises(DecodeError) as err:
2718 self.base_klass().decode(
2719 tag_encode(tag)[:-1],
2721 decode_path=decode_path,
2724 self.assertEqual(err.exception.offset, offset)
2725 self.assertEqual(err.exception.decode_path, decode_path)
2728 integers(min_value=128),
2729 integers(min_value=0),
2732 def test_bad_len(self, l, offset, decode_path):
2733 decode_path = tuple(str(i) for i in decode_path)
2734 with self.assertRaises(DecodeError) as err:
2735 self.base_klass().decode(
2736 self.base_klass.tag_default + len_encode(l)[:-1],
2738 decode_path=decode_path,
2741 self.assertEqual(err.exception.offset, offset)
2742 self.assertEqual(err.exception.decode_path, decode_path)
2745 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2746 integers(min_value=0),
2749 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2750 decode_path = tuple(str(i) for i in decode_path)
2751 value, bound_min = list(sorted(ints))
2753 class String(self.base_klass):
2754 # Multiply this value by four, to satisfy UTF-32 bounds
2755 # (4 bytes per character) validation
2756 bounds = (bound_min * 4, bound_min * 4)
2757 with self.assertRaises(DecodeError) as err:
2759 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2761 decode_path=decode_path,
2764 self.assertEqual(err.exception.offset, offset)
2765 self.assertEqual(err.exception.decode_path, decode_path)
2767 @given(data_strategy())
2768 def test_symmetric(self, d):
2769 values = d.draw(string_values_strategy(self.text_alphabet()))
2770 value = d.draw(text(alphabet=self.text_alphabet()))
2771 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2772 offset = d.draw(integers(min_value=0))
2773 tail_junk = d.draw(binary(max_size=5))
2774 _, _, _, _, default, optional, _decoded = values
2775 obj = self.base_klass(
2783 self.assertFalse(obj.expled)
2784 obj_encoded = obj.encode()
2785 obj_expled = obj(value, expl=tag_expl)
2786 self.assertTrue(obj_expled.expled)
2789 obj_expled_encoded = obj_expled.encode()
2790 obj_decoded, tail = obj_expled.decode(
2791 obj_expled_encoded + tail_junk,
2796 self.assertEqual(tail, tail_junk)
2797 self.assertEqual(obj_decoded, obj_expled)
2798 self.assertNotEqual(obj_decoded, obj)
2799 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2800 self.assertEqual(bytes(obj_decoded), bytes(obj))
2801 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2802 self.assertEqual(text_type(obj_decoded), text_type(obj))
2803 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2804 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2805 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2807 obj_decoded.expl_llen,
2808 len(len_encode(len(obj_encoded))),
2810 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2811 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2814 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2816 self.assertEqual(obj_decoded.expl_offset, offset)
2819 class TestUTF8String(StringMixin, CommonMixin, TestCase):
2820 base_klass = UTF8String
2823 class UnicodeDecodeErrorMixin(object):
2825 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
2829 def test_unicode_decode_error(self, cyrillic_text):
2830 with self.assertRaises(DecodeError):
2831 self.base_klass(cyrillic_text)
2834 class TestNumericString(StringMixin, CommonMixin, TestCase):
2835 base_klass = NumericString
2837 def text_alphabet(self):
2840 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
2841 def test_non_numeric(self, cyrillic_text):
2842 with assertRaisesRegex(self, DecodeError, "non-numeric"):
2843 self.base_klass(cyrillic_text)
2846 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2847 integers(min_value=0),
2850 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2851 decode_path = tuple(str(i) for i in decode_path)
2852 value, bound_min = list(sorted(ints))
2854 class String(self.base_klass):
2855 bounds = (bound_min, bound_min)
2856 with self.assertRaises(DecodeError) as err:
2858 self.base_klass(b"1" * value).encode(),
2860 decode_path=decode_path,
2863 self.assertEqual(err.exception.offset, offset)
2864 self.assertEqual(err.exception.decode_path, decode_path)
2867 class TestPrintableString(
2868 UnicodeDecodeErrorMixin,
2873 base_klass = PrintableString
2876 class TestTeletexString(
2877 UnicodeDecodeErrorMixin,
2882 base_klass = TeletexString
2885 class TestVideotexString(
2886 UnicodeDecodeErrorMixin,
2891 base_klass = VideotexString
2894 class TestIA5String(
2895 UnicodeDecodeErrorMixin,
2900 base_klass = IA5String
2903 class TestGraphicString(
2904 UnicodeDecodeErrorMixin,
2909 base_klass = GraphicString
2912 class TestVisibleString(
2913 UnicodeDecodeErrorMixin,
2918 base_klass = VisibleString
2920 def test_x690_vector(self):
2922 str(VisibleString().decode(hexdec("1A054A6F6E6573"))[0]),
2926 str(VisibleString().decode(
2927 hexdec("3A0904034A6F6E04026573"),
2928 ctx={"bered": True},
2933 str(VisibleString().decode(
2934 hexdec("3A8004034A6F6E040265730000"),
2935 ctx={"bered": True},
2941 class TestGeneralString(
2942 UnicodeDecodeErrorMixin,
2947 base_klass = GeneralString
2950 class TestUniversalString(StringMixin, CommonMixin, TestCase):
2951 base_klass = UniversalString
2954 class TestBMPString(StringMixin, CommonMixin, TestCase):
2955 base_klass = BMPString
2959 def generalized_time_values_strategy(
2967 if draw(booleans()):
2968 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2970 value = value.replace(microsecond=0)
2972 if draw(booleans()):
2973 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2975 default = default.replace(microsecond=0)
2979 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2981 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2982 optional = draw(one_of(none(), booleans()))
2984 draw(integers(min_value=0)),
2985 draw(integers(min_value=0)),
2986 draw(integers(min_value=0)),
2988 return (value, impl, expl, default, optional, _decoded)
2991 class TimeMixin(object):
2992 def test_invalid_value_type(self):
2993 with self.assertRaises(InvalidValueType) as err:
2994 self.base_klass(datetime.now().timetuple())
2997 @given(data_strategy())
2998 def test_optional(self, d):
2999 default = d.draw(datetimes(
3000 min_value=self.min_datetime,
3001 max_value=self.max_datetime,
3003 optional = d.draw(booleans())
3004 obj = self.base_klass(default=default, optional=optional)
3005 self.assertTrue(obj.optional)
3007 @given(data_strategy())
3008 def test_ready(self, d):
3009 obj = self.base_klass()
3010 self.assertFalse(obj.ready)
3013 with self.assertRaises(ObjNotReady) as err:
3016 value = d.draw(datetimes(min_value=self.min_datetime))
3017 obj = self.base_klass(value)
3018 self.assertTrue(obj.ready)
3022 @given(data_strategy())
3023 def test_comparison(self, d):
3024 value1 = d.draw(datetimes(
3025 min_value=self.min_datetime,
3026 max_value=self.max_datetime,
3028 value2 = d.draw(datetimes(
3029 min_value=self.min_datetime,
3030 max_value=self.max_datetime,
3032 tag1 = d.draw(binary(min_size=1))
3033 tag2 = d.draw(binary(min_size=1))
3035 value1 = value1.replace(microsecond=0)
3036 value2 = value2.replace(microsecond=0)
3037 obj1 = self.base_klass(value1)
3038 obj2 = self.base_klass(value2)
3039 self.assertEqual(obj1 == obj2, value1 == value2)
3040 self.assertEqual(obj1 != obj2, value1 != value2)
3041 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3042 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3043 obj1 = self.base_klass(value1, impl=tag1)
3044 obj2 = self.base_klass(value1, impl=tag2)
3045 self.assertEqual(obj1 == obj2, tag1 == tag2)
3046 self.assertEqual(obj1 != obj2, tag1 != tag2)
3048 @given(data_strategy())
3049 def test_call(self, d):
3057 ) = d.draw(generalized_time_values_strategy(
3058 min_datetime=self.min_datetime,
3059 max_datetime=self.max_datetime,
3060 omit_ms=self.omit_ms,
3062 obj_initial = self.base_klass(
3063 value=value_initial,
3066 default=default_initial,
3067 optional=optional_initial or False,
3068 _decoded=_decoded_initial,
3077 ) = d.draw(generalized_time_values_strategy(
3078 min_datetime=self.min_datetime,
3079 max_datetime=self.max_datetime,
3080 omit_ms=self.omit_ms,
3081 do_expl=impl_initial is None,
3091 value_expected = default if value is None else value
3093 default_initial if value_expected is None
3096 self.assertEqual(obj, value_expected)
3097 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3098 self.assertEqual(obj.expl_tag, expl or expl_initial)
3101 default_initial if default is None else default,
3103 if obj.default is None:
3104 optional = optional_initial if optional is None else optional
3105 optional = False if optional is None else optional
3108 self.assertEqual(obj.optional, optional)
3110 @given(data_strategy())
3111 def test_copy(self, d):
3112 values = d.draw(generalized_time_values_strategy(
3113 min_datetime=self.min_datetime,
3114 max_datetime=self.max_datetime,
3116 obj = self.base_klass(*values)
3117 obj_copied = obj.copy()
3118 self.assert_copied_basic_fields(obj, obj_copied)
3119 self.assertEqual(obj._value, obj_copied._value)
3121 @given(data_strategy())
3122 def test_stripped(self, d):
3123 value = d.draw(datetimes(
3124 min_value=self.min_datetime,
3125 max_value=self.max_datetime,
3127 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3128 obj = self.base_klass(value, impl=tag_impl)
3129 with self.assertRaises(NotEnoughData):
3130 obj.decode(obj.encode()[:-1])
3132 @given(data_strategy())
3133 def test_stripped_expl(self, d):
3134 value = d.draw(datetimes(
3135 min_value=self.min_datetime,
3136 max_value=self.max_datetime,
3138 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3139 obj = self.base_klass(value, expl=tag_expl)
3140 with self.assertRaises(NotEnoughData):
3141 obj.decode(obj.encode()[:-1])
3143 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3144 @given(data_strategy())
3145 def test_symmetric(self, d):
3146 values = d.draw(generalized_time_values_strategy(
3147 min_datetime=self.min_datetime,
3148 max_datetime=self.max_datetime,
3150 value = d.draw(datetimes(
3151 min_value=self.min_datetime,
3152 max_value=self.max_datetime,
3154 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3155 offset = d.draw(integers(min_value=0))
3156 tail_junk = d.draw(binary(max_size=5))
3157 _, _, _, default, optional, _decoded = values
3158 obj = self.base_klass(
3166 self.assertFalse(obj.expled)
3167 obj_encoded = obj.encode()
3168 obj_expled = obj(value, expl=tag_expl)
3169 self.assertTrue(obj_expled.expled)
3172 obj_expled_encoded = obj_expled.encode()
3173 obj_decoded, tail = obj_expled.decode(
3174 obj_expled_encoded + tail_junk,
3179 self.assertEqual(tail, tail_junk)
3180 self.assertEqual(obj_decoded, obj_expled)
3181 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3182 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3183 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3184 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3185 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3187 obj_decoded.expl_llen,
3188 len(len_encode(len(obj_encoded))),
3190 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3191 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3194 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3196 self.assertEqual(obj_decoded.expl_offset, offset)
3199 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3200 base_klass = GeneralizedTime
3202 min_datetime = datetime(1900, 1, 1)
3203 max_datetime = datetime(9999, 12, 31)
3205 def test_go_vectors_invalid(self):
3217 b"-20100102030410Z",
3218 b"2010-0102030410Z",
3219 b"2010-0002030410Z",
3220 b"201001-02030410Z",
3221 b"20100102-030410Z",
3222 b"2010010203-0410Z",
3223 b"201001020304-10Z",
3224 # These ones are INVALID in *DER*, but accepted
3225 # by Go's encoding/asn1
3226 b"20100102030405+0607",
3227 b"20100102030405-0607",
3229 with self.assertRaises(DecodeError) as err:
3230 GeneralizedTime(data)
3233 def test_go_vectors_valid(self):
3235 GeneralizedTime(b"20100102030405Z").todatetime(),
3236 datetime(2010, 1, 2, 3, 4, 5, 0),
3240 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3241 base_klass = UTCTime
3243 min_datetime = datetime(2000, 1, 1)
3244 max_datetime = datetime(2049, 12, 31)
3246 def test_go_vectors_invalid(self):
3272 # These ones are INVALID in *DER*, but accepted
3273 # by Go's encoding/asn1
3274 b"910506164540-0700",
3275 b"910506164540+0730",
3279 with self.assertRaises(DecodeError) as err:
3283 def test_go_vectors_valid(self):
3285 UTCTime(b"910506234540Z").todatetime(),
3286 datetime(1991, 5, 6, 23, 45, 40, 0),
3289 @given(integers(min_value=0, max_value=49))
3290 def test_pre50(self, year):
3292 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3296 @given(integers(min_value=50, max_value=99))
3297 def test_post50(self, year):
3299 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3305 def any_values_strategy(draw, do_expl=False):
3306 value = draw(one_of(none(), binary()))
3309 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3310 optional = draw(one_of(none(), booleans()))
3312 draw(integers(min_value=0)),
3313 draw(integers(min_value=0)),
3314 draw(integers(min_value=0)),
3316 return (value, expl, optional, _decoded)
3319 class AnyInherited(Any):
3323 class TestAny(CommonMixin, TestCase):
3326 def test_invalid_value_type(self):
3327 with self.assertRaises(InvalidValueType) as err:
3332 def test_optional(self, optional):
3333 obj = Any(optional=optional)
3334 self.assertEqual(obj.optional, optional)
3337 def test_ready(self, value):
3339 self.assertFalse(obj.ready)
3342 with self.assertRaises(ObjNotReady) as err:
3346 self.assertTrue(obj.ready)
3351 def test_basic(self, value):
3352 integer_encoded = Integer(value).encode()
3354 Any(integer_encoded),
3355 Any(Integer(value)),
3356 Any(Any(Integer(value))),
3358 self.assertSequenceEqual(bytes(obj), integer_encoded)
3360 obj.decode(obj.encode())[0].vlen,
3361 len(integer_encoded),
3365 self.assertSequenceEqual(obj.encode(), integer_encoded)
3367 @given(binary(), binary())
3368 def test_comparison(self, value1, value2):
3369 for klass in (Any, AnyInherited):
3370 obj1 = klass(value1)
3371 obj2 = klass(value2)
3372 self.assertEqual(obj1 == obj2, value1 == value2)
3373 self.assertEqual(obj1 != obj2, value1 != value2)
3374 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3376 @given(data_strategy())
3377 def test_call(self, d):
3378 for klass in (Any, AnyInherited):
3384 ) = d.draw(any_values_strategy())
3385 obj_initial = klass(
3388 optional_initial or False,
3396 ) = d.draw(any_values_strategy(do_expl=True))
3397 obj = obj_initial(value, expl, optional)
3399 value_expected = None if value is None else value
3400 self.assertEqual(obj, value_expected)
3401 self.assertEqual(obj.expl_tag, expl or expl_initial)
3402 if obj.default is None:
3403 optional = optional_initial if optional is None else optional
3404 optional = False if optional is None else optional
3405 self.assertEqual(obj.optional, optional)
3407 def test_simultaneous_impl_expl(self):
3408 # override it, as Any does not have implicit tag
3411 def test_decoded(self):
3412 # override it, as Any does not have implicit tag
3415 @given(any_values_strategy())
3416 def test_copy(self, values):
3417 for klass in (Any, AnyInherited):
3418 obj = klass(*values)
3419 obj_copied = obj.copy()
3420 self.assert_copied_basic_fields(obj, obj_copied)
3421 self.assertEqual(obj._value, obj_copied._value)
3423 @given(binary().map(OctetString))
3424 def test_stripped(self, value):
3426 with self.assertRaises(NotEnoughData):
3427 obj.decode(obj.encode()[:-1])
3431 integers(min_value=1).map(tag_ctxc),
3433 def test_stripped_expl(self, value, tag_expl):
3434 obj = Any(value, expl=tag_expl)
3435 with self.assertRaises(NotEnoughData):
3436 obj.decode(obj.encode()[:-1])
3439 integers(min_value=31),
3440 integers(min_value=0),
3443 def test_bad_tag(self, tag, offset, decode_path):
3444 decode_path = tuple(str(i) for i in decode_path)
3445 with self.assertRaises(DecodeError) as err:
3447 tag_encode(tag)[:-1],
3449 decode_path=decode_path,
3452 self.assertEqual(err.exception.offset, offset)
3453 self.assertEqual(err.exception.decode_path, decode_path)
3456 integers(min_value=128),
3457 integers(min_value=0),
3460 def test_bad_len(self, l, offset, decode_path):
3461 decode_path = tuple(str(i) for i in decode_path)
3462 with self.assertRaises(DecodeError) as err:
3464 Any.tag_default + len_encode(l)[:-1],
3466 decode_path=decode_path,
3469 self.assertEqual(err.exception.offset, offset)
3470 self.assertEqual(err.exception.decode_path, decode_path)
3472 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3474 any_values_strategy(),
3475 integers().map(lambda x: Integer(x).encode()),
3476 integers(min_value=1).map(tag_ctxc),
3477 integers(min_value=0),
3480 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3481 for klass in (Any, AnyInherited):
3482 _, _, optional, _decoded = values
3483 obj = klass(value=value, optional=optional, _decoded=_decoded)
3486 self.assertFalse(obj.expled)
3487 obj_encoded = obj.encode()
3488 obj_expled = obj(value, expl=tag_expl)
3489 self.assertTrue(obj_expled.expled)
3492 obj_expled_encoded = obj_expled.encode()
3493 obj_decoded, tail = obj_expled.decode(
3494 obj_expled_encoded + tail_junk,
3499 self.assertEqual(tail, tail_junk)
3500 self.assertEqual(obj_decoded, obj_expled)
3501 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3502 self.assertEqual(bytes(obj_decoded), bytes(obj))
3503 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3504 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3505 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3507 obj_decoded.expl_llen,
3508 len(len_encode(len(obj_encoded))),
3510 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3511 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3514 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3516 self.assertEqual(obj_decoded.expl_offset, offset)
3517 self.assertEqual(obj_decoded.tlen, 0)
3518 self.assertEqual(obj_decoded.llen, 0)
3519 self.assertEqual(obj_decoded.vlen, len(value))
3523 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3525 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3526 tags = [tag_encode(tag) for tag in draw(sets(
3527 integers(min_value=0),
3528 min_size=len(names),
3529 max_size=len(names),
3531 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3533 if value_required or draw(booleans()):
3534 value = draw(tuples(
3535 sampled_from([name for name, _ in schema]),
3536 integers().map(Integer),
3540 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3541 default = draw(one_of(
3543 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3545 optional = draw(one_of(none(), booleans()))
3547 draw(integers(min_value=0)),
3548 draw(integers(min_value=0)),
3549 draw(integers(min_value=0)),
3551 return (schema, value, expl, default, optional, _decoded)
3554 class ChoiceInherited(Choice):
3558 class TestChoice(CommonMixin, TestCase):
3560 schema = (("whatever", Boolean()),)
3563 def test_schema_required(self):
3564 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3567 def test_impl_forbidden(self):
3568 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3569 Choice(impl=b"whatever")
3571 def test_invalid_value_type(self):
3572 with self.assertRaises(InvalidValueType) as err:
3573 self.base_klass(123)
3575 with self.assertRaises(ObjUnknown) as err:
3576 self.base_klass(("whenever", Boolean(False)))
3578 with self.assertRaises(InvalidValueType) as err:
3579 self.base_klass(("whatever", Integer(123)))
3583 def test_optional(self, optional):
3584 obj = self.base_klass(
3585 default=self.base_klass(("whatever", Boolean(False))),
3588 self.assertTrue(obj.optional)
3591 def test_ready(self, value):
3592 obj = self.base_klass()
3593 self.assertFalse(obj.ready)
3596 self.assertIsNone(obj["whatever"])
3597 with self.assertRaises(ObjNotReady) as err:
3600 obj["whatever"] = Boolean()
3601 self.assertFalse(obj.ready)
3604 obj["whatever"] = Boolean(value)
3605 self.assertTrue(obj.ready)
3609 @given(booleans(), booleans())
3610 def test_comparison(self, value1, value2):
3611 class WahlInherited(self.base_klass):
3613 for klass in (self.base_klass, WahlInherited):
3614 obj1 = klass(("whatever", Boolean(value1)))
3615 obj2 = klass(("whatever", Boolean(value2)))
3616 self.assertEqual(obj1 == obj2, value1 == value2)
3617 self.assertEqual(obj1 != obj2, value1 != value2)
3618 self.assertEqual(obj1 == obj2._value, value1 == value2)
3619 self.assertFalse(obj1 == obj2._value[1])
3621 @given(data_strategy())
3622 def test_call(self, d):
3623 for klass in (Choice, ChoiceInherited):
3631 ) = d.draw(choice_values_strategy())
3634 schema = schema_initial
3636 value=value_initial,
3638 default=default_initial,
3639 optional=optional_initial or False,
3640 _decoded=_decoded_initial,
3649 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
3650 obj = obj_initial(value, expl, default, optional)
3652 value_expected = default if value is None else value
3654 default_initial if value_expected is None
3657 self.assertEqual(obj.choice, value_expected[0])
3658 self.assertEqual(obj.value, int(value_expected[1]))
3659 self.assertEqual(obj.expl_tag, expl or expl_initial)
3660 default_expect = default_initial if default is None else default
3661 if default_expect is not None:
3662 self.assertEqual(obj.default.choice, default_expect[0])
3663 self.assertEqual(obj.default.value, int(default_expect[1]))
3664 if obj.default is None:
3665 optional = optional_initial if optional is None else optional
3666 optional = False if optional is None else optional
3669 self.assertEqual(obj.optional, optional)
3670 self.assertEqual(obj.specs, obj_initial.specs)
3672 def test_simultaneous_impl_expl(self):
3673 # override it, as Any does not have implicit tag
3676 def test_decoded(self):
3677 # override it, as Any does not have implicit tag
3680 @given(choice_values_strategy())
3681 def test_copy(self, values):
3682 _schema, value, expl, default, optional, _decoded = values
3684 class Wahl(self.base_klass):
3690 optional=optional or False,
3693 obj_copied = obj.copy()
3694 self.assertIsNone(obj.tag)
3695 self.assertIsNone(obj_copied.tag)
3696 # hack for assert_copied_basic_fields
3697 obj.tag = "whatever"
3698 obj_copied.tag = "whatever"
3699 self.assert_copied_basic_fields(obj, obj_copied)
3700 self.assertEqual(obj._value, obj_copied._value)
3701 self.assertEqual(obj.specs, obj_copied.specs)
3704 def test_stripped(self, value):
3705 obj = self.base_klass(("whatever", Boolean(value)))
3706 with self.assertRaises(NotEnoughData):
3707 obj.decode(obj.encode()[:-1])
3711 integers(min_value=1).map(tag_ctxc),
3713 def test_stripped_expl(self, value, tag_expl):
3714 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3715 with self.assertRaises(NotEnoughData):
3716 obj.decode(obj.encode()[:-1])
3718 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3719 @given(data_strategy())
3720 def test_symmetric(self, d):
3721 _schema, value, _, default, optional, _decoded = d.draw(
3722 choice_values_strategy(value_required=True)
3724 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3725 offset = d.draw(integers(min_value=0))
3726 tail_junk = d.draw(binary(max_size=5))
3728 class Wahl(self.base_klass):
3738 self.assertFalse(obj.expled)
3739 obj_encoded = obj.encode()
3740 obj_expled = obj(value, expl=tag_expl)
3741 self.assertTrue(obj_expled.expled)
3744 obj_expled_encoded = obj_expled.encode()
3745 obj_decoded, tail = obj_expled.decode(
3746 obj_expled_encoded + tail_junk,
3751 self.assertEqual(tail, tail_junk)
3752 self.assertEqual(obj_decoded, obj_expled)
3753 self.assertEqual(obj_decoded.choice, obj_expled.choice)
3754 self.assertEqual(obj_decoded.value, obj_expled.value)
3755 self.assertEqual(obj_decoded.choice, obj.choice)
3756 self.assertEqual(obj_decoded.value, obj.value)
3757 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3758 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3759 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3761 obj_decoded.expl_llen,
3762 len(len_encode(len(obj_encoded))),
3764 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3765 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3768 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3770 self.assertEqual(obj_decoded.expl_offset, offset)
3771 self.assertSequenceEqual(
3773 obj_decoded.value.offset - offset:
3774 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
3780 def test_set_get(self, value):
3783 ("erste", Boolean()),
3784 ("zweite", Integer()),
3787 with self.assertRaises(ObjUnknown) as err:
3788 obj["whatever"] = "whenever"
3789 with self.assertRaises(InvalidValueType) as err:
3790 obj["zweite"] = Boolean(False)
3791 obj["zweite"] = Integer(value)
3793 with self.assertRaises(ObjUnknown) as err:
3796 self.assertIsNone(obj["erste"])
3797 self.assertEqual(obj["zweite"], Integer(value))
3799 def test_tag_mismatch(self):
3802 ("erste", Boolean()),
3804 int_encoded = Integer(123).encode()
3805 bool_encoded = Boolean(False).encode()
3807 obj.decode(bool_encoded)
3808 with self.assertRaises(TagMismatch):
3809 obj.decode(int_encoded)
3811 def test_tag_mismatch_underlying(self):
3812 class SeqOfBoolean(SequenceOf):
3815 class SeqOfInteger(SequenceOf):
3820 ("erste", SeqOfBoolean()),
3823 int_encoded = SeqOfInteger((Integer(123),)).encode()
3824 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
3826 obj.decode(bool_encoded)
3827 with self.assertRaises(TagMismatch) as err:
3828 obj.decode(int_encoded)
3829 self.assertEqual(err.exception.decode_path, ("erste", "0"))
3833 def seq_values_strategy(draw, seq_klass, do_expl=False):
3835 if draw(booleans()):
3838 k: v for k, v in draw(dictionaries(
3841 booleans().map(Boolean),
3842 integers().map(Integer),
3847 if draw(booleans()):
3848 schema = list(draw(dictionaries(
3851 booleans().map(Boolean),
3852 integers().map(Integer),
3858 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3860 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3862 if draw(booleans()):
3863 default = seq_klass()
3865 k: v for k, v in draw(dictionaries(
3868 booleans().map(Boolean),
3869 integers().map(Integer),
3873 optional = draw(one_of(none(), booleans()))
3875 draw(integers(min_value=0)),
3876 draw(integers(min_value=0)),
3877 draw(integers(min_value=0)),
3879 return (value, schema, impl, expl, default, optional, _decoded)
3883 def sequence_strategy(draw, seq_klass):
3884 inputs = draw(lists(
3886 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
3887 tuples(just(Integer), integers(), one_of(none(), integers())),
3892 integers(min_value=1),
3893 min_size=len(inputs),
3894 max_size=len(inputs),
3897 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3898 for tag, expled in zip(tags, draw(lists(
3900 min_size=len(inputs),
3901 max_size=len(inputs),
3905 for i, optional in enumerate(draw(lists(
3906 sampled_from(("required", "optional", "empty")),
3907 min_size=len(inputs),
3908 max_size=len(inputs),
3910 if optional in ("optional", "empty"):
3911 inits[i]["optional"] = True
3912 if optional == "empty":
3914 empties = set(empties)
3915 names = list(draw(sets(
3917 min_size=len(inputs),
3918 max_size=len(inputs),
3921 for i, (klass, value, default) in enumerate(inputs):
3922 schema.append((names[i], klass(default=default, **inits[i])))
3923 seq_name = draw(text_letters())
3924 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3927 for i, (klass, value, default) in enumerate(inputs):
3934 "default_value": None if spec.default is None else default,
3938 expect["optional"] = True
3940 expect["presented"] = True
3941 expect["value"] = value
3943 expect["optional"] = True
3944 if default is not None and default == value:
3945 expect["presented"] = False
3946 seq[name] = klass(value)
3947 expects.append(expect)
3952 def sequences_strategy(draw, seq_klass):
3953 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
3955 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
3956 for tag, expled in zip(tags, draw(lists(
3963 i for i, is_default in enumerate(draw(lists(
3969 names = list(draw(sets(
3974 seq_expectses = draw(lists(
3975 sequence_strategy(seq_klass=seq_klass),
3979 seqs = [seq for seq, _ in seq_expectses]
3981 for i, (name, seq) in enumerate(zip(names, seqs)):
3984 seq(default=(seq if i in defaulted else None), **inits[i]),
3986 seq_name = draw(text_letters())
3987 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
3990 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
3993 "expects": expects_inner,
3996 seq_outer[name] = seq_inner
3997 if seq_outer.specs[name].default is None:
3998 expect["presented"] = True
3999 expect_outers.append(expect)
4000 return seq_outer, expect_outers
4003 class SeqMixing(object):
4004 def test_invalid_value_type(self):
4005 with self.assertRaises(InvalidValueType) as err:
4006 self.base_klass(123)
4009 def test_invalid_value_type_set(self):
4010 class Seq(self.base_klass):
4011 schema = (("whatever", Boolean()),)
4013 with self.assertRaises(InvalidValueType) as err:
4014 seq["whatever"] = Integer(123)
4018 def test_optional(self, optional):
4019 obj = self.base_klass(default=self.base_klass(), optional=optional)
4020 self.assertTrue(obj.optional)
4022 @given(data_strategy())
4023 def test_ready(self, d):
4025 str(i): v for i, v in enumerate(d.draw(lists(
4032 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4039 for name in d.draw(permutations(
4040 list(ready.keys()) + list(non_ready.keys()),
4042 schema_input.append((name, Boolean()))
4044 class Seq(self.base_klass):
4045 schema = tuple(schema_input)
4047 for name in ready.keys():
4049 seq[name] = Boolean()
4050 self.assertFalse(seq.ready)
4053 for name, value in ready.items():
4054 seq[name] = Boolean(value)
4055 self.assertFalse(seq.ready)
4058 with self.assertRaises(ObjNotReady) as err:
4061 for name, value in non_ready.items():
4062 seq[name] = Boolean(value)
4063 self.assertTrue(seq.ready)
4067 @given(data_strategy())
4068 def test_call(self, d):
4069 class SeqInherited(self.base_klass):
4071 for klass in (self.base_klass, SeqInherited):
4080 ) = d.draw(seq_values_strategy(seq_klass=klass))
4081 obj_initial = klass(
4087 optional_initial or False,
4098 ) = d.draw(seq_values_strategy(
4100 do_expl=impl_initial is None,
4102 obj = obj_initial(value, impl, expl, default, optional)
4103 value_expected = default if value is None else value
4105 default_initial if value_expected is None
4108 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4109 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4110 self.assertEqual(obj.expl_tag, expl or expl_initial)
4112 {} if obj.default is None else obj.default._value,
4113 getattr(default_initial if default is None else default, "_value", {}),
4115 if obj.default is None:
4116 optional = optional_initial if optional is None else optional
4117 optional = False if optional is None else optional
4120 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4121 self.assertEqual(obj.optional, optional)
4123 @given(data_strategy())
4124 def test_copy(self, d):
4125 class SeqInherited(self.base_klass):
4127 for klass in (self.base_klass, SeqInherited):
4128 values = d.draw(seq_values_strategy(seq_klass=klass))
4129 obj = klass(*values)
4130 obj_copied = obj.copy()
4131 self.assert_copied_basic_fields(obj, obj_copied)
4132 self.assertEqual(obj.specs, obj_copied.specs)
4133 self.assertEqual(obj._value, obj_copied._value)
4135 @given(data_strategy())
4136 def test_stripped(self, d):
4137 value = d.draw(integers())
4138 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4140 class Seq(self.base_klass):
4142 schema = (("whatever", Integer()),)
4144 seq["whatever"] = Integer(value)
4145 with self.assertRaises(NotEnoughData):
4146 seq.decode(seq.encode()[:-1])
4148 @given(data_strategy())
4149 def test_stripped_expl(self, d):
4150 value = d.draw(integers())
4151 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4153 class Seq(self.base_klass):
4155 schema = (("whatever", Integer()),)
4157 seq["whatever"] = Integer(value)
4158 with self.assertRaises(NotEnoughData):
4159 seq.decode(seq.encode()[:-1])
4161 @given(binary(min_size=2))
4162 def test_non_tag_mismatch_raised(self, junk):
4164 _, _, len_encoded = tag_strip(memoryview(junk))
4165 len_decode(len_encoded)
4171 class Seq(self.base_klass):
4173 ("whatever", Integer()),
4175 ("whenever", Integer()),
4178 seq["whatever"] = Integer(123)
4179 seq["junk"] = Any(junk)
4180 seq["whenever"] = Integer(123)
4181 with self.assertRaises(DecodeError):
4182 seq.decode(seq.encode())
4185 integers(min_value=31),
4186 integers(min_value=0),
4189 def test_bad_tag(self, tag, offset, decode_path):
4190 decode_path = tuple(str(i) for i in decode_path)
4191 with self.assertRaises(DecodeError) as err:
4192 self.base_klass().decode(
4193 tag_encode(tag)[:-1],
4195 decode_path=decode_path,
4198 self.assertEqual(err.exception.offset, offset)
4199 self.assertEqual(err.exception.decode_path, decode_path)
4202 integers(min_value=128),
4203 integers(min_value=0),
4206 def test_bad_len(self, l, offset, decode_path):
4207 decode_path = tuple(str(i) for i in decode_path)
4208 with self.assertRaises(DecodeError) as err:
4209 self.base_klass().decode(
4210 self.base_klass.tag_default + len_encode(l)[:-1],
4212 decode_path=decode_path,
4215 self.assertEqual(err.exception.offset, offset)
4216 self.assertEqual(err.exception.decode_path, decode_path)
4218 def _assert_expects(self, seq, expects):
4219 for expect in expects:
4221 seq.specs[expect["name"]].optional,
4224 if expect["default_value"] is not None:
4226 seq.specs[expect["name"]].default,
4227 expect["default_value"],
4229 if expect["presented"]:
4230 self.assertIn(expect["name"], seq)
4231 self.assertEqual(seq[expect["name"]], expect["value"])
4233 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4234 @given(data_strategy())
4235 def test_symmetric(self, d):
4236 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4237 tail_junk = d.draw(binary(max_size=5))
4238 self.assertTrue(seq.ready)
4239 self.assertFalse(seq.decoded)
4240 self._assert_expects(seq, expects)
4243 seq_encoded = seq.encode()
4244 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4245 self.assertEqual(tail, tail_junk)
4246 self.assertTrue(seq.ready)
4247 self._assert_expects(seq_decoded, expects)
4248 self.assertEqual(seq, seq_decoded)
4249 self.assertEqual(seq_decoded.encode(), seq_encoded)
4250 for expect in expects:
4251 if not expect["presented"]:
4252 self.assertNotIn(expect["name"], seq_decoded)
4254 self.assertIn(expect["name"], seq_decoded)
4255 obj = seq_decoded[expect["name"]]
4256 self.assertTrue(obj.decoded)
4257 offset = obj.expl_offset if obj.expled else obj.offset
4258 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4259 self.assertSequenceEqual(
4260 seq_encoded[offset:offset + tlvlen],
4264 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4265 @given(data_strategy())
4266 def test_symmetric_with_seq(self, d):
4267 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4268 self.assertTrue(seq.ready)
4269 seq_encoded = seq.encode()
4270 seq_decoded, tail = seq.decode(seq_encoded)
4271 self.assertEqual(tail, b"")
4272 self.assertTrue(seq.ready)
4273 self.assertEqual(seq, seq_decoded)
4274 self.assertEqual(seq_decoded.encode(), seq_encoded)
4275 for expect_outer in expect_outers:
4276 if not expect_outer["presented"]:
4277 self.assertNotIn(expect_outer["name"], seq_decoded)
4279 self.assertIn(expect_outer["name"], seq_decoded)
4280 obj = seq_decoded[expect_outer["name"]]
4281 self.assertTrue(obj.decoded)
4282 offset = obj.expl_offset if obj.expled else obj.offset
4283 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4284 self.assertSequenceEqual(
4285 seq_encoded[offset:offset + tlvlen],
4288 self._assert_expects(obj, expect_outer["expects"])
4290 @given(data_strategy())
4291 def test_default_disappears(self, d):
4292 _schema = list(d.draw(dictionaries(
4294 sets(integers(), min_size=2, max_size=2),
4298 class Seq(self.base_klass):
4300 (n, Integer(default=d))
4301 for n, (_, d) in _schema
4304 for name, (value, _) in _schema:
4305 seq[name] = Integer(value)
4306 self.assertEqual(len(seq._value), len(_schema))
4307 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4308 self.assertGreater(len(seq.encode()), len(empty_seq))
4309 for name, (_, default) in _schema:
4310 seq[name] = Integer(default)
4311 self.assertEqual(len(seq._value), 0)
4312 self.assertSequenceEqual(seq.encode(), empty_seq)
4314 @given(data_strategy())
4315 def test_encoded_default_accepted(self, d):
4316 _schema = list(d.draw(dictionaries(
4321 tags = [tag_encode(tag) for tag in d.draw(sets(
4322 integers(min_value=0),
4323 min_size=len(_schema),
4324 max_size=len(_schema),
4327 class SeqWithoutDefault(self.base_klass):
4329 (n, Integer(impl=t))
4330 for (n, _), t in zip(_schema, tags)
4332 seq_without_default = SeqWithoutDefault()
4333 for name, value in _schema:
4334 seq_without_default[name] = Integer(value)
4335 seq_encoded = seq_without_default.encode()
4337 class SeqWithDefault(self.base_klass):
4339 (n, Integer(default=v, impl=t))
4340 for (n, v), t in zip(_schema, tags)
4342 seq_with_default = SeqWithDefault()
4343 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4344 for name, value in _schema:
4345 self.assertEqual(seq_decoded[name], seq_with_default[name])
4346 self.assertEqual(seq_decoded[name], value)
4348 @given(data_strategy())
4349 def test_missing_from_spec(self, d):
4350 names = list(d.draw(sets(text_letters(), min_size=2)))
4351 tags = [tag_encode(tag) for tag in d.draw(sets(
4352 integers(min_value=0),
4353 min_size=len(names),
4354 max_size=len(names),
4356 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4358 class SeqFull(self.base_klass):
4359 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4360 seq_full = SeqFull()
4361 for i, name in enumerate(names):
4362 seq_full[name] = Integer(i)
4363 seq_encoded = seq_full.encode()
4364 altered = names_tags[:-2] + names_tags[-1:]
4366 class SeqMissing(self.base_klass):
4367 schema = [(n, Integer(impl=t)) for n, t in altered]
4368 seq_missing = SeqMissing()
4369 with self.assertRaises(TagMismatch):
4370 seq_missing.decode(seq_encoded)
4373 class TestSequence(SeqMixing, CommonMixin, TestCase):
4374 base_klass = Sequence
4380 def test_remaining(self, value, junk):
4381 class Seq(Sequence):
4383 ("whatever", Integer()),
4385 int_encoded = Integer(value).encode()
4387 Sequence.tag_default,
4388 len_encode(len(int_encoded + junk)),
4391 with assertRaisesRegex(self, DecodeError, "remaining"):
4392 Seq().decode(junked)
4394 @given(sets(text_letters(), min_size=2))
4395 def test_obj_unknown(self, names):
4396 missing = names.pop()
4398 class Seq(Sequence):
4399 schema = [(n, Boolean()) for n in names]
4401 with self.assertRaises(ObjUnknown) as err:
4404 with self.assertRaises(ObjUnknown) as err:
4405 seq[missing] = Boolean()
4408 def test_x690_vector(self):
4409 class Seq(Sequence):
4411 ("name", IA5String()),
4414 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4415 self.assertEqual(seq["name"], "Smith")
4416 self.assertEqual(seq["ok"], True)
4419 class TestSet(SeqMixing, CommonMixin, TestCase):
4422 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4423 @given(data_strategy())
4424 def test_sorted(self, d):
4426 tag_encode(tag) for tag in
4427 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4431 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4433 for name, _ in Seq.schema:
4434 seq[name] = OctetString(b"")
4435 seq_encoded = seq.encode()
4436 seq_decoded, _ = seq.decode(seq_encoded)
4437 self.assertSequenceEqual(
4438 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4439 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4444 def seqof_values_strategy(draw, schema=None, do_expl=False):
4446 schema = draw(sampled_from((Boolean(), Integer())))
4447 bound_min, bound_max = sorted(draw(sets(
4448 integers(min_value=0, max_value=10),
4452 if isinstance(schema, Boolean):
4453 values_generator = booleans().map(Boolean)
4454 elif isinstance(schema, Integer):
4455 values_generator = integers().map(Integer)
4456 values_generator = lists(
4461 values = draw(one_of(none(), values_generator))
4465 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4467 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4468 default = draw(one_of(none(), values_generator))
4469 optional = draw(one_of(none(), booleans()))
4471 draw(integers(min_value=0)),
4472 draw(integers(min_value=0)),
4473 draw(integers(min_value=0)),
4478 (bound_min, bound_max),
4487 class SeqOfMixing(object):
4488 def test_invalid_value_type(self):
4489 with self.assertRaises(InvalidValueType) as err:
4490 self.base_klass(123)
4493 def test_invalid_values_type(self):
4494 class SeqOf(self.base_klass):
4496 with self.assertRaises(InvalidValueType) as err:
4497 SeqOf([Integer(123), Boolean(False), Integer(234)])
4500 def test_schema_required(self):
4501 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4502 self.base_klass.__mro__[1]()
4504 @given(booleans(), booleans(), binary(), binary())
4505 def test_comparison(self, value1, value2, tag1, tag2):
4506 class SeqOf(self.base_klass):
4508 obj1 = SeqOf([Boolean(value1)])
4509 obj2 = SeqOf([Boolean(value2)])
4510 self.assertEqual(obj1 == obj2, value1 == value2)
4511 self.assertEqual(obj1 != obj2, value1 != value2)
4512 self.assertEqual(obj1 == list(obj2), value1 == value2)
4513 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4514 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4515 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4516 self.assertEqual(obj1 == obj2, tag1 == tag2)
4517 self.assertEqual(obj1 != obj2, tag1 != tag2)
4519 @given(lists(booleans()))
4520 def test_iter(self, values):
4521 class SeqOf(self.base_klass):
4523 obj = SeqOf([Boolean(value) for value in values])
4524 self.assertEqual(len(obj), len(values))
4525 for i, value in enumerate(obj):
4526 self.assertEqual(value, values[i])
4528 @given(data_strategy())
4529 def test_ready(self, d):
4530 ready = [Integer(v) for v in d.draw(lists(
4537 range(d.draw(integers(min_value=1, max_value=5)))
4540 class SeqOf(self.base_klass):
4542 values = d.draw(permutations(ready + non_ready))
4544 for value in values:
4546 self.assertFalse(seqof.ready)
4549 with self.assertRaises(ObjNotReady) as err:
4552 for i, value in enumerate(values):
4553 self.assertEqual(seqof[i], value)
4554 if not seqof[i].ready:
4555 seqof[i] = Integer(i)
4556 self.assertTrue(seqof.ready)
4560 def test_spec_mismatch(self):
4561 class SeqOf(self.base_klass):
4564 seqof.append(Integer(123))
4565 with self.assertRaises(ValueError):
4566 seqof.append(Boolean(False))
4567 with self.assertRaises(ValueError):
4568 seqof[0] = Boolean(False)
4570 @given(data_strategy())
4571 def test_bounds_satisfied(self, d):
4572 class SeqOf(self.base_klass):
4574 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
4575 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4576 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
4577 SeqOf(value=value, bounds=(bound_min, bound_max))
4579 @given(data_strategy())
4580 def test_bounds_unsatisfied(self, d):
4581 class SeqOf(self.base_klass):
4583 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
4584 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
4585 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
4586 with self.assertRaises(BoundsError) as err:
4587 SeqOf(value=value, bounds=(bound_min, bound_max))
4589 value = [Boolean()] * d.draw(integers(
4590 min_value=bound_max + 1,
4591 max_value=bound_max + 10,
4593 with self.assertRaises(BoundsError) as err:
4594 SeqOf(value=value, bounds=(bound_min, bound_max))
4597 @given(integers(min_value=1, max_value=10))
4598 def test_out_of_bounds(self, bound_max):
4599 class SeqOf(self.base_klass):
4601 bounds = (0, bound_max)
4603 for _ in range(bound_max):
4604 seqof.append(Integer(123))
4605 with self.assertRaises(BoundsError):
4606 seqof.append(Integer(123))
4608 @given(data_strategy())
4609 def test_call(self, d):
4619 ) = d.draw(seqof_values_strategy())
4621 class SeqOf(self.base_klass):
4622 schema = schema_initial
4623 obj_initial = SeqOf(
4624 value=value_initial,
4625 bounds=bounds_initial,
4628 default=default_initial,
4629 optional=optional_initial or False,
4630 _decoded=_decoded_initial,
4641 ) = d.draw(seqof_values_strategy(
4642 schema=schema_initial,
4643 do_expl=impl_initial is None,
4645 if (default is None) and (obj_initial.default is not None):
4648 (bounds is None) and
4649 (value is not None) and
4650 (bounds_initial is not None) and
4651 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
4655 (bounds is None) and
4656 (default is not None) and
4657 (bounds_initial is not None) and
4658 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
4670 value_expected = default if value is None else value
4672 default_initial if value_expected is None
4675 value_expected = () if value_expected is None else value_expected
4676 self.assertEqual(obj, value_expected)
4677 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4678 self.assertEqual(obj.expl_tag, expl or expl_initial)
4681 default_initial if default is None else default,
4683 if obj.default is None:
4684 optional = optional_initial if optional is None else optional
4685 optional = False if optional is None else optional
4688 self.assertEqual(obj.optional, optional)
4690 (obj._bound_min, obj._bound_max),
4691 bounds or bounds_initial or (0, float("+inf")),
4694 @given(seqof_values_strategy())
4695 def test_copy(self, values):
4696 _schema, value, bounds, impl, expl, default, optional, _decoded = values
4698 class SeqOf(self.base_klass):
4706 optional=optional or False,
4709 obj_copied = obj.copy()
4710 self.assert_copied_basic_fields(obj, obj_copied)
4711 self.assertEqual(obj._bound_min, obj_copied._bound_min)
4712 self.assertEqual(obj._bound_max, obj_copied._bound_max)
4713 self.assertEqual(obj._value, obj_copied._value)
4717 integers(min_value=1).map(tag_encode),
4719 def test_stripped(self, values, tag_impl):
4720 class SeqOf(self.base_klass):
4721 schema = OctetString()
4722 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
4723 with self.assertRaises(NotEnoughData):
4724 obj.decode(obj.encode()[:-1])
4728 integers(min_value=1).map(tag_ctxc),
4730 def test_stripped_expl(self, values, tag_expl):
4731 class SeqOf(self.base_klass):
4732 schema = OctetString()
4733 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
4734 with self.assertRaises(NotEnoughData):
4735 obj.decode(obj.encode()[:-1])
4738 integers(min_value=31),
4739 integers(min_value=0),
4742 def test_bad_tag(self, tag, offset, decode_path):
4743 decode_path = tuple(str(i) for i in decode_path)
4744 with self.assertRaises(DecodeError) as err:
4745 self.base_klass().decode(
4746 tag_encode(tag)[:-1],
4748 decode_path=decode_path,
4751 self.assertEqual(err.exception.offset, offset)
4752 self.assertEqual(err.exception.decode_path, decode_path)
4755 integers(min_value=128),
4756 integers(min_value=0),
4759 def test_bad_len(self, l, offset, decode_path):
4760 decode_path = tuple(str(i) for i in decode_path)
4761 with self.assertRaises(DecodeError) as err:
4762 self.base_klass().decode(
4763 self.base_klass.tag_default + len_encode(l)[:-1],
4765 decode_path=decode_path,
4768 self.assertEqual(err.exception.offset, offset)
4769 self.assertEqual(err.exception.decode_path, decode_path)
4771 @given(binary(min_size=1))
4772 def test_tag_mismatch(self, impl):
4773 assume(impl != self.base_klass.tag_default)
4774 with self.assertRaises(TagMismatch):
4775 self.base_klass(impl=impl).decode(self.base_klass().encode())
4777 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4779 seqof_values_strategy(schema=Integer()),
4780 lists(integers().map(Integer)),
4781 integers(min_value=1).map(tag_ctxc),
4782 integers(min_value=0),
4785 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4786 _, _, _, _, _, default, optional, _decoded = values
4788 class SeqOf(self.base_klass):
4798 self.assertFalse(obj.expled)
4799 obj_encoded = obj.encode()
4800 obj_expled = obj(value, expl=tag_expl)
4801 self.assertTrue(obj_expled.expled)
4804 obj_expled_encoded = obj_expled.encode()
4805 obj_decoded, tail = obj_expled.decode(
4806 obj_expled_encoded + tail_junk,
4811 self.assertEqual(tail, tail_junk)
4812 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
4813 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4814 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4815 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4817 obj_decoded.expl_llen,
4818 len(len_encode(len(obj_encoded))),
4820 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4821 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4824 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4826 self.assertEqual(obj_decoded.expl_offset, offset)
4827 for obj_inner in obj_decoded:
4828 self.assertIn(obj_inner, obj_decoded)
4829 self.assertSequenceEqual(
4832 obj_inner.offset - offset:
4833 obj_inner.offset + obj_inner.tlvlen - offset
4838 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
4839 class SeqOf(SequenceOf):
4843 def _test_symmetric_compare_objs(self, obj1, obj2):
4844 self.assertEqual(obj1, obj2)
4845 self.assertSequenceEqual(list(obj1), list(obj2))
4848 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
4853 def _test_symmetric_compare_objs(self, obj1, obj2):
4854 self.assertSetEqual(
4855 set(int(v) for v in obj1),
4856 set(int(v) for v in obj2),
4859 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4860 @given(data_strategy())
4861 def test_sorted(self, d):
4862 values = [OctetString(v) for v in d.draw(lists(binary()))]
4865 schema = OctetString()
4867 seq_encoded = seq.encode()
4868 seq_decoded, _ = seq.decode(seq_encoded)
4869 self.assertSequenceEqual(
4870 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4871 b"".join(sorted([v.encode() for v in values])),
4875 class TestGoMarshalVectors(TestCase):
4877 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
4878 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
4879 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
4880 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
4881 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
4883 class Seq(Sequence):
4885 ("erste", Integer()),
4886 ("zweite", Integer(optional=True))
4889 seq["erste"] = Integer(64)
4890 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
4891 seq["erste"] = Integer(0x123456)
4892 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
4893 seq["erste"] = Integer(64)
4894 seq["zweite"] = Integer(65)
4895 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
4897 class NestedSeq(Sequence):
4901 seq["erste"] = Integer(127)
4902 seq["zweite"] = None
4903 nested = NestedSeq()
4904 nested["nest"] = seq
4905 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
4907 self.assertSequenceEqual(
4908 OctetString(b"\x01\x02\x03").encode(),
4909 hexdec("0403010203"),
4912 class Seq(Sequence):
4914 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
4917 seq["erste"] = Integer(64)
4918 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
4920 class Seq(Sequence):
4922 ("erste", Integer(expl=tag_ctxc(5))),
4925 seq["erste"] = Integer(64)
4926 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
4928 class Seq(Sequence):
4931 impl=tag_encode(0, klass=TagClassContext),
4936 seq["erste"] = Null()
4937 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
4939 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
4941 self.assertSequenceEqual(
4942 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
4943 hexdec("170d3730303130313030303030305a"),
4945 self.assertSequenceEqual(
4946 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
4947 hexdec("170d3039313131353232353631365a"),
4949 self.assertSequenceEqual(
4950 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
4951 hexdec("180f32313030303430353132303130315a"),
4954 class Seq(Sequence):
4956 ("erste", GeneralizedTime()),
4959 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
4960 self.assertSequenceEqual(
4962 hexdec("3011180f32303039313131353232353631365a"),
4965 self.assertSequenceEqual(
4966 BitString((1, b"\x80")).encode(),
4969 self.assertSequenceEqual(
4970 BitString((12, b"\x81\xF0")).encode(),
4971 hexdec("03030481f0"),
4974 self.assertSequenceEqual(
4975 ObjectIdentifier("1.2.3.4").encode(),
4976 hexdec("06032a0304"),
4978 self.assertSequenceEqual(
4979 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
4980 hexdec("06092a864888932d010105"),
4982 self.assertSequenceEqual(
4983 ObjectIdentifier("2.100.3").encode(),
4984 hexdec("0603813403"),
4987 self.assertSequenceEqual(
4988 PrintableString("test").encode(),
4989 hexdec("130474657374"),
4991 self.assertSequenceEqual(
4992 PrintableString("x" * 127).encode(),
4993 hexdec("137F" + "78" * 127),
4995 self.assertSequenceEqual(
4996 PrintableString("x" * 128).encode(),
4997 hexdec("138180" + "78" * 128),
4999 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5001 class Seq(Sequence):
5003 ("erste", IA5String()),
5006 seq["erste"] = IA5String("test")
5007 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5009 class Seq(Sequence):
5011 ("erste", PrintableString()),
5014 seq["erste"] = PrintableString("test")
5015 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5016 seq["erste"] = PrintableString("test*")
5017 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5019 class Seq(Sequence):
5021 ("erste", Any(optional=True)),
5022 ("zweite", Integer()),
5025 seq["zweite"] = Integer(64)
5026 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5031 seq.append(Integer(10))
5032 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5034 class _SeqOf(SequenceOf):
5035 schema = PrintableString()
5037 class SeqOf(SequenceOf):
5040 _seqof.append(PrintableString("1"))
5042 seqof.append(_seqof)
5043 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5045 class Seq(Sequence):
5047 ("erste", Integer(default=1)),
5050 seq["erste"] = Integer(0)
5051 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5052 seq["erste"] = Integer(1)
5053 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5054 seq["erste"] = Integer(2)
5055 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5058 class TestPP(TestCase):
5059 @given(data_strategy())
5060 def test_oid_printing(self, d):
5062 str(ObjectIdentifier(k)): v * 2
5063 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5065 chosen = d.draw(sampled_from(sorted(oids)))
5066 chosen_id = oids[chosen]
5067 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5068 self.assertNotIn(chosen_id, pp_console_row(pp))
5069 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5072 class TestAutoAddSlots(TestCase):
5074 class Inher(Integer):
5077 with self.assertRaises(AttributeError):
5079 inher.unexistent = "whatever"
5082 class TestOIDDefines(TestCase):
5083 @given(data_strategy())
5084 def runTest(self, d):
5085 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5086 value_name_chosen = d.draw(sampled_from(value_names))
5088 ObjectIdentifier(oid)
5089 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5091 oid_chosen = d.draw(sampled_from(oids))
5092 values = d.draw(lists(
5094 min_size=len(value_names),
5095 max_size=len(value_names),
5098 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5099 oid: Integer() for oid in oids[:-1]
5102 for i, value_name in enumerate(value_names):
5103 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5105 class Seq(Sequence):
5108 for value_name, value in zip(value_names, values):
5109 seq[value_name] = Any(Integer(value).encode())
5110 seq["type"] = oid_chosen
5111 seq, _ = Seq().decode(seq.encode())
5112 for value_name in value_names:
5113 if value_name == value_name_chosen:
5115 self.assertIsNone(seq[value_name].defined)
5116 if value_name_chosen in oids[:-1]:
5117 self.assertIsNotNone(seq[value_name_chosen].defined)
5118 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5119 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5122 class TestDefinesByPath(TestCase):
5123 def test_generated(self):
5124 class Seq(Sequence):
5126 ("type", ObjectIdentifier()),
5127 ("value", OctetString(expl=tag_ctxc(123))),
5130 class SeqInner(Sequence):
5132 ("typeInner", ObjectIdentifier()),
5133 ("valueInner", Any()),
5136 class PairValue(SetOf):
5139 class Pair(Sequence):
5141 ("type", ObjectIdentifier()),
5142 ("value", PairValue()),
5145 class Pairs(SequenceOf):
5152 type_octet_stringed,
5154 ObjectIdentifier(oid)
5155 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5157 seq_integered = Seq()
5158 seq_integered["type"] = type_integered
5159 seq_integered["value"] = OctetString(Integer(123).encode())
5160 seq_integered_raw = seq_integered.encode()
5164 (type_octet_stringed, OctetString(b"whatever")),
5165 (type_integered, Integer(123)),
5166 (type_octet_stringed, OctetString(b"whenever")),
5167 (type_integered, Integer(234)),
5169 for t, v in pairs_input:
5172 pair["value"] = PairValue((Any(v),))
5174 seq_inner = SeqInner()
5175 seq_inner["typeInner"] = type_innered
5176 seq_inner["valueInner"] = Any(pairs)
5177 seq_sequenced = Seq()
5178 seq_sequenced["type"] = type_sequenced
5179 seq_sequenced["value"] = OctetString(seq_inner.encode())
5180 seq_sequenced_raw = seq_sequenced.encode()
5182 defines_by_path = []
5183 seq_integered, _ = Seq().decode(seq_integered_raw)
5184 self.assertIsNone(seq_integered["value"].defined)
5185 defines_by_path.append(
5186 (("type",), ((("value",), {
5187 type_integered: Integer(),
5188 type_sequenced: SeqInner(),
5191 seq_integered, _ = Seq().decode(
5193 ctx={"defines_by_path": defines_by_path},
5195 self.assertIsNotNone(seq_integered["value"].defined)
5196 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5197 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5198 self.assertTrue(seq_integered_raw[
5199 seq_integered["value"].defined[1].offset:
5200 ].startswith(Integer(123).encode()))
5202 seq_sequenced, _ = Seq().decode(
5204 ctx={"defines_by_path": defines_by_path},
5206 self.assertIsNotNone(seq_sequenced["value"].defined)
5207 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5208 seq_inner = seq_sequenced["value"].defined[1]
5209 self.assertIsNone(seq_inner["valueInner"].defined)
5211 defines_by_path.append((
5212 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5213 ((("valueInner",), {type_innered: Pairs()}),),
5215 seq_sequenced, _ = Seq().decode(
5217 ctx={"defines_by_path": defines_by_path},
5219 self.assertIsNotNone(seq_sequenced["value"].defined)
5220 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5221 seq_inner = seq_sequenced["value"].defined[1]
5222 self.assertIsNotNone(seq_inner["valueInner"].defined)
5223 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5224 pairs = seq_inner["valueInner"].defined[1]
5226 self.assertIsNone(pair["value"][0].defined)
5228 defines_by_path.append((
5231 DecodePathDefBy(type_sequenced),
5233 DecodePathDefBy(type_innered),
5238 type_integered: Integer(),
5239 type_octet_stringed: OctetString(),
5242 seq_sequenced, _ = Seq().decode(
5244 ctx={"defines_by_path": defines_by_path},
5246 self.assertIsNotNone(seq_sequenced["value"].defined)
5247 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5248 seq_inner = seq_sequenced["value"].defined[1]
5249 self.assertIsNotNone(seq_inner["valueInner"].defined)
5250 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5251 pairs_got = seq_inner["valueInner"].defined[1]
5252 for pair_input, pair_got in zip(pairs_input, pairs_got):
5253 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5254 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5256 @given(oid_strategy(), integers())
5257 def test_simple(self, oid, tgt):
5258 class Inner(Sequence):
5260 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5261 ObjectIdentifier(oid): Integer(),
5265 class Outer(Sequence):
5268 ("tgt", OctetString()),
5272 inner["oid"] = ObjectIdentifier(oid)
5274 outer["inner"] = inner
5275 outer["tgt"] = OctetString(Integer(tgt).encode())
5276 decoded, _ = Outer().decode(outer.encode())
5277 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5280 class TestAbsDecodePath(TestCase):
5282 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5283 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5285 def test_concat(self, decode_path, rel_path):
5286 self.assertSequenceEqual(
5287 abs_decode_path(decode_path, rel_path),
5288 decode_path + rel_path,
5292 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5293 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5295 def test_abs(self, decode_path, rel_path):
5296 self.assertSequenceEqual(
5297 abs_decode_path(decode_path, ("/",) + rel_path),
5302 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5303 integers(min_value=1, max_value=3),
5304 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5306 def test_dots(self, decode_path, number_of_dots, rel_path):
5307 self.assertSequenceEqual(
5308 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5309 decode_path[:-number_of_dots] + rel_path,
5313 class TestStrictDefaultExistence(TestCase):
5314 @given(data_strategy())
5315 def runTest(self, d):
5316 count = d.draw(integers(min_value=1, max_value=10))
5317 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5319 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5320 for i in range(count)
5323 class Seq(Sequence):
5326 for i in range(count):
5327 seq["int%d" % i] = Integer(123)
5329 chosen = "int%d" % chosen
5330 seq.specs[chosen] = seq.specs[chosen](default=123)
5332 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5333 seq.decode(raw, ctx={"strict_default_existence": True})
5336 class TestX690PrefixedType(TestCase):
5338 self.assertSequenceEqual(
5339 VisibleString("Jones").encode(),
5340 hexdec("1A054A6F6E6573"),
5342 self.assertSequenceEqual(
5345 impl=tag_encode(3, klass=TagClassApplication),
5347 hexdec("43054A6F6E6573"),
5349 self.assertSequenceEqual(
5353 impl=tag_encode(3, klass=TagClassApplication),
5357 hexdec("A20743054A6F6E6573"),
5359 self.assertSequenceEqual(
5363 impl=tag_encode(3, klass=TagClassApplication),
5365 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5367 hexdec("670743054A6F6E6573"),
5369 self.assertSequenceEqual(
5370 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5371 hexdec("82054A6F6E6573"),