2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from datetime import datetime
20 from string import ascii_letters
21 from string import digits
22 from string import printable
23 from string import whitespace
24 from unittest import TestCase
26 from hypothesis import assume
27 from hypothesis import given
28 from hypothesis import settings
29 from hypothesis.strategies import binary
30 from hypothesis.strategies import booleans
31 from hypothesis.strategies import composite
32 from hypothesis.strategies import data as data_strategy
33 from hypothesis.strategies import datetimes
34 from hypothesis.strategies import dictionaries
35 from hypothesis.strategies import integers
36 from hypothesis.strategies import just
37 from hypothesis.strategies import lists
38 from hypothesis.strategies import none
39 from hypothesis.strategies import one_of
40 from hypothesis.strategies import permutations
41 from hypothesis.strategies import sampled_from
42 from hypothesis.strategies import sets
43 from hypothesis.strategies import text
44 from hypothesis.strategies import tuples
45 from six import assertRaisesRegex
46 from six import binary_type
47 from six import byte2int
48 from six import indexbytes
49 from six import int2byte
50 from six import iterbytes
52 from six import text_type
53 from six import unichr as six_unichr
55 from pyderasn import _pp
56 from pyderasn import abs_decode_path
57 from pyderasn import Any
58 from pyderasn import BitString
59 from pyderasn import BMPString
60 from pyderasn import Boolean
61 from pyderasn import BoundsError
62 from pyderasn import Choice
63 from pyderasn import DecodeError
64 from pyderasn import DecodePathDefBy
65 from pyderasn import Enumerated
66 from pyderasn import EOC
67 from pyderasn import EOC_LEN
68 from pyderasn import GeneralizedTime
69 from pyderasn import GeneralString
70 from pyderasn import GraphicString
71 from pyderasn import hexdec
72 from pyderasn import hexenc
73 from pyderasn import IA5String
74 from pyderasn import Integer
75 from pyderasn import InvalidLength
76 from pyderasn import InvalidOID
77 from pyderasn import InvalidValueType
78 from pyderasn import len_decode
79 from pyderasn import len_encode
80 from pyderasn import LEN_YYMMDDHHMMSSZ
81 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
82 from pyderasn import LEN_YYYYMMDDHHMMSSZ
83 from pyderasn import LENINDEF
84 from pyderasn import NotEnoughData
85 from pyderasn import Null
86 from pyderasn import NumericString
87 from pyderasn import ObjectIdentifier
88 from pyderasn import ObjNotReady
89 from pyderasn import ObjUnknown
90 from pyderasn import OctetString
91 from pyderasn import pp_console_row
92 from pyderasn import pprint
93 from pyderasn import PrintableString
94 from pyderasn import Sequence
95 from pyderasn import SequenceOf
96 from pyderasn import Set
97 from pyderasn import SetOf
98 from pyderasn import tag_ctxc
99 from pyderasn import tag_ctxp
100 from pyderasn import tag_decode
101 from pyderasn import tag_encode
102 from pyderasn import tag_strip
103 from pyderasn import TagClassApplication
104 from pyderasn import TagClassContext
105 from pyderasn import TagClassPrivate
106 from pyderasn import TagClassUniversal
107 from pyderasn import TagFormConstructed
108 from pyderasn import TagFormPrimitive
109 from pyderasn import TagMismatch
110 from pyderasn import TeletexString
111 from pyderasn import UniversalString
112 from pyderasn import UTCTime
113 from pyderasn import UTF8String
114 from pyderasn import VideotexString
115 from pyderasn import VisibleString
118 settings.register_profile("local", settings(
121 settings.load_profile("local")
122 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
124 tag_classes = sampled_from((
130 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
131 decode_path_strat = lists(integers(), max_size=3).map(
132 lambda decode_path: tuple(str(dp) for dp in decode_path)
136 class TestHex(TestCase):
138 def test_symmetric(self, data):
139 self.assertEqual(hexdec(hexenc(data)), data)
142 class TestTagCoder(TestCase):
143 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
147 integers(min_value=0, max_value=30),
150 def test_short(self, klass, form, num, junk):
151 raw = tag_encode(klass=klass, form=form, num=num)
152 self.assertEqual(tag_decode(raw), (klass, form, num))
153 self.assertEqual(len(raw), 1)
155 byte2int(tag_encode(klass=klass, form=form, num=0)),
156 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
158 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
159 self.assertSequenceEqual(stripped.tobytes(), raw)
160 self.assertEqual(tlen, len(raw))
161 self.assertSequenceEqual(tail, junk)
163 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
167 integers(min_value=31),
170 def test_long(self, klass, form, num, junk):
171 raw = tag_encode(klass=klass, form=form, num=num)
172 self.assertEqual(tag_decode(raw), (klass, form, num))
173 self.assertGreater(len(raw), 1)
175 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
178 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
179 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
180 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
181 self.assertSequenceEqual(stripped.tobytes(), raw)
182 self.assertEqual(tlen, len(raw))
183 self.assertSequenceEqual(tail, junk)
185 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
186 @given(integers(min_value=31))
187 def test_unfinished_tag(self, num):
188 raw = bytearray(tag_encode(num=num))
189 for i in range(1, len(raw)):
191 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
192 tag_strip(bytes(raw))
194 def test_go_vectors_valid(self):
195 for data, (eklass, etag, elen, eform) in (
196 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
197 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
198 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
199 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
200 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
201 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
202 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
203 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
204 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
205 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
207 tag, _, len_encoded = tag_strip(memoryview(data))
208 klass, form, num = tag_decode(tag)
209 _len, _, tail = len_decode(len_encoded)
210 self.assertSequenceEqual(tail, b"")
211 self.assertEqual(klass, eklass)
212 self.assertEqual(num, etag)
213 self.assertEqual(_len, elen)
214 self.assertEqual(form, eform)
216 def test_go_vectors_invalid(self):
224 with self.assertRaises(DecodeError):
225 _, _, len_encoded = tag_strip(memoryview(data))
226 len_decode(len_encoded)
229 integers(min_value=0, max_value=127),
230 integers(min_value=0, max_value=2),
232 def test_long_instead_of_short(self, l, dummy_num):
233 octets = (b"\x00" * dummy_num) + int2byte(l)
234 octets = int2byte((dummy_num + 1) | 0x80) + octets
235 with self.assertRaises(DecodeError):
239 class TestLenCoder(TestCase):
240 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
242 integers(min_value=0, max_value=127),
245 def test_short(self, l, junk):
246 raw = len_encode(l) + junk
247 decoded, llen, tail = len_decode(memoryview(raw))
248 self.assertEqual(decoded, l)
249 self.assertEqual(llen, 1)
250 self.assertEqual(len(raw), 1 + len(junk))
251 self.assertEqual(tail.tobytes(), junk)
253 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
255 integers(min_value=128),
258 def test_long(self, l, junk):
259 raw = len_encode(l) + junk
260 decoded, llen, tail = len_decode(memoryview(raw))
261 self.assertEqual(decoded, l)
262 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
263 self.assertEqual(llen, len(raw) - len(junk))
264 self.assertNotEqual(indexbytes(raw, 1), 0)
265 self.assertSequenceEqual(tail.tobytes(), junk)
267 def test_empty(self):
268 with self.assertRaises(NotEnoughData):
271 @given(integers(min_value=128))
272 def test_stripped(self, _len):
273 with self.assertRaises(NotEnoughData):
274 len_decode(len_encode(_len)[:-1])
277 text_printable = text(alphabet=printable, min_size=1)
281 def text_letters(draw):
282 result = draw(text(alphabet=ascii_letters, min_size=1))
284 result = result.encode("ascii")
288 class CommonMixin(object):
289 def test_tag_default(self):
290 obj = self.base_klass()
291 self.assertEqual(obj.tag, obj.tag_default)
293 def test_simultaneous_impl_expl(self):
294 with self.assertRaises(ValueError):
295 self.base_klass(impl=b"whatever", expl=b"whenever")
297 @given(binary(min_size=1), integers(), integers(), integers())
298 def test_decoded(self, impl, offset, llen, vlen):
299 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
300 self.assertEqual(obj.offset, offset)
301 self.assertEqual(obj.llen, llen)
302 self.assertEqual(obj.vlen, vlen)
303 self.assertEqual(obj.tlen, len(impl))
304 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
306 @given(binary(min_size=1))
307 def test_impl_inherited(self, impl_tag):
308 class Inherited(self.base_klass):
311 self.assertSequenceEqual(obj.impl, impl_tag)
312 self.assertFalse(obj.expled)
315 def test_expl_inherited(self, expl_tag):
316 class Inherited(self.base_klass):
319 self.assertSequenceEqual(obj.expl, expl_tag)
320 self.assertTrue(obj.expled)
322 def assert_copied_basic_fields(self, obj, obj_copied):
323 self.assertEqual(obj, obj_copied)
324 self.assertSequenceEqual(obj.tag, obj_copied.tag)
325 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
326 self.assertEqual(obj.default, obj_copied.default)
327 self.assertEqual(obj.optional, obj_copied.optional)
328 self.assertEqual(obj.offset, obj_copied.offset)
329 self.assertEqual(obj.llen, obj_copied.llen)
330 self.assertEqual(obj.vlen, obj_copied.vlen)
334 def boolean_values_strategy(draw, do_expl=False):
335 value = draw(one_of(none(), booleans()))
339 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
341 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
342 default = draw(one_of(none(), booleans()))
343 optional = draw(one_of(none(), booleans()))
345 draw(integers(min_value=0)),
346 draw(integers(min_value=0)),
347 draw(integers(min_value=0)),
349 return (value, impl, expl, default, optional, _decoded)
352 class BooleanInherited(Boolean):
356 class TestBoolean(CommonMixin, TestCase):
359 def test_invalid_value_type(self):
360 with self.assertRaises(InvalidValueType) as err:
365 def test_optional(self, optional):
366 obj = Boolean(default=Boolean(False), optional=optional)
367 self.assertTrue(obj.optional)
370 def test_ready(self, value):
372 self.assertFalse(obj.ready)
375 with self.assertRaises(ObjNotReady) as err:
379 self.assertTrue(obj.ready)
383 @given(booleans(), booleans(), binary(), binary())
384 def test_comparison(self, value1, value2, tag1, tag2):
385 for klass in (Boolean, BooleanInherited):
388 self.assertEqual(obj1 == obj2, value1 == value2)
389 self.assertEqual(obj1 != obj2, value1 != value2)
390 self.assertEqual(obj1 == bool(obj2), value1 == value2)
391 obj1 = klass(value1, impl=tag1)
392 obj2 = klass(value1, impl=tag2)
393 self.assertEqual(obj1 == obj2, tag1 == tag2)
394 self.assertEqual(obj1 != obj2, tag1 != tag2)
396 @given(data_strategy())
397 def test_call(self, d):
398 for klass in (Boolean, BooleanInherited):
406 ) = d.draw(boolean_values_strategy())
412 optional_initial or False,
422 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
423 obj = obj_initial(value, impl, expl, default, optional)
425 value_expected = default if value is None else value
427 default_initial if value_expected is None
430 self.assertEqual(obj, value_expected)
431 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
432 self.assertEqual(obj.expl_tag, expl or expl_initial)
435 default_initial if default is None else default,
437 if obj.default is None:
438 optional = optional_initial if optional is None else optional
439 optional = False if optional is None else optional
442 self.assertEqual(obj.optional, optional)
444 @given(boolean_values_strategy())
445 def test_copy(self, values):
446 for klass in (Boolean, BooleanInherited):
448 obj_copied = obj.copy()
449 self.assert_copied_basic_fields(obj, obj_copied)
453 integers(min_value=1).map(tag_encode),
455 def test_stripped(self, value, tag_impl):
456 obj = Boolean(value, impl=tag_impl)
457 with self.assertRaises(NotEnoughData):
458 obj.decode(obj.encode()[:-1])
462 integers(min_value=1).map(tag_ctxc),
464 def test_stripped_expl(self, value, tag_expl):
465 obj = Boolean(value, expl=tag_expl)
466 with self.assertRaises(NotEnoughData):
467 obj.decode(obj.encode()[:-1])
470 integers(min_value=31),
471 integers(min_value=0),
474 def test_bad_tag(self, tag, offset, decode_path):
475 with self.assertRaises(DecodeError) as err:
477 tag_encode(tag)[:-1],
479 decode_path=decode_path,
482 self.assertEqual(err.exception.offset, offset)
483 self.assertEqual(err.exception.decode_path, decode_path)
486 integers(min_value=31),
487 integers(min_value=0),
490 def test_bad_expl_tag(self, tag, offset, decode_path):
491 with self.assertRaises(DecodeError) as err:
492 Boolean(expl=Boolean.tag_default).decode(
493 tag_encode(tag)[:-1],
495 decode_path=decode_path,
498 self.assertEqual(err.exception.offset, offset)
499 self.assertEqual(err.exception.decode_path, decode_path)
502 integers(min_value=128),
503 integers(min_value=0),
506 def test_bad_len(self, l, offset, decode_path):
507 with self.assertRaises(DecodeError) as err:
509 Boolean.tag_default + len_encode(l)[:-1],
511 decode_path=decode_path,
514 self.assertEqual(err.exception.offset, offset)
515 self.assertEqual(err.exception.decode_path, decode_path)
518 integers(min_value=128),
519 integers(min_value=0),
522 def test_bad_expl_len(self, l, offset, decode_path):
523 with self.assertRaises(DecodeError) as err:
524 Boolean(expl=Boolean.tag_default).decode(
525 Boolean.tag_default + len_encode(l)[:-1],
527 decode_path=decode_path,
530 self.assertEqual(err.exception.offset, offset)
531 self.assertEqual(err.exception.decode_path, decode_path)
533 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
535 boolean_values_strategy(),
537 integers(min_value=1).map(tag_ctxc),
538 integers(min_value=0),
541 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
542 for klass in (Boolean, BooleanInherited):
543 _, _, _, default, optional, _decoded = values
552 self.assertFalse(obj.expled)
553 obj_encoded = obj.encode()
554 obj_expled = obj(value, expl=tag_expl)
555 self.assertTrue(obj_expled.expled)
558 obj_expled_encoded = obj_expled.encode()
559 obj_decoded, tail = obj_expled.decode(
560 obj_expled_encoded + tail_junk,
565 self.assertEqual(tail, tail_junk)
566 self.assertEqual(obj_decoded, obj_expled)
567 self.assertNotEqual(obj_decoded, obj)
568 self.assertEqual(bool(obj_decoded), bool(obj_expled))
569 self.assertEqual(bool(obj_decoded), bool(obj))
570 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
571 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
572 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
574 obj_decoded.expl_llen,
575 len(len_encode(len(obj_encoded))),
577 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
578 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
581 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
583 self.assertEqual(obj_decoded.expl_offset, offset)
585 @given(integers(min_value=2))
586 def test_invalid_len(self, l):
587 with self.assertRaises(InvalidLength):
588 Boolean().decode(b"".join((
594 @given(integers(min_value=0 + 1, max_value=255 - 1))
595 def test_ber_value(self, value):
596 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
597 Boolean().decode(b"".join((
602 obj, _ = Boolean().decode(
610 self.assertTrue(bool(obj))
611 self.assertTrue(obj.bered)
612 self.assertFalse(obj.lenindef)
615 integers(min_value=1).map(tag_ctxc),
616 binary().filter(lambda x: not x.startswith(EOC)),
618 def test_ber_expl_no_eoc(self, expl, junk):
619 encoded = expl + LENINDEF + Boolean(False).encode()
620 with assertRaisesRegex(self, DecodeError, "no EOC"):
621 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
622 obj, tail = Boolean(expl=expl).decode(
623 encoded + EOC + junk,
626 self.assertTrue(obj.expl_lenindef)
627 self.assertSequenceEqual(tail, junk)
630 integers(min_value=1).map(tag_ctxc),
637 def test_ber_expl(self, expl, values):
643 Boolean(value).encode() +
646 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
648 class SeqOf(SequenceOf):
649 schema = Boolean(expl=expl)
650 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
651 self.assertSequenceEqual(tail, b"")
652 self.assertSequenceEqual([bool(v) for v in seqof], values)
667 len(expl) + 1 + 3 + EOC_LEN,
678 def integer_values_strategy(draw, do_expl=False):
679 bound_min, value, default, bound_max = sorted(draw(sets(
688 _specs = draw(sets(text_letters()))
691 min_size=len(_specs),
692 max_size=len(_specs),
694 _specs = list(zip(_specs, values))
697 bounds = (bound_min, bound_max)
701 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
703 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
706 optional = draw(one_of(none(), booleans()))
708 draw(integers(min_value=0)),
709 draw(integers(min_value=0)),
710 draw(integers(min_value=0)),
712 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
715 class IntegerInherited(Integer):
719 class TestInteger(CommonMixin, TestCase):
722 def test_invalid_value_type(self):
723 with self.assertRaises(InvalidValueType) as err:
727 @given(sets(text_letters(), min_size=2))
728 def test_unknown_name(self, names_input):
729 missing = names_input.pop()
732 schema = [(n, 123) for n in names_input]
733 with self.assertRaises(ObjUnknown) as err:
737 @given(sets(text_letters(), min_size=2))
738 def test_known_name(self, names_input):
740 schema = [(n, 123) for n in names_input]
741 Int(names_input.pop())
744 def test_optional(self, optional):
745 obj = Integer(default=Integer(0), optional=optional)
746 self.assertTrue(obj.optional)
749 def test_ready(self, value):
751 self.assertFalse(obj.ready)
754 with self.assertRaises(ObjNotReady) as err:
758 self.assertTrue(obj.ready)
763 @given(integers(), integers(), binary(), binary())
764 def test_comparison(self, value1, value2, tag1, tag2):
765 for klass in (Integer, IntegerInherited):
768 self.assertEqual(obj1 == obj2, value1 == value2)
769 self.assertEqual(obj1 != obj2, value1 != value2)
770 self.assertEqual(obj1 == int(obj2), value1 == value2)
771 obj1 = klass(value1, impl=tag1)
772 obj2 = klass(value1, impl=tag2)
773 self.assertEqual(obj1 == obj2, tag1 == tag2)
774 self.assertEqual(obj1 != obj2, tag1 != tag2)
776 @given(lists(integers()))
777 def test_sorted_works(self, values):
778 self.assertSequenceEqual(
779 [int(v) for v in sorted(Integer(v) for v in values)],
783 @given(data_strategy())
784 def test_named(self, d):
785 names_input = list(d.draw(sets(text_letters(), min_size=1)))
786 values_input = list(d.draw(sets(
788 min_size=len(names_input),
789 max_size=len(names_input),
791 chosen_name = d.draw(sampled_from(names_input))
792 names_input = dict(zip(names_input, values_input))
796 _int = Int(chosen_name)
797 self.assertEqual(_int.named, chosen_name)
798 self.assertEqual(int(_int), names_input[chosen_name])
800 @given(integers(), integers(min_value=0), integers(min_value=0))
801 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
802 value = bound_min + value_delta
803 bound_max = value + bound_delta
804 Integer(value=value, bounds=(bound_min, bound_max))
806 @given(sets(integers(), min_size=3, max_size=3))
807 def test_bounds_unsatisfied(self, values):
808 values = sorted(values)
809 with self.assertRaises(BoundsError) as err:
810 Integer(value=values[0], bounds=(values[1], values[2]))
812 with self.assertRaises(BoundsError) as err:
813 Integer(value=values[2], bounds=(values[0], values[1]))
816 @given(data_strategy())
817 def test_call(self, d):
818 for klass in (Integer, IntegerInherited):
828 ) = d.draw(integer_values_strategy())
835 optional_initial or False,
848 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
849 if (default is None) and (obj_initial.default is not None):
853 (value is not None) and
854 (bounds_initial is not None) and
855 not (bounds_initial[0] <= value <= bounds_initial[1])
860 (default is not None) and
861 (bounds_initial is not None) and
862 not (bounds_initial[0] <= default <= bounds_initial[1])
865 obj = obj_initial(value, bounds, impl, expl, default, optional)
867 value_expected = default if value is None else value
869 default_initial if value_expected is None
872 self.assertEqual(obj, value_expected)
873 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
874 self.assertEqual(obj.expl_tag, expl or expl_initial)
877 default_initial if default is None else default,
879 if obj.default is None:
880 optional = optional_initial if optional is None else optional
881 optional = False if optional is None else optional
884 self.assertEqual(obj.optional, optional)
886 (obj._bound_min, obj._bound_max),
887 bounds or bounds_initial or (float("-inf"), float("+inf")),
891 {} if _specs_initial is None else dict(_specs_initial),
894 @given(integer_values_strategy())
895 def test_copy(self, values):
896 for klass in (Integer, IntegerInherited):
898 obj_copied = obj.copy()
899 self.assert_copied_basic_fields(obj, obj_copied)
900 self.assertEqual(obj.specs, obj_copied.specs)
901 self.assertEqual(obj._bound_min, obj_copied._bound_min)
902 self.assertEqual(obj._bound_max, obj_copied._bound_max)
903 self.assertEqual(obj._value, obj_copied._value)
907 integers(min_value=1).map(tag_encode),
909 def test_stripped(self, value, tag_impl):
910 obj = Integer(value, impl=tag_impl)
911 with self.assertRaises(NotEnoughData):
912 obj.decode(obj.encode()[:-1])
916 integers(min_value=1).map(tag_ctxc),
918 def test_stripped_expl(self, value, tag_expl):
919 obj = Integer(value, expl=tag_expl)
920 with self.assertRaises(NotEnoughData):
921 obj.decode(obj.encode()[:-1])
923 def test_zero_len(self):
924 with self.assertRaises(NotEnoughData):
925 Integer().decode(b"".join((
931 integers(min_value=31),
932 integers(min_value=0),
935 def test_bad_tag(self, tag, offset, decode_path):
936 with self.assertRaises(DecodeError) as err:
938 tag_encode(tag)[:-1],
940 decode_path=decode_path,
943 self.assertEqual(err.exception.offset, offset)
944 self.assertEqual(err.exception.decode_path, decode_path)
947 integers(min_value=128),
948 integers(min_value=0),
951 def test_bad_len(self, l, offset, decode_path):
952 with self.assertRaises(DecodeError) as err:
954 Integer.tag_default + len_encode(l)[:-1],
956 decode_path=decode_path,
959 self.assertEqual(err.exception.offset, offset)
960 self.assertEqual(err.exception.decode_path, decode_path)
963 sets(integers(), min_size=2, max_size=2),
964 integers(min_value=0),
967 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
968 value, bound_min = list(sorted(ints))
971 bounds = (bound_min, bound_min)
972 with self.assertRaises(DecodeError) as err:
974 Integer(value).encode(),
976 decode_path=decode_path,
979 self.assertEqual(err.exception.offset, offset)
980 self.assertEqual(err.exception.decode_path, decode_path)
982 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
984 integer_values_strategy(),
986 integers(min_value=1).map(tag_ctxc),
987 integers(min_value=0),
990 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
991 for klass in (Integer, IntegerInherited):
992 _, _, _, _, default, optional, _, _decoded = values
1001 self.assertFalse(obj.expled)
1002 obj_encoded = obj.encode()
1003 obj_expled = obj(value, expl=tag_expl)
1004 self.assertTrue(obj_expled.expled)
1007 obj_expled_encoded = obj_expled.encode()
1008 obj_decoded, tail = obj_expled.decode(
1009 obj_expled_encoded + tail_junk,
1014 self.assertEqual(tail, tail_junk)
1015 self.assertEqual(obj_decoded, obj_expled)
1016 self.assertNotEqual(obj_decoded, obj)
1017 self.assertEqual(int(obj_decoded), int(obj_expled))
1018 self.assertEqual(int(obj_decoded), int(obj))
1019 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1020 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1021 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1023 obj_decoded.expl_llen,
1024 len(len_encode(len(obj_encoded))),
1026 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1027 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1030 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1032 self.assertEqual(obj_decoded.expl_offset, offset)
1034 def test_go_vectors_valid(self):
1035 for data, expect in ((
1039 (b"\xff\x7f", -129),
1043 (b"\xff\x00", -256),
1047 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1048 (b"\x80\x00\x00\x00", -2147483648),
1051 Integer().decode(b"".join((
1052 Integer.tag_default,
1053 len_encode(len(data)),
1059 def test_go_vectors_invalid(self):
1064 with self.assertRaises(DecodeError):
1065 Integer().decode(b"".join((
1066 Integer.tag_default,
1067 len_encode(len(data)),
1073 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1076 if draw(booleans()):
1077 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1079 integers(min_value=0, max_value=255),
1080 min_size=len(schema),
1081 max_size=len(schema),
1083 schema = list(zip(schema, bits))
1085 def _value(value_required):
1086 if not value_required and draw(booleans()):
1088 generation_choice = 0
1090 generation_choice = draw(sampled_from((1, 2, 3)))
1091 if generation_choice == 1 or draw(booleans()):
1092 return "'%s'B" % "".join(draw(lists(
1093 sampled_from(("0", "1")),
1094 max_size=len(schema),
1096 elif generation_choice == 2 or draw(booleans()):
1097 return draw(binary(max_size=len(schema) // 8))
1098 elif generation_choice == 3 or draw(booleans()):
1099 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1101 value = _value(value_required)
1102 default = _value(value_required=False)
1106 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1108 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1109 optional = draw(one_of(none(), booleans()))
1111 draw(integers(min_value=0)),
1112 draw(integers(min_value=0)),
1113 draw(integers(min_value=0)),
1115 return (schema, value, impl, expl, default, optional, _decoded)
1118 class BitStringInherited(BitString):
1122 class TestBitString(CommonMixin, TestCase):
1123 base_klass = BitString
1125 @given(lists(booleans()))
1126 def test_b_encoding(self, bits):
1127 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1128 self.assertEqual(obj.bit_len, len(bits))
1129 self.assertSequenceEqual(list(obj), bits)
1130 for i, bit in enumerate(bits):
1131 self.assertEqual(obj[i], bit)
1133 @given(lists(booleans()))
1134 def test_out_of_bounds_bits(self, bits):
1135 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1136 for i in range(len(bits), len(bits) * 2):
1137 self.assertFalse(obj[i])
1139 def test_bad_b_encoding(self):
1140 with self.assertRaises(ValueError):
1141 BitString("'010120101'B")
1144 integers(min_value=1, max_value=255),
1145 integers(min_value=1, max_value=255),
1147 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1148 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1149 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1150 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1152 class BS(BitString):
1153 schema = (("whatever", 0),)
1154 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1155 self.assertEqual(obj.bit_len, leading_zeros + 1)
1156 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1158 def test_zero_len(self):
1159 with self.assertRaises(NotEnoughData):
1160 BitString().decode(b"".join((
1161 BitString.tag_default,
1165 def test_invalid_value_type(self):
1166 with self.assertRaises(InvalidValueType) as err:
1169 with self.assertRaises(InvalidValueType) as err:
1173 def test_obj_unknown(self):
1174 with self.assertRaises(ObjUnknown) as err:
1175 BitString(b"whatever")["whenever"]
1178 def test_get_invalid_type(self):
1179 with self.assertRaises(InvalidValueType) as err:
1180 BitString(b"whatever")[(1, 2, 3)]
1183 @given(data_strategy())
1184 def test_unknown_name(self, d):
1185 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1186 missing = _schema.pop()
1188 class BS(BitString):
1189 schema = [(n, i) for i, n in enumerate(_schema)]
1190 with self.assertRaises(ObjUnknown) as err:
1195 def test_optional(self, optional):
1196 obj = BitString(default=BitString(b""), optional=optional)
1197 self.assertTrue(obj.optional)
1200 def test_ready(self, value):
1202 self.assertFalse(obj.ready)
1205 with self.assertRaises(ObjNotReady) as err:
1208 obj = BitString(value)
1209 self.assertTrue(obj.ready)
1214 tuples(integers(min_value=0), binary()),
1215 tuples(integers(min_value=0), binary()),
1219 def test_comparison(self, value1, value2, tag1, tag2):
1220 for klass in (BitString, BitStringInherited):
1221 obj1 = klass(value1)
1222 obj2 = klass(value2)
1223 self.assertEqual(obj1 == obj2, value1 == value2)
1224 self.assertEqual(obj1 != obj2, value1 != value2)
1225 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1226 obj1 = klass(value1, impl=tag1)
1227 obj2 = klass(value1, impl=tag2)
1228 self.assertEqual(obj1 == obj2, tag1 == tag2)
1229 self.assertEqual(obj1 != obj2, tag1 != tag2)
1231 @given(data_strategy())
1232 def test_call(self, d):
1233 for klass in (BitString, BitStringInherited):
1242 ) = d.draw(bit_string_values_strategy())
1245 schema = schema_initial
1247 value=value_initial,
1250 default=default_initial,
1251 optional=optional_initial or False,
1252 _decoded=_decoded_initial,
1262 ) = d.draw(bit_string_values_strategy(
1263 schema=schema_initial,
1264 do_expl=impl_initial is None,
1273 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1274 self.assertEqual(obj.expl_tag, expl or expl_initial)
1275 if obj.default is None:
1276 optional = optional_initial if optional is None else optional
1277 optional = False if optional is None else optional
1280 self.assertEqual(obj.optional, optional)
1281 self.assertEqual(obj.specs, obj_initial.specs)
1283 @given(bit_string_values_strategy())
1284 def test_copy(self, values):
1285 for klass in (BitString, BitStringInherited):
1286 _schema, value, impl, expl, default, optional, _decoded = values
1295 optional=optional or False,
1298 obj_copied = obj.copy()
1299 self.assert_copied_basic_fields(obj, obj_copied)
1300 self.assertEqual(obj.specs, obj_copied.specs)
1301 self.assertEqual(obj._value, obj_copied._value)
1305 integers(min_value=1).map(tag_encode),
1307 def test_stripped(self, value, tag_impl):
1308 obj = BitString(value, impl=tag_impl)
1309 with self.assertRaises(NotEnoughData):
1310 obj.decode(obj.encode()[:-1])
1314 integers(min_value=1).map(tag_ctxc),
1316 def test_stripped_expl(self, value, tag_expl):
1317 obj = BitString(value, expl=tag_expl)
1318 with self.assertRaises(NotEnoughData):
1319 obj.decode(obj.encode()[:-1])
1322 integers(min_value=31),
1323 integers(min_value=0),
1326 def test_bad_tag(self, tag, offset, decode_path):
1327 with self.assertRaises(DecodeError) as err:
1329 tag_encode(tag)[:-1],
1331 decode_path=decode_path,
1334 self.assertEqual(err.exception.offset, offset)
1335 self.assertEqual(err.exception.decode_path, decode_path)
1338 integers(min_value=128),
1339 integers(min_value=0),
1342 def test_bad_len(self, l, offset, decode_path):
1343 with self.assertRaises(DecodeError) as err:
1345 BitString.tag_default + len_encode(l)[:-1],
1347 decode_path=decode_path,
1350 self.assertEqual(err.exception.offset, offset)
1351 self.assertEqual(err.exception.decode_path, decode_path)
1353 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1354 @given(data_strategy())
1355 def test_symmetric(self, d):
1364 ) = d.draw(bit_string_values_strategy(value_required=True))
1365 tail_junk = d.draw(binary(max_size=5))
1366 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1367 offset = d.draw(integers(min_value=0))
1368 for klass in (BitString, BitStringInherited):
1379 self.assertFalse(obj.expled)
1380 obj_encoded = obj.encode()
1381 obj_expled = obj(value, expl=tag_expl)
1382 self.assertTrue(obj_expled.expled)
1385 obj_expled_encoded = obj_expled.encode()
1386 obj_decoded, tail = obj_expled.decode(
1387 obj_expled_encoded + tail_junk,
1392 self.assertEqual(tail, tail_junk)
1393 self.assertEqual(obj_decoded, obj_expled)
1394 self.assertNotEqual(obj_decoded, obj)
1395 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1396 self.assertEqual(bytes(obj_decoded), bytes(obj))
1397 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1398 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1399 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1401 obj_decoded.expl_llen,
1402 len(len_encode(len(obj_encoded))),
1404 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1405 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1408 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1410 self.assertEqual(obj_decoded.expl_offset, offset)
1411 if isinstance(value, tuple):
1412 self.assertSetEqual(set(value), set(obj_decoded.named))
1416 @given(integers(min_value=1, max_value=255))
1417 def test_bad_zero_value(self, pad_size):
1418 with self.assertRaises(DecodeError):
1419 BitString().decode(b"".join((
1420 BitString.tag_default,
1425 def test_go_vectors_invalid(self):
1431 with self.assertRaises(DecodeError):
1432 BitString().decode(b"".join((
1433 BitString.tag_default,
1438 def test_go_vectors_valid(self):
1439 obj, _ = BitString().decode(b"".join((
1440 BitString.tag_default,
1444 self.assertEqual(bytes(obj), b"")
1445 self.assertEqual(obj.bit_len, 0)
1447 obj, _ = BitString().decode(b"".join((
1448 BitString.tag_default,
1452 self.assertEqual(bytes(obj), b"\x00")
1453 self.assertEqual(obj.bit_len, 1)
1455 obj = BitString((16, b"\x82\x40"))
1456 self.assertTrue(obj[0])
1457 self.assertFalse(obj[1])
1458 self.assertTrue(obj[6])
1459 self.assertTrue(obj[9])
1460 self.assertFalse(obj[17])
1463 integers(min_value=1, max_value=30),
1466 binary(min_size=1, max_size=5),
1468 binary(min_size=1, max_size=5),
1476 lists(booleans(), min_size=1),
1479 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1480 def chunk_constructed(contents):
1482 tag_encode(form=TagFormConstructed, num=3) +
1484 b"".join(BitString(content).encode() for content in contents) +
1488 payload_expected = b""
1489 bit_len_expected = 0
1490 for chunk_input in chunk_inputs:
1491 if isinstance(chunk_input, binary_type):
1492 chunks.append(BitString(chunk_input).encode())
1493 payload_expected += chunk_input
1494 bit_len_expected += len(chunk_input) * 8
1496 chunks.append(chunk_constructed(chunk_input))
1497 payload = b"".join(chunk_input)
1498 payload_expected += payload
1499 bit_len_expected += len(payload) * 8
1500 chunk_last = BitString("'%s'B" % "".join(
1501 "1" if bit else "0" for bit in chunk_last_bits
1503 payload_expected += bytes(chunk_last)
1504 bit_len_expected += chunk_last.bit_len
1505 encoded_indefinite = (
1506 tag_encode(form=TagFormConstructed, num=impl) +
1509 chunk_last.encode() +
1512 encoded_definite = (
1513 tag_encode(form=TagFormConstructed, num=impl) +
1514 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1518 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1519 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1520 for lenindef_expected, encoded in (
1521 (True, encoded_indefinite),
1522 (False, encoded_definite),
1524 obj, tail = BitString(impl=tag_encode(impl)).decode(
1526 ctx={"bered": True},
1528 self.assertSequenceEqual(tail, junk)
1529 self.assertEqual(obj.bit_len, bit_len_expected)
1530 self.assertSequenceEqual(bytes(obj), payload_expected)
1531 self.assertTrue(obj.bered)
1532 self.assertEqual(obj.lenindef, lenindef_expected)
1533 self.assertEqual(len(encoded), obj.tlvlen)
1536 integers(min_value=0),
1539 def test_ber_definite_too_short(self, offset, decode_path):
1540 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1542 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1544 decode_path=decode_path,
1545 ctx={"bered": True},
1547 self.assertEqual(err.exception.decode_path, decode_path)
1548 self.assertEqual(err.exception.offset, offset)
1551 integers(min_value=0),
1554 def test_ber_definite_no_data(self, offset, decode_path):
1555 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1557 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1559 decode_path=decode_path,
1560 ctx={"bered": True},
1562 self.assertEqual(err.exception.decode_path, decode_path)
1563 self.assertEqual(err.exception.offset, offset)
1566 integers(min_value=0),
1568 integers(min_value=1, max_value=3),
1570 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1571 bs = BitString(b"data").encode()
1572 with self.assertRaises(NotEnoughData) as err:
1574 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1576 decode_path=decode_path,
1577 ctx={"bered": True},
1579 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1580 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1583 integers(min_value=0),
1585 integers(min_value=1, max_value=3),
1587 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1588 bs = BitString(b"data").encode()
1589 bs_longer = BitString(b"data-longer").encode()
1590 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1593 tag_encode(3, form=TagFormConstructed) +
1594 len_encode((chunks + 1) * len(bs)) +
1599 decode_path=decode_path,
1600 ctx={"bered": True},
1602 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1603 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1606 integers(min_value=0),
1609 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1610 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1612 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1614 decode_path=decode_path,
1615 ctx={"bered": True},
1617 self.assertEqual(err.exception.decode_path, decode_path)
1618 self.assertEqual(err.exception.offset, offset)
1620 @given(data_strategy())
1621 def test_ber_indefinite_not_multiple(self, d):
1622 bs_short = BitString("'A'H").encode()
1623 bs_full = BitString("'AA'H").encode()
1624 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1625 chunks.append(bs_short)
1626 d.draw(permutations(chunks))
1627 chunks.append(bs_short)
1628 offset = d.draw(integers(min_value=0))
1629 decode_path = d.draw(decode_path_strat)
1630 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1633 tag_encode(3, form=TagFormConstructed) +
1639 decode_path=decode_path,
1640 ctx={"bered": True},
1643 err.exception.decode_path,
1644 decode_path + (str(chunks.index(bs_short)),),
1647 err.exception.offset,
1648 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1651 def test_x690_vector(self):
1652 vector = BitString("'0A3B5F291CD'H")
1653 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1654 self.assertSequenceEqual(tail, b"")
1655 self.assertEqual(obj, vector)
1656 obj, tail = BitString().decode(
1657 hexdec("23800303000A3B0305045F291CD00000"),
1658 ctx={"bered": True},
1660 self.assertSequenceEqual(tail, b"")
1661 self.assertEqual(obj, vector)
1662 self.assertTrue(obj.bered)
1663 self.assertTrue(obj.lenindef)
1667 def octet_string_values_strategy(draw, do_expl=False):
1668 bound_min, bound_max = sorted(draw(sets(
1669 integers(min_value=0, max_value=1 << 7),
1673 value = draw(one_of(
1675 binary(min_size=bound_min, max_size=bound_max),
1677 default = draw(one_of(
1679 binary(min_size=bound_min, max_size=bound_max),
1682 if draw(booleans()):
1683 bounds = (bound_min, bound_max)
1687 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1689 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1690 optional = draw(one_of(none(), booleans()))
1692 draw(integers(min_value=0)),
1693 draw(integers(min_value=0)),
1694 draw(integers(min_value=0)),
1696 return (value, bounds, impl, expl, default, optional, _decoded)
1699 class OctetStringInherited(OctetString):
1703 class TestOctetString(CommonMixin, TestCase):
1704 base_klass = OctetString
1706 def test_invalid_value_type(self):
1707 with self.assertRaises(InvalidValueType) as err:
1708 OctetString(text_type(123))
1712 def test_optional(self, optional):
1713 obj = OctetString(default=OctetString(b""), optional=optional)
1714 self.assertTrue(obj.optional)
1717 def test_ready(self, value):
1719 self.assertFalse(obj.ready)
1722 with self.assertRaises(ObjNotReady) as err:
1725 obj = OctetString(value)
1726 self.assertTrue(obj.ready)
1730 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1731 def test_comparison(self, value1, value2, tag1, tag2):
1732 for klass in (OctetString, OctetStringInherited):
1733 obj1 = klass(value1)
1734 obj2 = klass(value2)
1735 self.assertEqual(obj1 == obj2, value1 == value2)
1736 self.assertEqual(obj1 != obj2, value1 != value2)
1737 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1738 obj1 = klass(value1, impl=tag1)
1739 obj2 = klass(value1, impl=tag2)
1740 self.assertEqual(obj1 == obj2, tag1 == tag2)
1741 self.assertEqual(obj1 != obj2, tag1 != tag2)
1743 @given(lists(binary()))
1744 def test_sorted_works(self, values):
1745 self.assertSequenceEqual(
1746 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1750 @given(data_strategy())
1751 def test_bounds_satisfied(self, d):
1752 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1753 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1754 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1755 OctetString(value=value, bounds=(bound_min, bound_max))
1757 @given(data_strategy())
1758 def test_bounds_unsatisfied(self, d):
1759 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1760 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1761 value = d.draw(binary(max_size=bound_min - 1))
1762 with self.assertRaises(BoundsError) as err:
1763 OctetString(value=value, bounds=(bound_min, bound_max))
1765 value = d.draw(binary(min_size=bound_max + 1))
1766 with self.assertRaises(BoundsError) as err:
1767 OctetString(value=value, bounds=(bound_min, bound_max))
1770 @given(data_strategy())
1771 def test_call(self, d):
1772 for klass in (OctetString, OctetStringInherited):
1781 ) = d.draw(octet_string_values_strategy())
1782 obj_initial = klass(
1788 optional_initial or False,
1799 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1800 if (default is None) and (obj_initial.default is not None):
1803 (bounds is None) and
1804 (value is not None) and
1805 (bounds_initial is not None) and
1806 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1810 (bounds is None) and
1811 (default is not None) and
1812 (bounds_initial is not None) and
1813 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1816 obj = obj_initial(value, bounds, impl, expl, default, optional)
1818 value_expected = default if value is None else value
1820 default_initial if value_expected is None
1823 self.assertEqual(obj, value_expected)
1824 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1825 self.assertEqual(obj.expl_tag, expl or expl_initial)
1828 default_initial if default is None else default,
1830 if obj.default is None:
1831 optional = optional_initial if optional is None else optional
1832 optional = False if optional is None else optional
1835 self.assertEqual(obj.optional, optional)
1837 (obj._bound_min, obj._bound_max),
1838 bounds or bounds_initial or (0, float("+inf")),
1841 @given(octet_string_values_strategy())
1842 def test_copy(self, values):
1843 for klass in (OctetString, OctetStringInherited):
1844 obj = klass(*values)
1845 obj_copied = obj.copy()
1846 self.assert_copied_basic_fields(obj, obj_copied)
1847 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1848 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1849 self.assertEqual(obj._value, obj_copied._value)
1853 integers(min_value=1).map(tag_encode),
1855 def test_stripped(self, value, tag_impl):
1856 obj = OctetString(value, impl=tag_impl)
1857 with self.assertRaises(NotEnoughData):
1858 obj.decode(obj.encode()[:-1])
1862 integers(min_value=1).map(tag_ctxc),
1864 def test_stripped_expl(self, value, tag_expl):
1865 obj = OctetString(value, expl=tag_expl)
1866 with self.assertRaises(NotEnoughData):
1867 obj.decode(obj.encode()[:-1])
1870 integers(min_value=31),
1871 integers(min_value=0),
1874 def test_bad_tag(self, tag, offset, decode_path):
1875 with self.assertRaises(DecodeError) as err:
1876 OctetString().decode(
1877 tag_encode(tag)[:-1],
1879 decode_path=decode_path,
1882 self.assertEqual(err.exception.offset, offset)
1883 self.assertEqual(err.exception.decode_path, decode_path)
1886 integers(min_value=128),
1887 integers(min_value=0),
1890 def test_bad_len(self, l, offset, decode_path):
1891 with self.assertRaises(DecodeError) as err:
1892 OctetString().decode(
1893 OctetString.tag_default + len_encode(l)[:-1],
1895 decode_path=decode_path,
1898 self.assertEqual(err.exception.offset, offset)
1899 self.assertEqual(err.exception.decode_path, decode_path)
1902 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1903 integers(min_value=0),
1906 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1907 value, bound_min = list(sorted(ints))
1909 class String(OctetString):
1910 bounds = (bound_min, bound_min)
1911 with self.assertRaises(DecodeError) as err:
1913 OctetString(b"\x00" * value).encode(),
1915 decode_path=decode_path,
1918 self.assertEqual(err.exception.offset, offset)
1919 self.assertEqual(err.exception.decode_path, decode_path)
1921 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1923 octet_string_values_strategy(),
1925 integers(min_value=1).map(tag_ctxc),
1926 integers(min_value=0),
1929 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1930 for klass in (OctetString, OctetStringInherited):
1931 _, _, _, _, default, optional, _decoded = values
1940 self.assertFalse(obj.expled)
1941 obj_encoded = obj.encode()
1942 obj_expled = obj(value, expl=tag_expl)
1943 self.assertTrue(obj_expled.expled)
1946 obj_expled_encoded = obj_expled.encode()
1947 obj_decoded, tail = obj_expled.decode(
1948 obj_expled_encoded + tail_junk,
1953 self.assertEqual(tail, tail_junk)
1954 self.assertEqual(obj_decoded, obj_expled)
1955 self.assertNotEqual(obj_decoded, obj)
1956 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1957 self.assertEqual(bytes(obj_decoded), bytes(obj))
1958 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1959 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1960 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1962 obj_decoded.expl_llen,
1963 len(len_encode(len(obj_encoded))),
1965 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1966 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1969 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1971 self.assertEqual(obj_decoded.expl_offset, offset)
1974 integers(min_value=1, max_value=30),
1977 binary(min_size=1, max_size=5),
1979 binary(min_size=1, max_size=5),
1989 def test_constructed(self, impl, chunk_inputs, junk):
1990 def chunk_constructed(contents):
1992 tag_encode(form=TagFormConstructed, num=4) +
1994 b"".join(OctetString(content).encode() for content in contents) +
1998 payload_expected = b""
1999 for chunk_input in chunk_inputs:
2000 if isinstance(chunk_input, binary_type):
2001 chunks.append(OctetString(chunk_input).encode())
2002 payload_expected += chunk_input
2004 chunks.append(chunk_constructed(chunk_input))
2005 payload = b"".join(chunk_input)
2006 payload_expected += payload
2007 encoded_indefinite = (
2008 tag_encode(form=TagFormConstructed, num=impl) +
2013 encoded_definite = (
2014 tag_encode(form=TagFormConstructed, num=impl) +
2015 len_encode(len(b"".join(chunks))) +
2018 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2019 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2020 for lenindef_expected, encoded in (
2021 (True, encoded_indefinite),
2022 (False, encoded_definite),
2024 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2026 ctx={"bered": True},
2028 self.assertSequenceEqual(tail, junk)
2029 self.assertSequenceEqual(bytes(obj), payload_expected)
2030 self.assertTrue(obj.bered)
2031 self.assertEqual(obj.lenindef, lenindef_expected)
2032 self.assertEqual(len(encoded), obj.tlvlen)
2035 integers(min_value=0),
2038 def test_ber_definite_too_short(self, offset, decode_path):
2039 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2040 OctetString().decode(
2041 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2043 decode_path=decode_path,
2044 ctx={"bered": True},
2046 self.assertEqual(err.exception.decode_path, decode_path)
2047 self.assertEqual(err.exception.offset, offset)
2050 integers(min_value=0),
2052 integers(min_value=1, max_value=3),
2054 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2055 bs = OctetString(b"data").encode()
2056 with self.assertRaises(NotEnoughData) as err:
2057 OctetString().decode(
2058 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2060 decode_path=decode_path,
2061 ctx={"bered": True},
2063 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2064 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2067 integers(min_value=0),
2069 integers(min_value=1, max_value=3),
2071 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2072 bs = OctetString(b"data").encode()
2073 bs_longer = OctetString(b"data-longer").encode()
2074 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2075 OctetString().decode(
2077 tag_encode(4, form=TagFormConstructed) +
2078 len_encode((chunks + 1) * len(bs)) +
2083 decode_path=decode_path,
2084 ctx={"bered": True},
2086 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2087 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2091 def null_values_strategy(draw, do_expl=False):
2095 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2097 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2098 optional = draw(one_of(none(), booleans()))
2100 draw(integers(min_value=0)),
2101 draw(integers(min_value=0)),
2102 draw(integers(min_value=0)),
2104 return (impl, expl, optional, _decoded)
2107 class NullInherited(Null):
2111 class TestNull(CommonMixin, TestCase):
2114 def test_ready(self):
2116 self.assertTrue(obj.ready)
2120 @given(binary(), binary())
2121 def test_comparison(self, tag1, tag2):
2122 for klass in (Null, NullInherited):
2123 obj1 = klass(impl=tag1)
2124 obj2 = klass(impl=tag2)
2125 self.assertEqual(obj1 == obj2, tag1 == tag2)
2126 self.assertEqual(obj1 != obj2, tag1 != tag2)
2127 self.assertNotEqual(obj1, tag2)
2129 @given(data_strategy())
2130 def test_call(self, d):
2131 for klass in (Null, NullInherited):
2137 ) = d.draw(null_values_strategy())
2138 obj_initial = klass(
2141 optional=optional_initial or False,
2142 _decoded=_decoded_initial,
2149 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2150 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2151 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2152 self.assertEqual(obj.expl_tag, expl or expl_initial)
2153 optional = optional_initial if optional is None else optional
2154 optional = False if optional is None else optional
2155 self.assertEqual(obj.optional, optional)
2157 @given(null_values_strategy())
2158 def test_copy(self, values):
2159 for klass in (Null, NullInherited):
2160 impl, expl, optional, _decoded = values
2164 optional=optional or False,
2167 obj_copied = obj.copy()
2168 self.assert_copied_basic_fields(obj, obj_copied)
2170 @given(integers(min_value=1).map(tag_encode))
2171 def test_stripped(self, tag_impl):
2172 obj = Null(impl=tag_impl)
2173 with self.assertRaises(NotEnoughData):
2174 obj.decode(obj.encode()[:-1])
2176 @given(integers(min_value=1).map(tag_ctxc))
2177 def test_stripped_expl(self, tag_expl):
2178 obj = Null(expl=tag_expl)
2179 with self.assertRaises(NotEnoughData):
2180 obj.decode(obj.encode()[:-1])
2183 integers(min_value=31),
2184 integers(min_value=0),
2187 def test_bad_tag(self, tag, offset, decode_path):
2188 with self.assertRaises(DecodeError) as err:
2190 tag_encode(tag)[:-1],
2192 decode_path=decode_path,
2195 self.assertEqual(err.exception.offset, offset)
2196 self.assertEqual(err.exception.decode_path, decode_path)
2199 integers(min_value=128),
2200 integers(min_value=0),
2203 def test_bad_len(self, l, offset, decode_path):
2204 with self.assertRaises(DecodeError) as err:
2206 Null.tag_default + len_encode(l)[:-1],
2208 decode_path=decode_path,
2211 self.assertEqual(err.exception.offset, offset)
2212 self.assertEqual(err.exception.decode_path, decode_path)
2214 @given(binary(min_size=1))
2215 def test_tag_mismatch(self, impl):
2216 assume(impl != Null.tag_default)
2217 with self.assertRaises(TagMismatch):
2218 Null(impl=impl).decode(Null().encode())
2221 null_values_strategy(),
2222 integers(min_value=1).map(tag_ctxc),
2223 integers(min_value=0),
2226 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2227 for klass in (Null, NullInherited):
2228 _, _, optional, _decoded = values
2229 obj = klass(optional=optional, _decoded=_decoded)
2232 self.assertFalse(obj.expled)
2233 obj_encoded = obj.encode()
2234 obj_expled = obj(expl=tag_expl)
2235 self.assertTrue(obj_expled.expled)
2238 obj_expled_encoded = obj_expled.encode()
2239 obj_decoded, tail = obj_expled.decode(
2240 obj_expled_encoded + tail_junk,
2245 self.assertEqual(tail, tail_junk)
2246 self.assertEqual(obj_decoded, obj_expled)
2247 self.assertNotEqual(obj_decoded, obj)
2248 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2249 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2250 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2252 obj_decoded.expl_llen,
2253 len(len_encode(len(obj_encoded))),
2255 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2256 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2259 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2261 self.assertEqual(obj_decoded.expl_offset, offset)
2263 @given(integers(min_value=1))
2264 def test_invalid_len(self, l):
2265 with self.assertRaises(InvalidLength):
2266 Null().decode(b"".join((
2273 def oid_strategy(draw):
2274 first_arc = draw(integers(min_value=0, max_value=2))
2276 if first_arc in (0, 1):
2277 second_arc = draw(integers(min_value=0, max_value=39))
2279 second_arc = draw(integers(min_value=0))
2280 other_arcs = draw(lists(integers(min_value=0)))
2281 return tuple([first_arc, second_arc] + other_arcs)
2285 def oid_values_strategy(draw, do_expl=False):
2286 value = draw(one_of(none(), oid_strategy()))
2290 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2292 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2293 default = draw(one_of(none(), oid_strategy()))
2294 optional = draw(one_of(none(), booleans()))
2296 draw(integers(min_value=0)),
2297 draw(integers(min_value=0)),
2298 draw(integers(min_value=0)),
2300 return (value, impl, expl, default, optional, _decoded)
2303 class ObjectIdentifierInherited(ObjectIdentifier):
2307 class TestObjectIdentifier(CommonMixin, TestCase):
2308 base_klass = ObjectIdentifier
2310 def test_invalid_value_type(self):
2311 with self.assertRaises(InvalidValueType) as err:
2312 ObjectIdentifier(123)
2316 def test_optional(self, optional):
2317 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2318 self.assertTrue(obj.optional)
2320 @given(oid_strategy())
2321 def test_ready(self, value):
2322 obj = ObjectIdentifier()
2323 self.assertFalse(obj.ready)
2326 with self.assertRaises(ObjNotReady) as err:
2329 obj = ObjectIdentifier(value)
2330 self.assertTrue(obj.ready)
2335 @given(oid_strategy(), oid_strategy(), binary(), binary())
2336 def test_comparison(self, value1, value2, tag1, tag2):
2337 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2338 obj1 = klass(value1)
2339 obj2 = klass(value2)
2340 self.assertEqual(obj1 == obj2, value1 == value2)
2341 self.assertEqual(obj1 != obj2, value1 != value2)
2342 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2343 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2344 obj1 = klass(value1, impl=tag1)
2345 obj2 = klass(value1, impl=tag2)
2346 self.assertEqual(obj1 == obj2, tag1 == tag2)
2347 self.assertEqual(obj1 != obj2, tag1 != tag2)
2349 @given(lists(oid_strategy()))
2350 def test_sorted_works(self, values):
2351 self.assertSequenceEqual(
2352 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2356 @given(data_strategy())
2357 def test_call(self, d):
2358 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2366 ) = d.draw(oid_values_strategy())
2367 obj_initial = klass(
2368 value=value_initial,
2371 default=default_initial,
2372 optional=optional_initial or False,
2373 _decoded=_decoded_initial,
2382 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2391 value_expected = default if value is None else value
2393 default_initial if value_expected is None
2396 self.assertEqual(obj, value_expected)
2397 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2398 self.assertEqual(obj.expl_tag, expl or expl_initial)
2401 default_initial if default is None else default,
2403 if obj.default is None:
2404 optional = optional_initial if optional is None else optional
2405 optional = False if optional is None else optional
2408 self.assertEqual(obj.optional, optional)
2410 @given(oid_values_strategy())
2411 def test_copy(self, values):
2412 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2429 obj_copied = obj.copy()
2430 self.assert_copied_basic_fields(obj, obj_copied)
2431 self.assertEqual(obj._value, obj_copied._value)
2433 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2436 integers(min_value=1).map(tag_encode),
2438 def test_stripped(self, value, tag_impl):
2439 obj = ObjectIdentifier(value, impl=tag_impl)
2440 with self.assertRaises(NotEnoughData):
2441 obj.decode(obj.encode()[:-1])
2445 integers(min_value=1).map(tag_ctxc),
2447 def test_stripped_expl(self, value, tag_expl):
2448 obj = ObjectIdentifier(value, expl=tag_expl)
2449 with self.assertRaises(NotEnoughData):
2450 obj.decode(obj.encode()[:-1])
2453 integers(min_value=31),
2454 integers(min_value=0),
2457 def test_bad_tag(self, tag, offset, decode_path):
2458 with self.assertRaises(DecodeError) as err:
2459 ObjectIdentifier().decode(
2460 tag_encode(tag)[:-1],
2462 decode_path=decode_path,
2465 self.assertEqual(err.exception.offset, offset)
2466 self.assertEqual(err.exception.decode_path, decode_path)
2469 integers(min_value=128),
2470 integers(min_value=0),
2473 def test_bad_len(self, l, offset, decode_path):
2474 with self.assertRaises(DecodeError) as err:
2475 ObjectIdentifier().decode(
2476 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2478 decode_path=decode_path,
2481 self.assertEqual(err.exception.offset, offset)
2482 self.assertEqual(err.exception.decode_path, decode_path)
2484 def test_zero_oid(self):
2485 with self.assertRaises(NotEnoughData):
2486 ObjectIdentifier().decode(
2487 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2490 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2491 @given(oid_strategy())
2492 def test_unfinished_oid(self, value):
2493 assume(list(value)[-1] > 255)
2494 obj_encoded = ObjectIdentifier(value).encode()
2495 obj, _ = ObjectIdentifier().decode(obj_encoded)
2496 data = obj_encoded[obj.tlen + obj.llen:-1]
2498 ObjectIdentifier.tag_default,
2499 len_encode(len(data)),
2502 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2505 @given(integers(min_value=0))
2506 def test_invalid_short(self, value):
2507 with self.assertRaises(InvalidOID):
2508 ObjectIdentifier((value,))
2509 with self.assertRaises(InvalidOID):
2510 ObjectIdentifier("%d" % value)
2512 @given(integers(min_value=3), integers(min_value=0))
2513 def test_invalid_first_arc(self, first_arc, second_arc):
2514 with self.assertRaises(InvalidOID):
2515 ObjectIdentifier((first_arc, second_arc))
2516 with self.assertRaises(InvalidOID):
2517 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2519 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2520 def test_invalid_second_arc(self, first_arc, second_arc):
2521 with self.assertRaises(InvalidOID):
2522 ObjectIdentifier((first_arc, second_arc))
2523 with self.assertRaises(InvalidOID):
2524 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2526 @given(text(alphabet=ascii_letters + ".", min_size=1))
2527 def test_junk(self, oid):
2528 with self.assertRaises(InvalidOID):
2529 ObjectIdentifier(oid)
2531 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2532 @given(oid_strategy())
2533 def test_validness(self, oid):
2534 obj = ObjectIdentifier(oid)
2535 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2540 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2542 oid_values_strategy(),
2544 integers(min_value=1).map(tag_ctxc),
2545 integers(min_value=0),
2548 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2549 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2550 _, _, _, default, optional, _decoded = values
2559 self.assertFalse(obj.expled)
2560 obj_encoded = obj.encode()
2561 obj_expled = obj(value, expl=tag_expl)
2562 self.assertTrue(obj_expled.expled)
2565 obj_expled_encoded = obj_expled.encode()
2566 obj_decoded, tail = obj_expled.decode(
2567 obj_expled_encoded + tail_junk,
2572 self.assertEqual(tail, tail_junk)
2573 self.assertEqual(obj_decoded, obj_expled)
2574 self.assertNotEqual(obj_decoded, obj)
2575 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2576 self.assertEqual(tuple(obj_decoded), tuple(obj))
2577 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2578 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2579 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2581 obj_decoded.expl_llen,
2582 len(len_encode(len(obj_encoded))),
2584 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2585 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2588 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2590 self.assertEqual(obj_decoded.expl_offset, offset)
2593 oid_strategy().map(ObjectIdentifier),
2594 oid_strategy().map(ObjectIdentifier),
2596 def test_add(self, oid1, oid2):
2597 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2598 for oid_to_add in (oid2, tuple(oid2)):
2599 self.assertEqual(oid1 + oid_to_add, oid_expect)
2600 with self.assertRaises(InvalidValueType):
2603 def test_go_vectors_valid(self):
2604 for data, expect in (
2606 (b"\x55\x02", (2, 5, 2)),
2607 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2608 (b"\x81\x34\x03", (2, 100, 3)),
2611 ObjectIdentifier().decode(b"".join((
2612 ObjectIdentifier.tag_default,
2613 len_encode(len(data)),
2619 def test_go_vectors_invalid(self):
2620 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2621 with self.assertRaises(DecodeError):
2622 ObjectIdentifier().decode(b"".join((
2623 Integer.tag_default,
2624 len_encode(len(data)),
2628 def test_x690_vector(self):
2630 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2631 ObjectIdentifier((2, 999, 3)),
2636 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2638 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2639 values = list(draw(sets(
2641 min_size=len(schema),
2642 max_size=len(schema),
2644 schema = list(zip(schema, values))
2645 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2649 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2651 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2652 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2653 optional = draw(one_of(none(), booleans()))
2655 draw(integers(min_value=0)),
2656 draw(integers(min_value=0)),
2657 draw(integers(min_value=0)),
2659 return (schema, value, impl, expl, default, optional, _decoded)
2662 class TestEnumerated(CommonMixin, TestCase):
2663 class EWhatever(Enumerated):
2664 schema = (("whatever", 0),)
2666 base_klass = EWhatever
2668 def test_schema_required(self):
2669 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2672 def test_invalid_value_type(self):
2673 with self.assertRaises(InvalidValueType) as err:
2674 self.base_klass((1, 2))
2677 @given(sets(text_letters(), min_size=2))
2678 def test_unknown_name(self, schema_input):
2679 missing = schema_input.pop()
2681 class E(Enumerated):
2682 schema = [(n, 123) for n in schema_input]
2683 with self.assertRaises(ObjUnknown) as err:
2688 sets(text_letters(), min_size=2),
2689 sets(integers(), min_size=2),
2691 def test_unknown_value(self, schema_input, values_input):
2693 missing_value = values_input.pop()
2694 _input = list(zip(schema_input, values_input))
2696 class E(Enumerated):
2698 with self.assertRaises(DecodeError) as err:
2703 def test_optional(self, optional):
2704 obj = self.base_klass(default="whatever", optional=optional)
2705 self.assertTrue(obj.optional)
2707 def test_ready(self):
2708 obj = self.base_klass()
2709 self.assertFalse(obj.ready)
2712 with self.assertRaises(ObjNotReady) as err:
2715 obj = self.base_klass("whatever")
2716 self.assertTrue(obj.ready)
2720 @given(integers(), integers(), binary(), binary())
2721 def test_comparison(self, value1, value2, tag1, tag2):
2722 class E(Enumerated):
2724 ("whatever0", value1),
2725 ("whatever1", value2),
2728 class EInherited(E):
2730 for klass in (E, EInherited):
2731 obj1 = klass(value1)
2732 obj2 = klass(value2)
2733 self.assertEqual(obj1 == obj2, value1 == value2)
2734 self.assertEqual(obj1 != obj2, value1 != value2)
2735 self.assertEqual(obj1 == int(obj2), value1 == value2)
2736 obj1 = klass(value1, impl=tag1)
2737 obj2 = klass(value1, impl=tag2)
2738 self.assertEqual(obj1 == obj2, tag1 == tag2)
2739 self.assertEqual(obj1 != obj2, tag1 != tag2)
2741 @given(data_strategy())
2742 def test_call(self, d):
2751 ) = d.draw(enumerated_values_strategy())
2753 class E(Enumerated):
2754 schema = schema_initial
2756 value=value_initial,
2759 default=default_initial,
2760 optional=optional_initial or False,
2761 _decoded=_decoded_initial,
2771 ) = d.draw(enumerated_values_strategy(
2772 schema=schema_initial,
2773 do_expl=impl_initial is None,
2783 value_expected = default if value is None else value
2785 default_initial if value_expected is None
2790 dict(schema_initial).get(value_expected, value_expected),
2792 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2793 self.assertEqual(obj.expl_tag, expl or expl_initial)
2796 default_initial if default is None else default,
2798 if obj.default is None:
2799 optional = optional_initial if optional is None else optional
2800 optional = False if optional is None else optional
2803 self.assertEqual(obj.optional, optional)
2804 self.assertEqual(obj.specs, dict(schema_initial))
2806 @given(enumerated_values_strategy())
2807 def test_copy(self, values):
2808 schema_input, value, impl, expl, default, optional, _decoded = values
2810 class E(Enumerated):
2811 schema = schema_input
2820 obj_copied = obj.copy()
2821 self.assert_copied_basic_fields(obj, obj_copied)
2822 self.assertEqual(obj.specs, obj_copied.specs)
2824 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2825 @given(data_strategy())
2826 def test_symmetric(self, d):
2827 schema_input, _, _, _, default, optional, _decoded = d.draw(
2828 enumerated_values_strategy(),
2830 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2831 offset = d.draw(integers(min_value=0))
2832 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2833 tail_junk = d.draw(binary(max_size=5))
2835 class E(Enumerated):
2836 schema = schema_input
2845 self.assertFalse(obj.expled)
2846 obj_encoded = obj.encode()
2847 obj_expled = obj(value, expl=tag_expl)
2848 self.assertTrue(obj_expled.expled)
2851 obj_expled_encoded = obj_expled.encode()
2852 obj_decoded, tail = obj_expled.decode(
2853 obj_expled_encoded + tail_junk,
2858 self.assertEqual(tail, tail_junk)
2859 self.assertEqual(obj_decoded, obj_expled)
2860 self.assertNotEqual(obj_decoded, obj)
2861 self.assertEqual(int(obj_decoded), int(obj_expled))
2862 self.assertEqual(int(obj_decoded), int(obj))
2863 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2864 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2865 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2867 obj_decoded.expl_llen,
2868 len(len_encode(len(obj_encoded))),
2870 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2871 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2874 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2876 self.assertEqual(obj_decoded.expl_offset, offset)
2880 def string_values_strategy(draw, alphabet, do_expl=False):
2881 bound_min, bound_max = sorted(draw(sets(
2882 integers(min_value=0, max_value=1 << 7),
2886 value = draw(one_of(
2888 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2890 default = draw(one_of(
2892 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2895 if draw(booleans()):
2896 bounds = (bound_min, bound_max)
2900 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2902 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2903 optional = draw(one_of(none(), booleans()))
2905 draw(integers(min_value=0)),
2906 draw(integers(min_value=0)),
2907 draw(integers(min_value=0)),
2909 return (value, bounds, impl, expl, default, optional, _decoded)
2912 class StringMixin(object):
2913 def test_invalid_value_type(self):
2914 with self.assertRaises(InvalidValueType) as err:
2915 self.base_klass((1, 2))
2918 def text_alphabet(self):
2919 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2920 return printable + whitespace
2924 def test_optional(self, optional):
2925 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2926 self.assertTrue(obj.optional)
2928 @given(data_strategy())
2929 def test_ready(self, d):
2930 obj = self.base_klass()
2931 self.assertFalse(obj.ready)
2935 with self.assertRaises(ObjNotReady) as err:
2938 value = d.draw(text(alphabet=self.text_alphabet()))
2939 obj = self.base_klass(value)
2940 self.assertTrue(obj.ready)
2945 @given(data_strategy())
2946 def test_comparison(self, d):
2947 value1 = d.draw(text(alphabet=self.text_alphabet()))
2948 value2 = d.draw(text(alphabet=self.text_alphabet()))
2949 tag1 = d.draw(binary(min_size=1))
2950 tag2 = d.draw(binary(min_size=1))
2951 obj1 = self.base_klass(value1)
2952 obj2 = self.base_klass(value2)
2953 self.assertEqual(obj1 == obj2, value1 == value2)
2954 self.assertEqual(obj1 != obj2, value1 != value2)
2955 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2956 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2957 obj1 = self.base_klass(value1, impl=tag1)
2958 obj2 = self.base_klass(value1, impl=tag2)
2959 self.assertEqual(obj1 == obj2, tag1 == tag2)
2960 self.assertEqual(obj1 != obj2, tag1 != tag2)
2962 @given(data_strategy())
2963 def test_bounds_satisfied(self, d):
2964 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2965 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2966 value = d.draw(text(
2967 alphabet=self.text_alphabet(),
2971 self.base_klass(value=value, bounds=(bound_min, bound_max))
2973 @given(data_strategy())
2974 def test_bounds_unsatisfied(self, d):
2975 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2976 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2977 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2978 with self.assertRaises(BoundsError) as err:
2979 self.base_klass(value=value, bounds=(bound_min, bound_max))
2981 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2982 with self.assertRaises(BoundsError) as err:
2983 self.base_klass(value=value, bounds=(bound_min, bound_max))
2986 @given(data_strategy())
2987 def test_call(self, d):
2996 ) = d.draw(string_values_strategy(self.text_alphabet()))
2997 obj_initial = self.base_klass(
3003 optional_initial or False,
3014 ) = d.draw(string_values_strategy(
3015 self.text_alphabet(),
3016 do_expl=impl_initial is None,
3018 if (default is None) and (obj_initial.default is not None):
3021 (bounds is None) and
3022 (value is not None) and
3023 (bounds_initial is not None) and
3024 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3028 (bounds is None) and
3029 (default is not None) and
3030 (bounds_initial is not None) and
3031 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3034 obj = obj_initial(value, bounds, impl, expl, default, optional)
3036 value_expected = default if value is None else value
3038 default_initial if value_expected is None
3041 self.assertEqual(obj, value_expected)
3042 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3043 self.assertEqual(obj.expl_tag, expl or expl_initial)
3046 default_initial if default is None else default,
3048 if obj.default is None:
3049 optional = optional_initial if optional is None else optional
3050 optional = False if optional is None else optional
3053 self.assertEqual(obj.optional, optional)
3055 (obj._bound_min, obj._bound_max),
3056 bounds or bounds_initial or (0, float("+inf")),
3059 @given(data_strategy())
3060 def test_copy(self, d):
3061 values = d.draw(string_values_strategy(self.text_alphabet()))
3062 obj = self.base_klass(*values)
3063 obj_copied = obj.copy()
3064 self.assert_copied_basic_fields(obj, obj_copied)
3065 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3066 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3067 self.assertEqual(obj._value, obj_copied._value)
3069 @given(data_strategy())
3070 def test_stripped(self, d):
3071 value = d.draw(text(alphabet=self.text_alphabet()))
3072 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3073 obj = self.base_klass(value, impl=tag_impl)
3074 with self.assertRaises(NotEnoughData):
3075 obj.decode(obj.encode()[:-1])
3077 @given(data_strategy())
3078 def test_stripped_expl(self, d):
3079 value = d.draw(text(alphabet=self.text_alphabet()))
3080 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3081 obj = self.base_klass(value, expl=tag_expl)
3082 with self.assertRaises(NotEnoughData):
3083 obj.decode(obj.encode()[:-1])
3086 integers(min_value=31),
3087 integers(min_value=0),
3090 def test_bad_tag(self, tag, offset, decode_path):
3091 with self.assertRaises(DecodeError) as err:
3092 self.base_klass().decode(
3093 tag_encode(tag)[:-1],
3095 decode_path=decode_path,
3098 self.assertEqual(err.exception.offset, offset)
3099 self.assertEqual(err.exception.decode_path, decode_path)
3102 integers(min_value=128),
3103 integers(min_value=0),
3106 def test_bad_len(self, l, offset, decode_path):
3107 with self.assertRaises(DecodeError) as err:
3108 self.base_klass().decode(
3109 self.base_klass.tag_default + len_encode(l)[:-1],
3111 decode_path=decode_path,
3114 self.assertEqual(err.exception.offset, offset)
3115 self.assertEqual(err.exception.decode_path, decode_path)
3118 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3119 integers(min_value=0),
3122 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3123 value, bound_min = list(sorted(ints))
3125 class String(self.base_klass):
3126 # Multiply this value by four, to satisfy UTF-32 bounds
3127 # (4 bytes per character) validation
3128 bounds = (bound_min * 4, bound_min * 4)
3129 with self.assertRaises(DecodeError) as err:
3131 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3133 decode_path=decode_path,
3136 self.assertEqual(err.exception.offset, offset)
3137 self.assertEqual(err.exception.decode_path, decode_path)
3139 @given(data_strategy())
3140 def test_symmetric(self, d):
3141 values = d.draw(string_values_strategy(self.text_alphabet()))
3142 value = d.draw(text(alphabet=self.text_alphabet()))
3143 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3144 offset = d.draw(integers(min_value=0))
3145 tail_junk = d.draw(binary(max_size=5))
3146 _, _, _, _, default, optional, _decoded = values
3147 obj = self.base_klass(
3155 self.assertFalse(obj.expled)
3156 obj_encoded = obj.encode()
3157 obj_expled = obj(value, expl=tag_expl)
3158 self.assertTrue(obj_expled.expled)
3161 obj_expled_encoded = obj_expled.encode()
3162 obj_decoded, tail = obj_expled.decode(
3163 obj_expled_encoded + tail_junk,
3168 self.assertEqual(tail, tail_junk)
3169 self.assertEqual(obj_decoded, obj_expled)
3170 self.assertNotEqual(obj_decoded, obj)
3171 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3172 self.assertEqual(bytes(obj_decoded), bytes(obj))
3173 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3174 self.assertEqual(text_type(obj_decoded), text_type(obj))
3175 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3176 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3177 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3179 obj_decoded.expl_llen,
3180 len(len_encode(len(obj_encoded))),
3182 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3183 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3186 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3188 self.assertEqual(obj_decoded.expl_offset, offset)
3191 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3192 base_klass = UTF8String
3195 class UnicodeDecodeErrorMixin(object):
3197 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3201 def test_unicode_decode_error(self, cyrillic_text):
3202 with self.assertRaises(DecodeError):
3203 self.base_klass(cyrillic_text)
3206 class TestNumericString(StringMixin, CommonMixin, TestCase):
3207 base_klass = NumericString
3209 def text_alphabet(self):
3212 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3213 def test_non_numeric(self, cyrillic_text):
3214 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3215 self.base_klass(cyrillic_text)
3218 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3219 integers(min_value=0),
3222 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3223 value, bound_min = list(sorted(ints))
3225 class String(self.base_klass):
3226 bounds = (bound_min, bound_min)
3227 with self.assertRaises(DecodeError) as err:
3229 self.base_klass(b"1" * value).encode(),
3231 decode_path=decode_path,
3234 self.assertEqual(err.exception.offset, offset)
3235 self.assertEqual(err.exception.decode_path, decode_path)
3238 class TestPrintableString(
3239 UnicodeDecodeErrorMixin,
3244 base_klass = PrintableString
3247 class TestTeletexString(
3248 UnicodeDecodeErrorMixin,
3253 base_klass = TeletexString
3256 class TestVideotexString(
3257 UnicodeDecodeErrorMixin,
3262 base_klass = VideotexString
3265 class TestIA5String(
3266 UnicodeDecodeErrorMixin,
3271 base_klass = IA5String
3274 class TestGraphicString(
3275 UnicodeDecodeErrorMixin,
3280 base_klass = GraphicString
3283 class TestVisibleString(
3284 UnicodeDecodeErrorMixin,
3289 base_klass = VisibleString
3291 def test_x690_vector(self):
3292 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3293 self.assertSequenceEqual(tail, b"")
3294 self.assertEqual(str(obj), "Jones")
3295 self.assertFalse(obj.bered)
3296 self.assertFalse(obj.lenindef)
3298 obj, tail = VisibleString().decode(
3299 hexdec("3A0904034A6F6E04026573"),
3300 ctx={"bered": True},
3302 self.assertSequenceEqual(tail, b"")
3303 self.assertEqual(str(obj), "Jones")
3304 self.assertTrue(obj.bered)
3305 self.assertFalse(obj.lenindef)
3307 obj, tail = VisibleString().decode(
3308 hexdec("3A8004034A6F6E040265730000"),
3309 ctx={"bered": True},
3311 self.assertSequenceEqual(tail, b"")
3312 self.assertEqual(str(obj), "Jones")
3313 self.assertTrue(obj.bered)
3314 self.assertTrue(obj.lenindef)
3317 class TestGeneralString(
3318 UnicodeDecodeErrorMixin,
3323 base_klass = GeneralString
3326 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3327 base_klass = UniversalString
3330 class TestBMPString(StringMixin, CommonMixin, TestCase):
3331 base_klass = BMPString
3335 def generalized_time_values_strategy(
3343 if draw(booleans()):
3344 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3346 value = value.replace(microsecond=0)
3348 if draw(booleans()):
3349 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3351 default = default.replace(microsecond=0)
3355 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3357 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3358 optional = draw(one_of(none(), booleans()))
3360 draw(integers(min_value=0)),
3361 draw(integers(min_value=0)),
3362 draw(integers(min_value=0)),
3364 return (value, impl, expl, default, optional, _decoded)
3367 class TimeMixin(object):
3368 def test_invalid_value_type(self):
3369 with self.assertRaises(InvalidValueType) as err:
3370 self.base_klass(datetime.now().timetuple())
3373 @given(data_strategy())
3374 def test_optional(self, d):
3375 default = d.draw(datetimes(
3376 min_value=self.min_datetime,
3377 max_value=self.max_datetime,
3379 optional = d.draw(booleans())
3380 obj = self.base_klass(default=default, optional=optional)
3381 self.assertTrue(obj.optional)
3383 @given(data_strategy())
3384 def test_ready(self, d):
3385 obj = self.base_klass()
3386 self.assertFalse(obj.ready)
3389 with self.assertRaises(ObjNotReady) as err:
3392 value = d.draw(datetimes(min_value=self.min_datetime))
3393 obj = self.base_klass(value)
3394 self.assertTrue(obj.ready)
3398 @given(data_strategy())
3399 def test_comparison(self, d):
3400 value1 = d.draw(datetimes(
3401 min_value=self.min_datetime,
3402 max_value=self.max_datetime,
3404 value2 = d.draw(datetimes(
3405 min_value=self.min_datetime,
3406 max_value=self.max_datetime,
3408 tag1 = d.draw(binary(min_size=1))
3409 tag2 = d.draw(binary(min_size=1))
3411 value1 = value1.replace(microsecond=0)
3412 value2 = value2.replace(microsecond=0)
3413 obj1 = self.base_klass(value1)
3414 obj2 = self.base_klass(value2)
3415 self.assertEqual(obj1 == obj2, value1 == value2)
3416 self.assertEqual(obj1 != obj2, value1 != value2)
3417 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3418 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3419 obj1 = self.base_klass(value1, impl=tag1)
3420 obj2 = self.base_klass(value1, impl=tag2)
3421 self.assertEqual(obj1 == obj2, tag1 == tag2)
3422 self.assertEqual(obj1 != obj2, tag1 != tag2)
3424 @given(data_strategy())
3425 def test_call(self, d):
3433 ) = d.draw(generalized_time_values_strategy(
3434 min_datetime=self.min_datetime,
3435 max_datetime=self.max_datetime,
3436 omit_ms=self.omit_ms,
3438 obj_initial = self.base_klass(
3439 value=value_initial,
3442 default=default_initial,
3443 optional=optional_initial or False,
3444 _decoded=_decoded_initial,
3453 ) = d.draw(generalized_time_values_strategy(
3454 min_datetime=self.min_datetime,
3455 max_datetime=self.max_datetime,
3456 omit_ms=self.omit_ms,
3457 do_expl=impl_initial is None,
3467 value_expected = default if value is None else value
3469 default_initial if value_expected is None
3472 self.assertEqual(obj, value_expected)
3473 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3474 self.assertEqual(obj.expl_tag, expl or expl_initial)
3477 default_initial if default is None else default,
3479 if obj.default is None:
3480 optional = optional_initial if optional is None else optional
3481 optional = False if optional is None else optional
3484 self.assertEqual(obj.optional, optional)
3486 @given(data_strategy())
3487 def test_copy(self, d):
3488 values = d.draw(generalized_time_values_strategy(
3489 min_datetime=self.min_datetime,
3490 max_datetime=self.max_datetime,
3492 obj = self.base_klass(*values)
3493 obj_copied = obj.copy()
3494 self.assert_copied_basic_fields(obj, obj_copied)
3495 self.assertEqual(obj._value, obj_copied._value)
3497 @given(data_strategy())
3498 def test_stripped(self, d):
3499 value = d.draw(datetimes(
3500 min_value=self.min_datetime,
3501 max_value=self.max_datetime,
3503 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3504 obj = self.base_klass(value, impl=tag_impl)
3505 with self.assertRaises(NotEnoughData):
3506 obj.decode(obj.encode()[:-1])
3508 @given(data_strategy())
3509 def test_stripped_expl(self, d):
3510 value = d.draw(datetimes(
3511 min_value=self.min_datetime,
3512 max_value=self.max_datetime,
3514 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3515 obj = self.base_klass(value, expl=tag_expl)
3516 with self.assertRaises(NotEnoughData):
3517 obj.decode(obj.encode()[:-1])
3519 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3520 @given(data_strategy())
3521 def test_symmetric(self, d):
3522 values = d.draw(generalized_time_values_strategy(
3523 min_datetime=self.min_datetime,
3524 max_datetime=self.max_datetime,
3526 value = d.draw(datetimes(
3527 min_value=self.min_datetime,
3528 max_value=self.max_datetime,
3530 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3531 offset = d.draw(integers(min_value=0))
3532 tail_junk = d.draw(binary(max_size=5))
3533 _, _, _, default, optional, _decoded = values
3534 obj = self.base_klass(
3542 self.assertFalse(obj.expled)
3543 obj_encoded = obj.encode()
3544 obj_expled = obj(value, expl=tag_expl)
3545 self.assertTrue(obj_expled.expled)
3548 obj_expled_encoded = obj_expled.encode()
3549 obj_decoded, tail = obj_expled.decode(
3550 obj_expled_encoded + tail_junk,
3555 self.assertEqual(tail, tail_junk)
3556 self.assertEqual(obj_decoded, obj_expled)
3557 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3558 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3559 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3560 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3561 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3563 obj_decoded.expl_llen,
3564 len(len_encode(len(obj_encoded))),
3566 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3567 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3570 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3572 self.assertEqual(obj_decoded.expl_offset, offset)
3575 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3576 base_klass = GeneralizedTime
3578 min_datetime = datetime(1900, 1, 1)
3579 max_datetime = datetime(9999, 12, 31)
3581 def test_go_vectors_invalid(self):
3593 b"-20100102030410Z",
3594 b"2010-0102030410Z",
3595 b"2010-0002030410Z",
3596 b"201001-02030410Z",
3597 b"20100102-030410Z",
3598 b"2010010203-0410Z",
3599 b"201001020304-10Z",
3600 # These ones are INVALID in *DER*, but accepted
3601 # by Go's encoding/asn1
3602 b"20100102030405+0607",
3603 b"20100102030405-0607",
3605 with self.assertRaises(DecodeError) as err:
3606 GeneralizedTime(data)
3609 def test_go_vectors_valid(self):
3611 GeneralizedTime(b"20100102030405Z").todatetime(),
3612 datetime(2010, 1, 2, 3, 4, 5, 0),
3617 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3618 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3620 binary(min_size=1, max_size=1),
3622 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3623 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3626 def test_junk(self, part0, part1, part2):
3627 junk = part0 + part1 + part2
3628 assume(not (set(junk) <= set(digits.encode("ascii"))))
3629 with self.assertRaises(DecodeError):
3630 GeneralizedTime().decode(
3631 GeneralizedTime.tag_default +
3632 len_encode(len(junk)) +
3638 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3639 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3641 binary(min_size=1, max_size=1),
3643 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3644 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3647 def test_junk_dm(self, part0, part1, part2):
3648 junk = part0 + part1 + part2
3649 assume(not (set(junk) <= set(digits.encode("ascii"))))
3650 with self.assertRaises(DecodeError):
3651 GeneralizedTime().decode(
3652 GeneralizedTime.tag_default +
3653 len_encode(len(junk)) +
3658 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3659 base_klass = UTCTime
3661 min_datetime = datetime(2000, 1, 1)
3662 max_datetime = datetime(2049, 12, 31)
3664 def test_go_vectors_invalid(self):
3690 # These ones are INVALID in *DER*, but accepted
3691 # by Go's encoding/asn1
3692 b"910506164540-0700",
3693 b"910506164540+0730",
3697 with self.assertRaises(DecodeError) as err:
3701 def test_go_vectors_valid(self):
3703 UTCTime(b"910506234540Z").todatetime(),
3704 datetime(1991, 5, 6, 23, 45, 40, 0),
3707 @given(integers(min_value=0, max_value=49))
3708 def test_pre50(self, year):
3710 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3714 @given(integers(min_value=50, max_value=99))
3715 def test_post50(self, year):
3717 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3723 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3724 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3726 binary(min_size=1, max_size=1),
3728 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3729 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3732 def test_junk(self, part0, part1, part2):
3733 junk = part0 + part1 + part2
3734 assume(not (set(junk) <= set(digits.encode("ascii"))))
3735 with self.assertRaises(DecodeError):
3737 UTCTime.tag_default +
3738 len_encode(len(junk)) +
3744 def any_values_strategy(draw, do_expl=False):
3745 value = draw(one_of(none(), binary()))
3748 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3749 optional = draw(one_of(none(), booleans()))
3751 draw(integers(min_value=0)),
3752 draw(integers(min_value=0)),
3753 draw(integers(min_value=0)),
3755 return (value, expl, optional, _decoded)
3758 class AnyInherited(Any):
3762 class TestAny(CommonMixin, TestCase):
3765 def test_invalid_value_type(self):
3766 with self.assertRaises(InvalidValueType) as err:
3771 def test_optional(self, optional):
3772 obj = Any(optional=optional)
3773 self.assertEqual(obj.optional, optional)
3776 def test_ready(self, value):
3778 self.assertFalse(obj.ready)
3781 with self.assertRaises(ObjNotReady) as err:
3785 self.assertTrue(obj.ready)
3790 def test_basic(self, value):
3791 integer_encoded = Integer(value).encode()
3793 Any(integer_encoded),
3794 Any(Integer(value)),
3795 Any(Any(Integer(value))),
3797 self.assertSequenceEqual(bytes(obj), integer_encoded)
3799 obj.decode(obj.encode())[0].vlen,
3800 len(integer_encoded),
3804 self.assertSequenceEqual(obj.encode(), integer_encoded)
3806 @given(binary(), binary())
3807 def test_comparison(self, value1, value2):
3808 for klass in (Any, AnyInherited):
3809 obj1 = klass(value1)
3810 obj2 = klass(value2)
3811 self.assertEqual(obj1 == obj2, value1 == value2)
3812 self.assertEqual(obj1 != obj2, value1 != value2)
3813 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3815 @given(data_strategy())
3816 def test_call(self, d):
3817 for klass in (Any, AnyInherited):
3823 ) = d.draw(any_values_strategy())
3824 obj_initial = klass(
3827 optional_initial or False,
3835 ) = d.draw(any_values_strategy(do_expl=True))
3836 obj = obj_initial(value, expl, optional)
3838 value_expected = None if value is None else value
3839 self.assertEqual(obj, value_expected)
3840 self.assertEqual(obj.expl_tag, expl or expl_initial)
3841 if obj.default is None:
3842 optional = optional_initial if optional is None else optional
3843 optional = False if optional is None else optional
3844 self.assertEqual(obj.optional, optional)
3846 def test_simultaneous_impl_expl(self):
3847 # override it, as Any does not have implicit tag
3850 def test_decoded(self):
3851 # override it, as Any does not have implicit tag
3854 @given(any_values_strategy())
3855 def test_copy(self, values):
3856 for klass in (Any, AnyInherited):
3857 obj = klass(*values)
3858 obj_copied = obj.copy()
3859 self.assert_copied_basic_fields(obj, obj_copied)
3860 self.assertEqual(obj._value, obj_copied._value)
3862 @given(binary().map(OctetString))
3863 def test_stripped(self, value):
3865 with self.assertRaises(NotEnoughData):
3866 obj.decode(obj.encode()[:-1])
3870 integers(min_value=1).map(tag_ctxc),
3872 def test_stripped_expl(self, value, tag_expl):
3873 obj = Any(value, expl=tag_expl)
3874 with self.assertRaises(NotEnoughData):
3875 obj.decode(obj.encode()[:-1])
3878 integers(min_value=31),
3879 integers(min_value=0),
3882 def test_bad_tag(self, tag, offset, decode_path):
3883 with self.assertRaises(DecodeError) as err:
3885 tag_encode(tag)[:-1],
3887 decode_path=decode_path,
3890 self.assertEqual(err.exception.offset, offset)
3891 self.assertEqual(err.exception.decode_path, decode_path)
3894 integers(min_value=128),
3895 integers(min_value=0),
3898 def test_bad_len(self, l, offset, decode_path):
3899 with self.assertRaises(DecodeError) as err:
3901 Any.tag_default + len_encode(l)[:-1],
3903 decode_path=decode_path,
3906 self.assertEqual(err.exception.offset, offset)
3907 self.assertEqual(err.exception.decode_path, decode_path)
3909 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3911 any_values_strategy(),
3912 integers().map(lambda x: Integer(x).encode()),
3913 integers(min_value=1).map(tag_ctxc),
3914 integers(min_value=0),
3917 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3918 for klass in (Any, AnyInherited):
3919 _, _, optional, _decoded = values
3920 obj = klass(value=value, optional=optional, _decoded=_decoded)
3923 self.assertFalse(obj.expled)
3924 obj_encoded = obj.encode()
3925 obj_expled = obj(value, expl=tag_expl)
3926 self.assertTrue(obj_expled.expled)
3929 obj_expled_encoded = obj_expled.encode()
3930 obj_decoded, tail = obj_expled.decode(
3931 obj_expled_encoded + tail_junk,
3936 self.assertEqual(tail, tail_junk)
3937 self.assertEqual(obj_decoded, obj_expled)
3938 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3939 self.assertEqual(bytes(obj_decoded), bytes(obj))
3940 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3941 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3942 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3944 obj_decoded.expl_llen,
3945 len(len_encode(len(obj_encoded))),
3947 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3948 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3951 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3953 self.assertEqual(obj_decoded.expl_offset, offset)
3954 self.assertEqual(obj_decoded.tlen, 0)
3955 self.assertEqual(obj_decoded.llen, 0)
3956 self.assertEqual(obj_decoded.vlen, len(value))
3959 integers(min_value=1).map(tag_ctxc),
3960 integers(min_value=0, max_value=3),
3961 integers(min_value=0),
3965 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
3966 chunk = Boolean(False, expl=expl).encode()
3968 OctetString.tag_default +
3970 b"".join([chunk] * chunks) +
3973 obj, tail = Any().decode(
3976 decode_path=decode_path,
3977 ctx={"bered": True},
3979 self.assertSequenceEqual(tail, junk)
3980 self.assertEqual(obj.offset, offset)
3981 self.assertEqual(obj.tlvlen, len(encoded))
3982 with self.assertRaises(NotEnoughData) as err:
3986 decode_path=decode_path,
3987 ctx={"bered": True},
3989 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
3990 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
3994 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3996 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3997 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
3999 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4000 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4002 min_size=len(names),
4003 max_size=len(names),
4006 (name, Integer(**tag_kwargs))
4007 for name, tag_kwargs in zip(names, tags)
4010 if value_required or draw(booleans()):
4011 value = draw(tuples(
4012 sampled_from([name for name, _ in schema]),
4013 integers().map(Integer),
4017 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4018 default = draw(one_of(
4020 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4022 optional = draw(one_of(none(), booleans()))
4024 draw(integers(min_value=0)),
4025 draw(integers(min_value=0)),
4026 draw(integers(min_value=0)),
4028 return (schema, value, expl, default, optional, _decoded)
4031 class ChoiceInherited(Choice):
4035 class TestChoice(CommonMixin, TestCase):
4037 schema = (("whatever", Boolean()),)
4040 def test_schema_required(self):
4041 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4044 def test_impl_forbidden(self):
4045 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4046 Choice(impl=b"whatever")
4048 def test_invalid_value_type(self):
4049 with self.assertRaises(InvalidValueType) as err:
4050 self.base_klass(123)
4052 with self.assertRaises(ObjUnknown) as err:
4053 self.base_klass(("whenever", Boolean(False)))
4055 with self.assertRaises(InvalidValueType) as err:
4056 self.base_klass(("whatever", Integer(123)))
4060 def test_optional(self, optional):
4061 obj = self.base_klass(
4062 default=self.base_klass(("whatever", Boolean(False))),
4065 self.assertTrue(obj.optional)
4068 def test_ready(self, value):
4069 obj = self.base_klass()
4070 self.assertFalse(obj.ready)
4073 self.assertIsNone(obj["whatever"])
4074 with self.assertRaises(ObjNotReady) as err:
4077 obj["whatever"] = Boolean()
4078 self.assertFalse(obj.ready)
4081 obj["whatever"] = Boolean(value)
4082 self.assertTrue(obj.ready)
4086 @given(booleans(), booleans())
4087 def test_comparison(self, value1, value2):
4088 class WahlInherited(self.base_klass):
4090 for klass in (self.base_klass, WahlInherited):
4091 obj1 = klass(("whatever", Boolean(value1)))
4092 obj2 = klass(("whatever", Boolean(value2)))
4093 self.assertEqual(obj1 == obj2, value1 == value2)
4094 self.assertEqual(obj1 != obj2, value1 != value2)
4095 self.assertEqual(obj1 == obj2._value, value1 == value2)
4096 self.assertFalse(obj1 == obj2._value[1])
4098 @given(data_strategy())
4099 def test_call(self, d):
4100 for klass in (Choice, ChoiceInherited):
4108 ) = d.draw(choice_values_strategy())
4111 schema = schema_initial
4113 value=value_initial,
4115 default=default_initial,
4116 optional=optional_initial or False,
4117 _decoded=_decoded_initial,
4126 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4127 obj = obj_initial(value, expl, default, optional)
4129 value_expected = default if value is None else value
4131 default_initial if value_expected is None
4134 self.assertEqual(obj.choice, value_expected[0])
4135 self.assertEqual(obj.value, int(value_expected[1]))
4136 self.assertEqual(obj.expl_tag, expl or expl_initial)
4137 default_expect = default_initial if default is None else default
4138 if default_expect is not None:
4139 self.assertEqual(obj.default.choice, default_expect[0])
4140 self.assertEqual(obj.default.value, int(default_expect[1]))
4141 if obj.default is None:
4142 optional = optional_initial if optional is None else optional
4143 optional = False if optional is None else optional
4146 self.assertEqual(obj.optional, optional)
4147 self.assertEqual(obj.specs, obj_initial.specs)
4149 def test_simultaneous_impl_expl(self):
4150 # override it, as Any does not have implicit tag
4153 def test_decoded(self):
4154 # override it, as Any does not have implicit tag
4157 @given(choice_values_strategy())
4158 def test_copy(self, values):
4159 _schema, value, expl, default, optional, _decoded = values
4161 class Wahl(self.base_klass):
4167 optional=optional or False,
4170 obj_copied = obj.copy()
4171 self.assertIsNone(obj.tag)
4172 self.assertIsNone(obj_copied.tag)
4173 # hack for assert_copied_basic_fields
4174 obj.tag = "whatever"
4175 obj_copied.tag = "whatever"
4176 self.assert_copied_basic_fields(obj, obj_copied)
4177 self.assertEqual(obj._value, obj_copied._value)
4178 self.assertEqual(obj.specs, obj_copied.specs)
4181 def test_stripped(self, value):
4182 obj = self.base_klass(("whatever", Boolean(value)))
4183 with self.assertRaises(NotEnoughData):
4184 obj.decode(obj.encode()[:-1])
4188 integers(min_value=1).map(tag_ctxc),
4190 def test_stripped_expl(self, value, tag_expl):
4191 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4192 with self.assertRaises(NotEnoughData):
4193 obj.decode(obj.encode()[:-1])
4195 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4196 @given(data_strategy())
4197 def test_symmetric(self, d):
4198 _schema, value, _, default, optional, _decoded = d.draw(
4199 choice_values_strategy(value_required=True)
4201 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4202 offset = d.draw(integers(min_value=0))
4203 tail_junk = d.draw(binary(max_size=5))
4205 class Wahl(self.base_klass):
4215 self.assertFalse(obj.expled)
4216 obj_encoded = obj.encode()
4217 obj_expled = obj(value, expl=tag_expl)
4218 self.assertTrue(obj_expled.expled)
4221 obj_expled_encoded = obj_expled.encode()
4222 obj_decoded, tail = obj_expled.decode(
4223 obj_expled_encoded + tail_junk,
4228 self.assertEqual(tail, tail_junk)
4229 self.assertEqual(obj_decoded, obj_expled)
4230 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4231 self.assertEqual(obj_decoded.value, obj_expled.value)
4232 self.assertEqual(obj_decoded.choice, obj.choice)
4233 self.assertEqual(obj_decoded.value, obj.value)
4234 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4235 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4236 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4238 obj_decoded.expl_llen,
4239 len(len_encode(len(obj_encoded))),
4241 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4242 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4245 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4247 self.assertEqual(obj_decoded.expl_offset, offset)
4248 self.assertSequenceEqual(
4250 obj_decoded.value.fulloffset - offset:
4251 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4257 def test_set_get(self, value):
4260 ("erste", Boolean()),
4261 ("zweite", Integer()),
4264 with self.assertRaises(ObjUnknown) as err:
4265 obj["whatever"] = "whenever"
4266 with self.assertRaises(InvalidValueType) as err:
4267 obj["zweite"] = Boolean(False)
4268 obj["zweite"] = Integer(value)
4270 with self.assertRaises(ObjUnknown) as err:
4273 self.assertIsNone(obj["erste"])
4274 self.assertEqual(obj["zweite"], Integer(value))
4276 def test_tag_mismatch(self):
4279 ("erste", Boolean()),
4281 int_encoded = Integer(123).encode()
4282 bool_encoded = Boolean(False).encode()
4284 obj.decode(bool_encoded)
4285 with self.assertRaises(TagMismatch):
4286 obj.decode(int_encoded)
4288 def test_tag_mismatch_underlying(self):
4289 class SeqOfBoolean(SequenceOf):
4292 class SeqOfInteger(SequenceOf):
4297 ("erste", SeqOfBoolean()),
4300 int_encoded = SeqOfInteger((Integer(123),)).encode()
4301 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4303 obj.decode(bool_encoded)
4304 with self.assertRaises(TagMismatch) as err:
4305 obj.decode(int_encoded)
4306 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4310 def seq_values_strategy(draw, seq_klass, do_expl=False):
4312 if draw(booleans()):
4315 k: v for k, v in draw(dictionaries(
4318 booleans().map(Boolean),
4319 integers().map(Integer),
4324 if draw(booleans()):
4325 schema = list(draw(dictionaries(
4328 booleans().map(Boolean),
4329 integers().map(Integer),
4335 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4337 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4339 if draw(booleans()):
4340 default = seq_klass()
4342 k: v for k, v in draw(dictionaries(
4345 booleans().map(Boolean),
4346 integers().map(Integer),
4350 optional = draw(one_of(none(), booleans()))
4352 draw(integers(min_value=0)),
4353 draw(integers(min_value=0)),
4354 draw(integers(min_value=0)),
4356 return (value, schema, impl, expl, default, optional, _decoded)
4360 def sequence_strategy(draw, seq_klass):
4361 inputs = draw(lists(
4363 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4364 tuples(just(Integer), integers(), one_of(none(), integers())),
4369 integers(min_value=1),
4370 min_size=len(inputs),
4371 max_size=len(inputs),
4374 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4375 for tag, expled in zip(tags, draw(lists(
4377 min_size=len(inputs),
4378 max_size=len(inputs),
4382 for i, optional in enumerate(draw(lists(
4383 sampled_from(("required", "optional", "empty")),
4384 min_size=len(inputs),
4385 max_size=len(inputs),
4387 if optional in ("optional", "empty"):
4388 inits[i]["optional"] = True
4389 if optional == "empty":
4391 empties = set(empties)
4392 names = list(draw(sets(
4394 min_size=len(inputs),
4395 max_size=len(inputs),
4398 for i, (klass, value, default) in enumerate(inputs):
4399 schema.append((names[i], klass(default=default, **inits[i])))
4400 seq_name = draw(text_letters())
4401 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4404 for i, (klass, value, default) in enumerate(inputs):
4411 "default_value": None if spec.default is None else default,
4415 expect["optional"] = True
4417 expect["presented"] = True
4418 expect["value"] = value
4420 expect["optional"] = True
4421 if default is not None and default == value:
4422 expect["presented"] = False
4423 seq[name] = klass(value)
4424 expects.append(expect)
4429 def sequences_strategy(draw, seq_klass):
4430 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4432 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4433 for tag, expled in zip(tags, draw(lists(
4440 i for i, is_default in enumerate(draw(lists(
4446 names = list(draw(sets(
4451 seq_expectses = draw(lists(
4452 sequence_strategy(seq_klass=seq_klass),
4456 seqs = [seq for seq, _ in seq_expectses]
4458 for i, (name, seq) in enumerate(zip(names, seqs)):
4461 seq(default=(seq if i in defaulted else None), **inits[i]),
4463 seq_name = draw(text_letters())
4464 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4467 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4470 "expects": expects_inner,
4473 seq_outer[name] = seq_inner
4474 if seq_outer.specs[name].default is None:
4475 expect["presented"] = True
4476 expect_outers.append(expect)
4477 return seq_outer, expect_outers
4480 class SeqMixing(object):
4481 def test_invalid_value_type(self):
4482 with self.assertRaises(InvalidValueType) as err:
4483 self.base_klass(123)
4486 def test_invalid_value_type_set(self):
4487 class Seq(self.base_klass):
4488 schema = (("whatever", Boolean()),)
4490 with self.assertRaises(InvalidValueType) as err:
4491 seq["whatever"] = Integer(123)
4495 def test_optional(self, optional):
4496 obj = self.base_klass(default=self.base_klass(), optional=optional)
4497 self.assertTrue(obj.optional)
4499 @given(data_strategy())
4500 def test_ready(self, d):
4502 str(i): v for i, v in enumerate(d.draw(lists(
4509 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4516 for name in d.draw(permutations(
4517 list(ready.keys()) + list(non_ready.keys()),
4519 schema_input.append((name, Boolean()))
4521 class Seq(self.base_klass):
4522 schema = tuple(schema_input)
4524 for name in ready.keys():
4526 seq[name] = Boolean()
4527 self.assertFalse(seq.ready)
4530 for name, value in ready.items():
4531 seq[name] = Boolean(value)
4532 self.assertFalse(seq.ready)
4535 with self.assertRaises(ObjNotReady) as err:
4538 for name, value in non_ready.items():
4539 seq[name] = Boolean(value)
4540 self.assertTrue(seq.ready)
4544 @given(data_strategy())
4545 def test_call(self, d):
4546 class SeqInherited(self.base_klass):
4548 for klass in (self.base_klass, SeqInherited):
4557 ) = d.draw(seq_values_strategy(seq_klass=klass))
4558 obj_initial = klass(
4564 optional_initial or False,
4575 ) = d.draw(seq_values_strategy(
4577 do_expl=impl_initial is None,
4579 obj = obj_initial(value, impl, expl, default, optional)
4580 value_expected = default if value is None else value
4582 default_initial if value_expected is None
4585 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4586 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4587 self.assertEqual(obj.expl_tag, expl or expl_initial)
4589 {} if obj.default is None else obj.default._value,
4590 getattr(default_initial if default is None else default, "_value", {}),
4592 if obj.default is None:
4593 optional = optional_initial if optional is None else optional
4594 optional = False if optional is None else optional
4597 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4598 self.assertEqual(obj.optional, optional)
4600 @given(data_strategy())
4601 def test_copy(self, d):
4602 class SeqInherited(self.base_klass):
4604 for klass in (self.base_klass, SeqInherited):
4605 values = d.draw(seq_values_strategy(seq_klass=klass))
4606 obj = klass(*values)
4607 obj_copied = obj.copy()
4608 self.assert_copied_basic_fields(obj, obj_copied)
4609 self.assertEqual(obj.specs, obj_copied.specs)
4610 self.assertEqual(obj._value, obj_copied._value)
4612 @given(data_strategy())
4613 def test_stripped(self, d):
4614 value = d.draw(integers())
4615 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4617 class Seq(self.base_klass):
4619 schema = (("whatever", Integer()),)
4621 seq["whatever"] = Integer(value)
4622 with self.assertRaises(NotEnoughData):
4623 seq.decode(seq.encode()[:-1])
4625 @given(data_strategy())
4626 def test_stripped_expl(self, d):
4627 value = d.draw(integers())
4628 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4630 class Seq(self.base_klass):
4632 schema = (("whatever", Integer()),)
4634 seq["whatever"] = Integer(value)
4635 with self.assertRaises(NotEnoughData):
4636 seq.decode(seq.encode()[:-1])
4638 @given(binary(min_size=2))
4639 def test_non_tag_mismatch_raised(self, junk):
4641 _, _, len_encoded = tag_strip(memoryview(junk))
4642 len_decode(len_encoded)
4648 class Seq(self.base_klass):
4650 ("whatever", Integer()),
4652 ("whenever", Integer()),
4655 seq["whatever"] = Integer(123)
4656 seq["junk"] = Any(junk)
4657 seq["whenever"] = Integer(123)
4658 with self.assertRaises(DecodeError):
4659 seq.decode(seq.encode())
4662 integers(min_value=31),
4663 integers(min_value=0),
4666 def test_bad_tag(self, tag, offset, decode_path):
4667 with self.assertRaises(DecodeError) as err:
4668 self.base_klass().decode(
4669 tag_encode(tag)[:-1],
4671 decode_path=decode_path,
4674 self.assertEqual(err.exception.offset, offset)
4675 self.assertEqual(err.exception.decode_path, decode_path)
4678 integers(min_value=128),
4679 integers(min_value=0),
4682 def test_bad_len(self, l, offset, decode_path):
4683 with self.assertRaises(DecodeError) as err:
4684 self.base_klass().decode(
4685 self.base_klass.tag_default + len_encode(l)[:-1],
4687 decode_path=decode_path,
4690 self.assertEqual(err.exception.offset, offset)
4691 self.assertEqual(err.exception.decode_path, decode_path)
4693 def _assert_expects(self, seq, expects):
4694 for expect in expects:
4696 seq.specs[expect["name"]].optional,
4699 if expect["default_value"] is not None:
4701 seq.specs[expect["name"]].default,
4702 expect["default_value"],
4704 if expect["presented"]:
4705 self.assertIn(expect["name"], seq)
4706 self.assertEqual(seq[expect["name"]], expect["value"])
4708 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4709 @given(data_strategy())
4710 def test_symmetric(self, d):
4711 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4712 tail_junk = d.draw(binary(max_size=5))
4713 self.assertTrue(seq.ready)
4714 self.assertFalse(seq.decoded)
4715 self._assert_expects(seq, expects)
4718 self.assertTrue(seq.ready)
4719 seq_encoded = seq.encode()
4720 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4721 self.assertFalse(seq_decoded.lenindef)
4723 t, _, lv = tag_strip(seq_encoded)
4724 _, _, v = len_decode(lv)
4725 seq_encoded_lenindef = t + LENINDEF + v + EOC
4726 seq_decoded_lenindef, tail_lenindef = seq.decode(
4727 seq_encoded_lenindef + tail_junk,
4728 ctx={"bered": True},
4730 self.assertTrue(seq_decoded_lenindef.lenindef)
4731 with self.assertRaises(DecodeError):
4732 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4733 with self.assertRaises(DecodeError):
4734 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4735 repr(seq_decoded_lenindef)
4736 pprint(seq_decoded_lenindef)
4737 self.assertTrue(seq_decoded_lenindef.ready)
4739 for decoded, decoded_tail, encoded in (
4740 (seq_decoded, tail, seq_encoded),
4741 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4743 self.assertEqual(decoded_tail, tail_junk)
4744 self._assert_expects(decoded, expects)
4745 self.assertEqual(seq, decoded)
4746 self.assertEqual(decoded.encode(), seq_encoded)
4747 self.assertEqual(decoded.tlvlen, len(encoded))
4748 for expect in expects:
4749 if not expect["presented"]:
4750 self.assertNotIn(expect["name"], decoded)
4752 self.assertIn(expect["name"], decoded)
4753 obj = decoded[expect["name"]]
4754 self.assertTrue(obj.decoded)
4755 offset = obj.expl_offset if obj.expled else obj.offset
4756 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4757 self.assertSequenceEqual(
4758 seq_encoded[offset:offset + tlvlen],
4762 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4763 @given(data_strategy())
4764 def test_symmetric_with_seq(self, d):
4765 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4766 self.assertTrue(seq.ready)
4767 seq_encoded = seq.encode()
4768 seq_decoded, tail = seq.decode(seq_encoded)
4769 self.assertEqual(tail, b"")
4770 self.assertTrue(seq.ready)
4771 self.assertEqual(seq, seq_decoded)
4772 self.assertEqual(seq_decoded.encode(), seq_encoded)
4773 for expect_outer in expect_outers:
4774 if not expect_outer["presented"]:
4775 self.assertNotIn(expect_outer["name"], seq_decoded)
4777 self.assertIn(expect_outer["name"], seq_decoded)
4778 obj = seq_decoded[expect_outer["name"]]
4779 self.assertTrue(obj.decoded)
4780 offset = obj.expl_offset if obj.expled else obj.offset
4781 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4782 self.assertSequenceEqual(
4783 seq_encoded[offset:offset + tlvlen],
4786 self._assert_expects(obj, expect_outer["expects"])
4788 @given(data_strategy())
4789 def test_default_disappears(self, d):
4790 _schema = list(d.draw(dictionaries(
4792 sets(integers(), min_size=2, max_size=2),
4796 class Seq(self.base_klass):
4798 (n, Integer(default=d))
4799 for n, (_, d) in _schema
4802 for name, (value, _) in _schema:
4803 seq[name] = Integer(value)
4804 self.assertEqual(len(seq._value), len(_schema))
4805 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4806 self.assertGreater(len(seq.encode()), len(empty_seq))
4807 for name, (_, default) in _schema:
4808 seq[name] = Integer(default)
4809 self.assertEqual(len(seq._value), 0)
4810 self.assertSequenceEqual(seq.encode(), empty_seq)
4812 @given(data_strategy())
4813 def test_encoded_default_accepted(self, d):
4814 _schema = list(d.draw(dictionaries(
4819 tags = [tag_encode(tag) for tag in d.draw(sets(
4820 integers(min_value=0),
4821 min_size=len(_schema),
4822 max_size=len(_schema),
4825 class SeqWithoutDefault(self.base_klass):
4827 (n, Integer(impl=t))
4828 for (n, _), t in zip(_schema, tags)
4830 seq_without_default = SeqWithoutDefault()
4831 for name, value in _schema:
4832 seq_without_default[name] = Integer(value)
4833 seq_encoded = seq_without_default.encode()
4835 class SeqWithDefault(self.base_klass):
4837 (n, Integer(default=v, impl=t))
4838 for (n, v), t in zip(_schema, tags)
4840 seq_with_default = SeqWithDefault()
4841 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4842 for name, value in _schema:
4843 self.assertEqual(seq_decoded[name], seq_with_default[name])
4844 self.assertEqual(seq_decoded[name], value)
4846 @given(data_strategy())
4847 def test_missing_from_spec(self, d):
4848 names = list(d.draw(sets(text_letters(), min_size=2)))
4849 tags = [tag_encode(tag) for tag in d.draw(sets(
4850 integers(min_value=0),
4851 min_size=len(names),
4852 max_size=len(names),
4854 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4856 class SeqFull(self.base_klass):
4857 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4858 seq_full = SeqFull()
4859 for i, name in enumerate(names):
4860 seq_full[name] = Integer(i)
4861 seq_encoded = seq_full.encode()
4862 altered = names_tags[:-2] + names_tags[-1:]
4864 class SeqMissing(self.base_klass):
4865 schema = [(n, Integer(impl=t)) for n, t in altered]
4866 seq_missing = SeqMissing()
4867 with self.assertRaises(TagMismatch):
4868 seq_missing.decode(seq_encoded)
4871 class TestSequence(SeqMixing, CommonMixin, TestCase):
4872 base_klass = Sequence
4878 def test_remaining(self, value, junk):
4879 class Seq(Sequence):
4881 ("whatever", Integer()),
4883 int_encoded = Integer(value).encode()
4885 Sequence.tag_default,
4886 len_encode(len(int_encoded + junk)),
4889 with assertRaisesRegex(self, DecodeError, "remaining"):
4890 Seq().decode(junked)
4892 @given(sets(text_letters(), min_size=2))
4893 def test_obj_unknown(self, names):
4894 missing = names.pop()
4896 class Seq(Sequence):
4897 schema = [(n, Boolean()) for n in names]
4899 with self.assertRaises(ObjUnknown) as err:
4902 with self.assertRaises(ObjUnknown) as err:
4903 seq[missing] = Boolean()
4906 def test_x690_vector(self):
4907 class Seq(Sequence):
4909 ("name", IA5String()),
4912 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4913 self.assertEqual(seq["name"], "Smith")
4914 self.assertEqual(seq["ok"], True)
4917 class TestSet(SeqMixing, CommonMixin, TestCase):
4920 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4921 @given(data_strategy())
4922 def test_sorted(self, d):
4924 tag_encode(tag) for tag in
4925 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4929 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4931 for name, _ in Seq.schema:
4932 seq[name] = OctetString(b"")
4933 seq_encoded = seq.encode()
4934 seq_decoded, _ = seq.decode(seq_encoded)
4935 self.assertSequenceEqual(
4936 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4937 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4942 def seqof_values_strategy(draw, schema=None, do_expl=False):
4944 schema = draw(sampled_from((Boolean(), Integer())))
4945 bound_min, bound_max = sorted(draw(sets(
4946 integers(min_value=0, max_value=10),
4950 if isinstance(schema, Boolean):
4951 values_generator = booleans().map(Boolean)
4952 elif isinstance(schema, Integer):
4953 values_generator = integers().map(Integer)
4954 values_generator = lists(
4959 values = draw(one_of(none(), values_generator))
4963 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4965 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4966 default = draw(one_of(none(), values_generator))
4967 optional = draw(one_of(none(), booleans()))
4969 draw(integers(min_value=0)),
4970 draw(integers(min_value=0)),
4971 draw(integers(min_value=0)),
4976 (bound_min, bound_max),
4985 class SeqOfMixing(object):
4986 def test_invalid_value_type(self):
4987 with self.assertRaises(InvalidValueType) as err:
4988 self.base_klass(123)
4991 def test_invalid_values_type(self):
4992 class SeqOf(self.base_klass):
4994 with self.assertRaises(InvalidValueType) as err:
4995 SeqOf([Integer(123), Boolean(False), Integer(234)])
4998 def test_schema_required(self):
4999 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5000 self.base_klass.__mro__[1]()
5002 @given(booleans(), booleans(), binary(), binary())
5003 def test_comparison(self, value1, value2, tag1, tag2):
5004 class SeqOf(self.base_klass):
5006 obj1 = SeqOf([Boolean(value1)])
5007 obj2 = SeqOf([Boolean(value2)])
5008 self.assertEqual(obj1 == obj2, value1 == value2)
5009 self.assertEqual(obj1 != obj2, value1 != value2)
5010 self.assertEqual(obj1 == list(obj2), value1 == value2)
5011 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5012 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5013 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5014 self.assertEqual(obj1 == obj2, tag1 == tag2)
5015 self.assertEqual(obj1 != obj2, tag1 != tag2)
5017 @given(lists(booleans()))
5018 def test_iter(self, values):
5019 class SeqOf(self.base_klass):
5021 obj = SeqOf([Boolean(value) for value in values])
5022 self.assertEqual(len(obj), len(values))
5023 for i, value in enumerate(obj):
5024 self.assertEqual(value, values[i])
5026 @given(data_strategy())
5027 def test_ready(self, d):
5028 ready = [Integer(v) for v in d.draw(lists(
5035 range(d.draw(integers(min_value=1, max_value=5)))
5038 class SeqOf(self.base_klass):
5040 values = d.draw(permutations(ready + non_ready))
5042 for value in values:
5044 self.assertFalse(seqof.ready)
5047 with self.assertRaises(ObjNotReady) as err:
5050 for i, value in enumerate(values):
5051 self.assertEqual(seqof[i], value)
5052 if not seqof[i].ready:
5053 seqof[i] = Integer(i)
5054 self.assertTrue(seqof.ready)
5058 def test_spec_mismatch(self):
5059 class SeqOf(self.base_klass):
5062 seqof.append(Integer(123))
5063 with self.assertRaises(ValueError):
5064 seqof.append(Boolean(False))
5065 with self.assertRaises(ValueError):
5066 seqof[0] = Boolean(False)
5068 @given(data_strategy())
5069 def test_bounds_satisfied(self, d):
5070 class SeqOf(self.base_klass):
5072 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5073 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5074 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5075 SeqOf(value=value, bounds=(bound_min, bound_max))
5077 @given(data_strategy())
5078 def test_bounds_unsatisfied(self, d):
5079 class SeqOf(self.base_klass):
5081 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5082 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5083 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
5084 with self.assertRaises(BoundsError) as err:
5085 SeqOf(value=value, bounds=(bound_min, bound_max))
5087 value = [Boolean()] * d.draw(integers(
5088 min_value=bound_max + 1,
5089 max_value=bound_max + 10,
5091 with self.assertRaises(BoundsError) as err:
5092 SeqOf(value=value, bounds=(bound_min, bound_max))
5095 @given(integers(min_value=1, max_value=10))
5096 def test_out_of_bounds(self, bound_max):
5097 class SeqOf(self.base_klass):
5099 bounds = (0, bound_max)
5101 for _ in range(bound_max):
5102 seqof.append(Integer(123))
5103 with self.assertRaises(BoundsError):
5104 seqof.append(Integer(123))
5106 @given(data_strategy())
5107 def test_call(self, d):
5117 ) = d.draw(seqof_values_strategy())
5119 class SeqOf(self.base_klass):
5120 schema = schema_initial
5121 obj_initial = SeqOf(
5122 value=value_initial,
5123 bounds=bounds_initial,
5126 default=default_initial,
5127 optional=optional_initial or False,
5128 _decoded=_decoded_initial,
5139 ) = d.draw(seqof_values_strategy(
5140 schema=schema_initial,
5141 do_expl=impl_initial is None,
5143 if (default is None) and (obj_initial.default is not None):
5146 (bounds is None) and
5147 (value is not None) and
5148 (bounds_initial is not None) and
5149 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5153 (bounds is None) and
5154 (default is not None) and
5155 (bounds_initial is not None) and
5156 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5168 value_expected = default if value is None else value
5170 default_initial if value_expected is None
5173 value_expected = () if value_expected is None else value_expected
5174 self.assertEqual(obj, value_expected)
5175 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5176 self.assertEqual(obj.expl_tag, expl or expl_initial)
5179 default_initial if default is None else default,
5181 if obj.default is None:
5182 optional = optional_initial if optional is None else optional
5183 optional = False if optional is None else optional
5186 self.assertEqual(obj.optional, optional)
5188 (obj._bound_min, obj._bound_max),
5189 bounds or bounds_initial or (0, float("+inf")),
5192 @given(seqof_values_strategy())
5193 def test_copy(self, values):
5194 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5196 class SeqOf(self.base_klass):
5204 optional=optional or False,
5207 obj_copied = obj.copy()
5208 self.assert_copied_basic_fields(obj, obj_copied)
5209 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5210 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5211 self.assertEqual(obj._value, obj_copied._value)
5215 integers(min_value=1).map(tag_encode),
5217 def test_stripped(self, values, tag_impl):
5218 class SeqOf(self.base_klass):
5219 schema = OctetString()
5220 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5221 with self.assertRaises(NotEnoughData):
5222 obj.decode(obj.encode()[:-1])
5226 integers(min_value=1).map(tag_ctxc),
5228 def test_stripped_expl(self, values, tag_expl):
5229 class SeqOf(self.base_klass):
5230 schema = OctetString()
5231 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5232 with self.assertRaises(NotEnoughData):
5233 obj.decode(obj.encode()[:-1])
5236 integers(min_value=31),
5237 integers(min_value=0),
5240 def test_bad_tag(self, tag, offset, decode_path):
5241 with self.assertRaises(DecodeError) as err:
5242 self.base_klass().decode(
5243 tag_encode(tag)[:-1],
5245 decode_path=decode_path,
5248 self.assertEqual(err.exception.offset, offset)
5249 self.assertEqual(err.exception.decode_path, decode_path)
5252 integers(min_value=128),
5253 integers(min_value=0),
5256 def test_bad_len(self, l, offset, decode_path):
5257 with self.assertRaises(DecodeError) as err:
5258 self.base_klass().decode(
5259 self.base_klass.tag_default + len_encode(l)[:-1],
5261 decode_path=decode_path,
5264 self.assertEqual(err.exception.offset, offset)
5265 self.assertEqual(err.exception.decode_path, decode_path)
5267 @given(binary(min_size=1))
5268 def test_tag_mismatch(self, impl):
5269 assume(impl != self.base_klass.tag_default)
5270 with self.assertRaises(TagMismatch):
5271 self.base_klass(impl=impl).decode(self.base_klass().encode())
5273 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5275 seqof_values_strategy(schema=Integer()),
5276 lists(integers().map(Integer)),
5277 integers(min_value=1).map(tag_ctxc),
5278 integers(min_value=0),
5281 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5282 _, _, _, _, _, default, optional, _decoded = values
5284 class SeqOf(self.base_klass):
5294 self.assertFalse(obj.expled)
5295 obj_encoded = obj.encode()
5296 obj_expled = obj(value, expl=tag_expl)
5297 self.assertTrue(obj_expled.expled)
5300 obj_expled_encoded = obj_expled.encode()
5301 obj_decoded, tail = obj_expled.decode(
5302 obj_expled_encoded + tail_junk,
5307 self.assertEqual(tail, tail_junk)
5308 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5309 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5310 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5311 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5313 obj_decoded.expl_llen,
5314 len(len_encode(len(obj_encoded))),
5316 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5317 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5320 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5322 self.assertEqual(obj_decoded.expl_offset, offset)
5323 for obj_inner in obj_decoded:
5324 self.assertIn(obj_inner, obj_decoded)
5325 self.assertSequenceEqual(
5328 obj_inner.offset - offset:
5329 obj_inner.offset + obj_inner.tlvlen - offset
5333 t, _, lv = tag_strip(obj_encoded)
5334 _, _, v = len_decode(lv)
5335 obj_encoded_lenindef = t + LENINDEF + v + EOC
5336 obj_decoded_lenindef, tail_lenindef = obj.decode(
5337 obj_encoded_lenindef + tail_junk,
5338 ctx={"bered": True},
5340 self.assertTrue(obj_decoded_lenindef.lenindef)
5341 repr(obj_decoded_lenindef)
5342 pprint(obj_decoded_lenindef)
5343 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5344 with self.assertRaises(DecodeError):
5345 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5346 with self.assertRaises(DecodeError):
5347 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5350 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5351 class SeqOf(SequenceOf):
5355 def _test_symmetric_compare_objs(self, obj1, obj2):
5356 self.assertEqual(obj1, obj2)
5357 self.assertSequenceEqual(list(obj1), list(obj2))
5360 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5365 def _test_symmetric_compare_objs(self, obj1, obj2):
5366 self.assertSetEqual(
5367 set(int(v) for v in obj1),
5368 set(int(v) for v in obj2),
5371 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5372 @given(data_strategy())
5373 def test_sorted(self, d):
5374 values = [OctetString(v) for v in d.draw(lists(binary()))]
5377 schema = OctetString()
5379 seq_encoded = seq.encode()
5380 seq_decoded, _ = seq.decode(seq_encoded)
5381 self.assertSequenceEqual(
5382 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5383 b"".join(sorted([v.encode() for v in values])),
5387 class TestGoMarshalVectors(TestCase):
5389 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5390 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5391 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5392 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5393 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5395 class Seq(Sequence):
5397 ("erste", Integer()),
5398 ("zweite", Integer(optional=True))
5401 seq["erste"] = Integer(64)
5402 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5403 seq["erste"] = Integer(0x123456)
5404 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5405 seq["erste"] = Integer(64)
5406 seq["zweite"] = Integer(65)
5407 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5409 class NestedSeq(Sequence):
5413 seq["erste"] = Integer(127)
5414 seq["zweite"] = None
5415 nested = NestedSeq()
5416 nested["nest"] = seq
5417 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5419 self.assertSequenceEqual(
5420 OctetString(b"\x01\x02\x03").encode(),
5421 hexdec("0403010203"),
5424 class Seq(Sequence):
5426 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5429 seq["erste"] = Integer(64)
5430 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5432 class Seq(Sequence):
5434 ("erste", Integer(expl=tag_ctxc(5))),
5437 seq["erste"] = Integer(64)
5438 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5440 class Seq(Sequence):
5443 impl=tag_encode(0, klass=TagClassContext),
5448 seq["erste"] = Null()
5449 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5451 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5453 self.assertSequenceEqual(
5454 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5455 hexdec("170d3730303130313030303030305a"),
5457 self.assertSequenceEqual(
5458 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5459 hexdec("170d3039313131353232353631365a"),
5461 self.assertSequenceEqual(
5462 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5463 hexdec("180f32313030303430353132303130315a"),
5466 class Seq(Sequence):
5468 ("erste", GeneralizedTime()),
5471 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5472 self.assertSequenceEqual(
5474 hexdec("3011180f32303039313131353232353631365a"),
5477 self.assertSequenceEqual(
5478 BitString((1, b"\x80")).encode(),
5481 self.assertSequenceEqual(
5482 BitString((12, b"\x81\xF0")).encode(),
5483 hexdec("03030481f0"),
5486 self.assertSequenceEqual(
5487 ObjectIdentifier("1.2.3.4").encode(),
5488 hexdec("06032a0304"),
5490 self.assertSequenceEqual(
5491 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5492 hexdec("06092a864888932d010105"),
5494 self.assertSequenceEqual(
5495 ObjectIdentifier("2.100.3").encode(),
5496 hexdec("0603813403"),
5499 self.assertSequenceEqual(
5500 PrintableString("test").encode(),
5501 hexdec("130474657374"),
5503 self.assertSequenceEqual(
5504 PrintableString("x" * 127).encode(),
5505 hexdec("137F" + "78" * 127),
5507 self.assertSequenceEqual(
5508 PrintableString("x" * 128).encode(),
5509 hexdec("138180" + "78" * 128),
5511 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5513 class Seq(Sequence):
5515 ("erste", IA5String()),
5518 seq["erste"] = IA5String("test")
5519 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5521 class Seq(Sequence):
5523 ("erste", PrintableString()),
5526 seq["erste"] = PrintableString("test")
5527 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5528 seq["erste"] = PrintableString("test*")
5529 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5531 class Seq(Sequence):
5533 ("erste", Any(optional=True)),
5534 ("zweite", Integer()),
5537 seq["zweite"] = Integer(64)
5538 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5543 seq.append(Integer(10))
5544 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5546 class _SeqOf(SequenceOf):
5547 schema = PrintableString()
5549 class SeqOf(SequenceOf):
5552 _seqof.append(PrintableString("1"))
5554 seqof.append(_seqof)
5555 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5557 class Seq(Sequence):
5559 ("erste", Integer(default=1)),
5562 seq["erste"] = Integer(0)
5563 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5564 seq["erste"] = Integer(1)
5565 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5566 seq["erste"] = Integer(2)
5567 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5570 class TestPP(TestCase):
5571 @given(data_strategy())
5572 def test_oid_printing(self, d):
5574 str(ObjectIdentifier(k)): v * 2
5575 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5577 chosen = d.draw(sampled_from(sorted(oids)))
5578 chosen_id = oids[chosen]
5579 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5580 self.assertNotIn(chosen_id, pp_console_row(pp))
5581 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5584 class TestAutoAddSlots(TestCase):
5586 class Inher(Integer):
5589 with self.assertRaises(AttributeError):
5591 inher.unexistent = "whatever"
5594 class TestOIDDefines(TestCase):
5595 @given(data_strategy())
5596 def runTest(self, d):
5597 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5598 value_name_chosen = d.draw(sampled_from(value_names))
5600 ObjectIdentifier(oid)
5601 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5603 oid_chosen = d.draw(sampled_from(oids))
5604 values = d.draw(lists(
5606 min_size=len(value_names),
5607 max_size=len(value_names),
5610 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5611 oid: Integer() for oid in oids[:-1]
5614 for i, value_name in enumerate(value_names):
5615 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5617 class Seq(Sequence):
5620 for value_name, value in zip(value_names, values):
5621 seq[value_name] = Any(Integer(value).encode())
5622 seq["type"] = oid_chosen
5623 seq, _ = Seq().decode(seq.encode())
5624 for value_name in value_names:
5625 if value_name == value_name_chosen:
5627 self.assertIsNone(seq[value_name].defined)
5628 if value_name_chosen in oids[:-1]:
5629 self.assertIsNotNone(seq[value_name_chosen].defined)
5630 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5631 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5634 class TestDefinesByPath(TestCase):
5635 def test_generated(self):
5636 class Seq(Sequence):
5638 ("type", ObjectIdentifier()),
5639 ("value", OctetString(expl=tag_ctxc(123))),
5642 class SeqInner(Sequence):
5644 ("typeInner", ObjectIdentifier()),
5645 ("valueInner", Any()),
5648 class PairValue(SetOf):
5651 class Pair(Sequence):
5653 ("type", ObjectIdentifier()),
5654 ("value", PairValue()),
5657 class Pairs(SequenceOf):
5664 type_octet_stringed,
5666 ObjectIdentifier(oid)
5667 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5669 seq_integered = Seq()
5670 seq_integered["type"] = type_integered
5671 seq_integered["value"] = OctetString(Integer(123).encode())
5672 seq_integered_raw = seq_integered.encode()
5676 (type_octet_stringed, OctetString(b"whatever")),
5677 (type_integered, Integer(123)),
5678 (type_octet_stringed, OctetString(b"whenever")),
5679 (type_integered, Integer(234)),
5681 for t, v in pairs_input:
5684 pair["value"] = PairValue((Any(v),))
5686 seq_inner = SeqInner()
5687 seq_inner["typeInner"] = type_innered
5688 seq_inner["valueInner"] = Any(pairs)
5689 seq_sequenced = Seq()
5690 seq_sequenced["type"] = type_sequenced
5691 seq_sequenced["value"] = OctetString(seq_inner.encode())
5692 seq_sequenced_raw = seq_sequenced.encode()
5694 defines_by_path = []
5695 seq_integered, _ = Seq().decode(seq_integered_raw)
5696 self.assertIsNone(seq_integered["value"].defined)
5697 defines_by_path.append(
5698 (("type",), ((("value",), {
5699 type_integered: Integer(),
5700 type_sequenced: SeqInner(),
5703 seq_integered, _ = Seq().decode(
5705 ctx={"defines_by_path": defines_by_path},
5707 self.assertIsNotNone(seq_integered["value"].defined)
5708 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5709 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5710 self.assertTrue(seq_integered_raw[
5711 seq_integered["value"].defined[1].offset:
5712 ].startswith(Integer(123).encode()))
5714 seq_sequenced, _ = Seq().decode(
5716 ctx={"defines_by_path": defines_by_path},
5718 self.assertIsNotNone(seq_sequenced["value"].defined)
5719 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5720 seq_inner = seq_sequenced["value"].defined[1]
5721 self.assertIsNone(seq_inner["valueInner"].defined)
5723 defines_by_path.append((
5724 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5725 ((("valueInner",), {type_innered: Pairs()}),),
5727 seq_sequenced, _ = Seq().decode(
5729 ctx={"defines_by_path": defines_by_path},
5731 self.assertIsNotNone(seq_sequenced["value"].defined)
5732 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5733 seq_inner = seq_sequenced["value"].defined[1]
5734 self.assertIsNotNone(seq_inner["valueInner"].defined)
5735 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5736 pairs = seq_inner["valueInner"].defined[1]
5738 self.assertIsNone(pair["value"][0].defined)
5740 defines_by_path.append((
5743 DecodePathDefBy(type_sequenced),
5745 DecodePathDefBy(type_innered),
5750 type_integered: Integer(),
5751 type_octet_stringed: OctetString(),
5754 seq_sequenced, _ = Seq().decode(
5756 ctx={"defines_by_path": defines_by_path},
5758 self.assertIsNotNone(seq_sequenced["value"].defined)
5759 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5760 seq_inner = seq_sequenced["value"].defined[1]
5761 self.assertIsNotNone(seq_inner["valueInner"].defined)
5762 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5763 pairs_got = seq_inner["valueInner"].defined[1]
5764 for pair_input, pair_got in zip(pairs_input, pairs_got):
5765 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5766 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5768 @given(oid_strategy(), integers())
5769 def test_simple(self, oid, tgt):
5770 class Inner(Sequence):
5772 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5773 ObjectIdentifier(oid): Integer(),
5777 class Outer(Sequence):
5780 ("tgt", OctetString()),
5784 inner["oid"] = ObjectIdentifier(oid)
5786 outer["inner"] = inner
5787 outer["tgt"] = OctetString(Integer(tgt).encode())
5788 decoded, _ = Outer().decode(outer.encode())
5789 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5792 class TestAbsDecodePath(TestCase):
5794 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5795 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5797 def test_concat(self, decode_path, rel_path):
5798 self.assertSequenceEqual(
5799 abs_decode_path(decode_path, rel_path),
5800 decode_path + rel_path,
5804 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5805 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5807 def test_abs(self, decode_path, rel_path):
5808 self.assertSequenceEqual(
5809 abs_decode_path(decode_path, ("/",) + rel_path),
5814 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5815 integers(min_value=1, max_value=3),
5816 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5818 def test_dots(self, decode_path, number_of_dots, rel_path):
5819 self.assertSequenceEqual(
5820 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5821 decode_path[:-number_of_dots] + rel_path,
5825 class TestStrictDefaultExistence(TestCase):
5826 @given(data_strategy())
5827 def runTest(self, d):
5828 count = d.draw(integers(min_value=1, max_value=10))
5829 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5831 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5832 for i in range(count)
5835 class Seq(Sequence):
5838 for i in range(count):
5839 seq["int%d" % i] = Integer(123)
5841 chosen = "int%d" % chosen
5842 seq.specs[chosen] = seq.specs[chosen](default=123)
5844 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5845 seq.decode(raw, ctx={"strict_default_existence": True})
5848 class TestX690PrefixedType(TestCase):
5850 self.assertSequenceEqual(
5851 VisibleString("Jones").encode(),
5852 hexdec("1A054A6F6E6573"),
5854 self.assertSequenceEqual(
5857 impl=tag_encode(3, klass=TagClassApplication),
5859 hexdec("43054A6F6E6573"),
5861 self.assertSequenceEqual(
5865 impl=tag_encode(3, klass=TagClassApplication),
5869 hexdec("A20743054A6F6E6573"),
5871 self.assertSequenceEqual(
5875 impl=tag_encode(3, klass=TagClassApplication),
5877 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5879 hexdec("670743054A6F6E6573"),
5881 self.assertSequenceEqual(
5882 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5883 hexdec("82054A6F6E6573"),