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 assertRaisesRegex(self, DecodeError, "bounds") as err:
813 Integer(bounds=(values[1], values[2])).decode(
814 Integer(values[0]).encode()
817 with self.assertRaises(BoundsError) as err:
818 Integer(value=values[2], bounds=(values[0], values[1]))
820 with assertRaisesRegex(self, DecodeError, "bounds") as err:
821 Integer(bounds=(values[0], values[1])).decode(
822 Integer(values[2]).encode()
826 @given(data_strategy())
827 def test_call(self, d):
828 for klass in (Integer, IntegerInherited):
838 ) = d.draw(integer_values_strategy())
845 optional_initial or False,
858 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
859 if (default is None) and (obj_initial.default is not None):
863 (value is not None) and
864 (bounds_initial is not None) and
865 not (bounds_initial[0] <= value <= bounds_initial[1])
870 (default is not None) and
871 (bounds_initial is not None) and
872 not (bounds_initial[0] <= default <= bounds_initial[1])
875 obj = obj_initial(value, bounds, impl, expl, default, optional)
877 value_expected = default if value is None else value
879 default_initial if value_expected is None
882 self.assertEqual(obj, value_expected)
883 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
884 self.assertEqual(obj.expl_tag, expl or expl_initial)
887 default_initial if default is None else default,
889 if obj.default is None:
890 optional = optional_initial if optional is None else optional
891 optional = False if optional is None else optional
894 self.assertEqual(obj.optional, optional)
896 (obj._bound_min, obj._bound_max),
897 bounds or bounds_initial or (float("-inf"), float("+inf")),
901 {} if _specs_initial is None else dict(_specs_initial),
904 @given(integer_values_strategy())
905 def test_copy(self, values):
906 for klass in (Integer, IntegerInherited):
908 obj_copied = obj.copy()
909 self.assert_copied_basic_fields(obj, obj_copied)
910 self.assertEqual(obj.specs, obj_copied.specs)
911 self.assertEqual(obj._bound_min, obj_copied._bound_min)
912 self.assertEqual(obj._bound_max, obj_copied._bound_max)
913 self.assertEqual(obj._value, obj_copied._value)
917 integers(min_value=1).map(tag_encode),
919 def test_stripped(self, value, tag_impl):
920 obj = Integer(value, impl=tag_impl)
921 with self.assertRaises(NotEnoughData):
922 obj.decode(obj.encode()[:-1])
926 integers(min_value=1).map(tag_ctxc),
928 def test_stripped_expl(self, value, tag_expl):
929 obj = Integer(value, expl=tag_expl)
930 with self.assertRaises(NotEnoughData):
931 obj.decode(obj.encode()[:-1])
933 def test_zero_len(self):
934 with self.assertRaises(NotEnoughData):
935 Integer().decode(b"".join((
941 integers(min_value=31),
942 integers(min_value=0),
945 def test_bad_tag(self, tag, offset, decode_path):
946 with self.assertRaises(DecodeError) as err:
948 tag_encode(tag)[:-1],
950 decode_path=decode_path,
953 self.assertEqual(err.exception.offset, offset)
954 self.assertEqual(err.exception.decode_path, decode_path)
957 integers(min_value=128),
958 integers(min_value=0),
961 def test_bad_len(self, l, offset, decode_path):
962 with self.assertRaises(DecodeError) as err:
964 Integer.tag_default + len_encode(l)[:-1],
966 decode_path=decode_path,
969 self.assertEqual(err.exception.offset, offset)
970 self.assertEqual(err.exception.decode_path, decode_path)
973 sets(integers(), min_size=2, max_size=2),
974 integers(min_value=0),
977 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
978 value, bound_min = list(sorted(ints))
981 bounds = (bound_min, bound_min)
982 with self.assertRaises(DecodeError) as err:
984 Integer(value).encode(),
986 decode_path=decode_path,
989 self.assertEqual(err.exception.offset, offset)
990 self.assertEqual(err.exception.decode_path, decode_path)
992 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
994 integer_values_strategy(),
996 integers(min_value=1).map(tag_ctxc),
997 integers(min_value=0),
1000 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1001 for klass in (Integer, IntegerInherited):
1002 _, _, _, _, default, optional, _, _decoded = values
1011 self.assertFalse(obj.expled)
1012 obj_encoded = obj.encode()
1013 obj_expled = obj(value, expl=tag_expl)
1014 self.assertTrue(obj_expled.expled)
1017 obj_expled_encoded = obj_expled.encode()
1018 obj_decoded, tail = obj_expled.decode(
1019 obj_expled_encoded + tail_junk,
1024 self.assertEqual(tail, tail_junk)
1025 self.assertEqual(obj_decoded, obj_expled)
1026 self.assertNotEqual(obj_decoded, obj)
1027 self.assertEqual(int(obj_decoded), int(obj_expled))
1028 self.assertEqual(int(obj_decoded), int(obj))
1029 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1030 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1031 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1033 obj_decoded.expl_llen,
1034 len(len_encode(len(obj_encoded))),
1036 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1037 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1040 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1042 self.assertEqual(obj_decoded.expl_offset, offset)
1044 def test_go_vectors_valid(self):
1045 for data, expect in ((
1049 (b"\xff\x7f", -129),
1053 (b"\xff\x00", -256),
1057 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1058 (b"\x80\x00\x00\x00", -2147483648),
1061 Integer().decode(b"".join((
1062 Integer.tag_default,
1063 len_encode(len(data)),
1069 def test_go_vectors_invalid(self):
1074 with self.assertRaises(DecodeError):
1075 Integer().decode(b"".join((
1076 Integer.tag_default,
1077 len_encode(len(data)),
1083 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1086 if draw(booleans()):
1087 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1089 integers(min_value=0, max_value=255),
1090 min_size=len(schema),
1091 max_size=len(schema),
1093 schema = list(zip(schema, bits))
1095 def _value(value_required):
1096 if not value_required and draw(booleans()):
1098 generation_choice = 0
1100 generation_choice = draw(sampled_from((1, 2, 3)))
1101 if generation_choice == 1 or draw(booleans()):
1102 return "'%s'B" % "".join(draw(lists(
1103 sampled_from(("0", "1")),
1104 max_size=len(schema),
1106 elif generation_choice == 2 or draw(booleans()):
1107 return draw(binary(max_size=len(schema) // 8))
1108 elif generation_choice == 3 or draw(booleans()):
1109 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1111 value = _value(value_required)
1112 default = _value(value_required=False)
1116 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1118 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1119 optional = draw(one_of(none(), booleans()))
1121 draw(integers(min_value=0)),
1122 draw(integers(min_value=0)),
1123 draw(integers(min_value=0)),
1125 return (schema, value, impl, expl, default, optional, _decoded)
1128 class BitStringInherited(BitString):
1132 class TestBitString(CommonMixin, TestCase):
1133 base_klass = BitString
1135 @given(lists(booleans()))
1136 def test_b_encoding(self, bits):
1137 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1138 self.assertEqual(obj.bit_len, len(bits))
1139 self.assertSequenceEqual(list(obj), bits)
1140 for i, bit in enumerate(bits):
1141 self.assertEqual(obj[i], bit)
1143 @given(lists(booleans()))
1144 def test_out_of_bounds_bits(self, bits):
1145 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1146 for i in range(len(bits), len(bits) * 2):
1147 self.assertFalse(obj[i])
1149 def test_bad_b_encoding(self):
1150 with self.assertRaises(ValueError):
1151 BitString("'010120101'B")
1154 integers(min_value=1, max_value=255),
1155 integers(min_value=1, max_value=255),
1157 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1158 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1159 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1160 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1162 class BS(BitString):
1163 schema = (("whatever", 0),)
1164 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1165 self.assertEqual(obj.bit_len, leading_zeros + 1)
1166 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1168 def test_zero_len(self):
1169 with self.assertRaises(NotEnoughData):
1170 BitString().decode(b"".join((
1171 BitString.tag_default,
1175 def test_invalid_value_type(self):
1176 with self.assertRaises(InvalidValueType) as err:
1179 with self.assertRaises(InvalidValueType) as err:
1183 def test_obj_unknown(self):
1184 with self.assertRaises(ObjUnknown) as err:
1185 BitString(b"whatever")["whenever"]
1188 def test_get_invalid_type(self):
1189 with self.assertRaises(InvalidValueType) as err:
1190 BitString(b"whatever")[(1, 2, 3)]
1193 @given(data_strategy())
1194 def test_unknown_name(self, d):
1195 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1196 missing = _schema.pop()
1198 class BS(BitString):
1199 schema = [(n, i) for i, n in enumerate(_schema)]
1200 with self.assertRaises(ObjUnknown) as err:
1205 def test_optional(self, optional):
1206 obj = BitString(default=BitString(b""), optional=optional)
1207 self.assertTrue(obj.optional)
1210 def test_ready(self, value):
1212 self.assertFalse(obj.ready)
1215 with self.assertRaises(ObjNotReady) as err:
1218 obj = BitString(value)
1219 self.assertTrue(obj.ready)
1224 tuples(integers(min_value=0), binary()),
1225 tuples(integers(min_value=0), binary()),
1229 def test_comparison(self, value1, value2, tag1, tag2):
1230 for klass in (BitString, BitStringInherited):
1231 obj1 = klass(value1)
1232 obj2 = klass(value2)
1233 self.assertEqual(obj1 == obj2, value1 == value2)
1234 self.assertEqual(obj1 != obj2, value1 != value2)
1235 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1236 obj1 = klass(value1, impl=tag1)
1237 obj2 = klass(value1, impl=tag2)
1238 self.assertEqual(obj1 == obj2, tag1 == tag2)
1239 self.assertEqual(obj1 != obj2, tag1 != tag2)
1241 @given(data_strategy())
1242 def test_call(self, d):
1243 for klass in (BitString, BitStringInherited):
1252 ) = d.draw(bit_string_values_strategy())
1255 schema = schema_initial
1257 value=value_initial,
1260 default=default_initial,
1261 optional=optional_initial or False,
1262 _decoded=_decoded_initial,
1272 ) = d.draw(bit_string_values_strategy(
1273 schema=schema_initial,
1274 do_expl=impl_initial is None,
1283 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1284 self.assertEqual(obj.expl_tag, expl or expl_initial)
1285 if obj.default is None:
1286 optional = optional_initial if optional is None else optional
1287 optional = False if optional is None else optional
1290 self.assertEqual(obj.optional, optional)
1291 self.assertEqual(obj.specs, obj_initial.specs)
1293 @given(bit_string_values_strategy())
1294 def test_copy(self, values):
1295 for klass in (BitString, BitStringInherited):
1296 _schema, value, impl, expl, default, optional, _decoded = values
1305 optional=optional or False,
1308 obj_copied = obj.copy()
1309 self.assert_copied_basic_fields(obj, obj_copied)
1310 self.assertEqual(obj.specs, obj_copied.specs)
1311 self.assertEqual(obj._value, obj_copied._value)
1315 integers(min_value=1).map(tag_encode),
1317 def test_stripped(self, value, tag_impl):
1318 obj = BitString(value, impl=tag_impl)
1319 with self.assertRaises(NotEnoughData):
1320 obj.decode(obj.encode()[:-1])
1324 integers(min_value=1).map(tag_ctxc),
1326 def test_stripped_expl(self, value, tag_expl):
1327 obj = BitString(value, expl=tag_expl)
1328 with self.assertRaises(NotEnoughData):
1329 obj.decode(obj.encode()[:-1])
1332 integers(min_value=31),
1333 integers(min_value=0),
1336 def test_bad_tag(self, tag, offset, decode_path):
1337 with self.assertRaises(DecodeError) as err:
1339 tag_encode(tag)[:-1],
1341 decode_path=decode_path,
1344 self.assertEqual(err.exception.offset, offset)
1345 self.assertEqual(err.exception.decode_path, decode_path)
1348 integers(min_value=128),
1349 integers(min_value=0),
1352 def test_bad_len(self, l, offset, decode_path):
1353 with self.assertRaises(DecodeError) as err:
1355 BitString.tag_default + len_encode(l)[:-1],
1357 decode_path=decode_path,
1360 self.assertEqual(err.exception.offset, offset)
1361 self.assertEqual(err.exception.decode_path, decode_path)
1363 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1364 @given(data_strategy())
1365 def test_symmetric(self, d):
1374 ) = d.draw(bit_string_values_strategy(value_required=True))
1375 tail_junk = d.draw(binary(max_size=5))
1376 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1377 offset = d.draw(integers(min_value=0))
1378 for klass in (BitString, BitStringInherited):
1389 self.assertFalse(obj.expled)
1390 obj_encoded = obj.encode()
1391 obj_expled = obj(value, expl=tag_expl)
1392 self.assertTrue(obj_expled.expled)
1395 obj_expled_encoded = obj_expled.encode()
1396 obj_decoded, tail = obj_expled.decode(
1397 obj_expled_encoded + tail_junk,
1402 self.assertEqual(tail, tail_junk)
1403 self.assertEqual(obj_decoded, obj_expled)
1404 self.assertNotEqual(obj_decoded, obj)
1405 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1406 self.assertEqual(bytes(obj_decoded), bytes(obj))
1407 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1408 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1409 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1411 obj_decoded.expl_llen,
1412 len(len_encode(len(obj_encoded))),
1414 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1415 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1418 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1420 self.assertEqual(obj_decoded.expl_offset, offset)
1421 if isinstance(value, tuple):
1422 self.assertSetEqual(set(value), set(obj_decoded.named))
1426 @given(integers(min_value=1, max_value=255))
1427 def test_bad_zero_value(self, pad_size):
1428 with self.assertRaises(DecodeError):
1429 BitString().decode(b"".join((
1430 BitString.tag_default,
1435 def test_go_vectors_invalid(self):
1441 with self.assertRaises(DecodeError):
1442 BitString().decode(b"".join((
1443 BitString.tag_default,
1448 def test_go_vectors_valid(self):
1449 obj, _ = BitString().decode(b"".join((
1450 BitString.tag_default,
1454 self.assertEqual(bytes(obj), b"")
1455 self.assertEqual(obj.bit_len, 0)
1457 obj, _ = BitString().decode(b"".join((
1458 BitString.tag_default,
1462 self.assertEqual(bytes(obj), b"\x00")
1463 self.assertEqual(obj.bit_len, 1)
1465 obj = BitString((16, b"\x82\x40"))
1466 self.assertTrue(obj[0])
1467 self.assertFalse(obj[1])
1468 self.assertTrue(obj[6])
1469 self.assertTrue(obj[9])
1470 self.assertFalse(obj[17])
1473 integers(min_value=1, max_value=30),
1476 binary(min_size=1, max_size=5),
1478 binary(min_size=1, max_size=5),
1486 lists(booleans(), min_size=1),
1489 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1490 def chunk_constructed(contents):
1492 tag_encode(form=TagFormConstructed, num=3) +
1494 b"".join(BitString(content).encode() for content in contents) +
1498 payload_expected = b""
1499 bit_len_expected = 0
1500 for chunk_input in chunk_inputs:
1501 if isinstance(chunk_input, binary_type):
1502 chunks.append(BitString(chunk_input).encode())
1503 payload_expected += chunk_input
1504 bit_len_expected += len(chunk_input) * 8
1506 chunks.append(chunk_constructed(chunk_input))
1507 payload = b"".join(chunk_input)
1508 payload_expected += payload
1509 bit_len_expected += len(payload) * 8
1510 chunk_last = BitString("'%s'B" % "".join(
1511 "1" if bit else "0" for bit in chunk_last_bits
1513 payload_expected += bytes(chunk_last)
1514 bit_len_expected += chunk_last.bit_len
1515 encoded_indefinite = (
1516 tag_encode(form=TagFormConstructed, num=impl) +
1519 chunk_last.encode() +
1522 encoded_definite = (
1523 tag_encode(form=TagFormConstructed, num=impl) +
1524 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1528 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1529 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1530 for lenindef_expected, encoded in (
1531 (True, encoded_indefinite),
1532 (False, encoded_definite),
1534 obj, tail = BitString(impl=tag_encode(impl)).decode(
1536 ctx={"bered": True},
1538 self.assertSequenceEqual(tail, junk)
1539 self.assertEqual(obj.bit_len, bit_len_expected)
1540 self.assertSequenceEqual(bytes(obj), payload_expected)
1541 self.assertTrue(obj.bered)
1542 self.assertEqual(obj.lenindef, lenindef_expected)
1543 self.assertEqual(len(encoded), obj.tlvlen)
1546 integers(min_value=0),
1549 def test_ber_definite_too_short(self, offset, decode_path):
1550 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1552 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1554 decode_path=decode_path,
1555 ctx={"bered": True},
1557 self.assertEqual(err.exception.decode_path, decode_path)
1558 self.assertEqual(err.exception.offset, offset)
1561 integers(min_value=0),
1564 def test_ber_definite_no_data(self, offset, decode_path):
1565 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1567 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1569 decode_path=decode_path,
1570 ctx={"bered": True},
1572 self.assertEqual(err.exception.decode_path, decode_path)
1573 self.assertEqual(err.exception.offset, offset)
1576 integers(min_value=0),
1578 integers(min_value=1, max_value=3),
1580 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1581 bs = BitString(b"data").encode()
1582 with self.assertRaises(NotEnoughData) as err:
1584 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1586 decode_path=decode_path,
1587 ctx={"bered": True},
1589 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1590 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1593 integers(min_value=0),
1595 integers(min_value=1, max_value=3),
1597 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1598 bs = BitString(b"data").encode()
1599 bs_longer = BitString(b"data-longer").encode()
1600 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1603 tag_encode(3, form=TagFormConstructed) +
1604 len_encode((chunks + 1) * len(bs)) +
1609 decode_path=decode_path,
1610 ctx={"bered": True},
1612 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1613 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1616 integers(min_value=0),
1619 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1620 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1622 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1624 decode_path=decode_path,
1625 ctx={"bered": True},
1627 self.assertEqual(err.exception.decode_path, decode_path)
1628 self.assertEqual(err.exception.offset, offset)
1630 @given(data_strategy())
1631 def test_ber_indefinite_not_multiple(self, d):
1632 bs_short = BitString("'A'H").encode()
1633 bs_full = BitString("'AA'H").encode()
1634 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1635 chunks.append(bs_short)
1636 d.draw(permutations(chunks))
1637 chunks.append(bs_short)
1638 offset = d.draw(integers(min_value=0))
1639 decode_path = d.draw(decode_path_strat)
1640 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1643 tag_encode(3, form=TagFormConstructed) +
1649 decode_path=decode_path,
1650 ctx={"bered": True},
1653 err.exception.decode_path,
1654 decode_path + (str(chunks.index(bs_short)),),
1657 err.exception.offset,
1658 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1661 def test_x690_vector(self):
1662 vector = BitString("'0A3B5F291CD'H")
1663 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1664 self.assertSequenceEqual(tail, b"")
1665 self.assertEqual(obj, vector)
1666 obj, tail = BitString().decode(
1667 hexdec("23800303000A3B0305045F291CD00000"),
1668 ctx={"bered": True},
1670 self.assertSequenceEqual(tail, b"")
1671 self.assertEqual(obj, vector)
1672 self.assertTrue(obj.bered)
1673 self.assertTrue(obj.lenindef)
1677 def octet_string_values_strategy(draw, do_expl=False):
1678 bound_min, bound_max = sorted(draw(sets(
1679 integers(min_value=0, max_value=1 << 7),
1683 value = draw(one_of(
1685 binary(min_size=bound_min, max_size=bound_max),
1687 default = draw(one_of(
1689 binary(min_size=bound_min, max_size=bound_max),
1692 if draw(booleans()):
1693 bounds = (bound_min, bound_max)
1697 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1699 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1700 optional = draw(one_of(none(), booleans()))
1702 draw(integers(min_value=0)),
1703 draw(integers(min_value=0)),
1704 draw(integers(min_value=0)),
1706 return (value, bounds, impl, expl, default, optional, _decoded)
1709 class OctetStringInherited(OctetString):
1713 class TestOctetString(CommonMixin, TestCase):
1714 base_klass = OctetString
1716 def test_invalid_value_type(self):
1717 with self.assertRaises(InvalidValueType) as err:
1718 OctetString(text_type(123))
1722 def test_optional(self, optional):
1723 obj = OctetString(default=OctetString(b""), optional=optional)
1724 self.assertTrue(obj.optional)
1727 def test_ready(self, value):
1729 self.assertFalse(obj.ready)
1732 with self.assertRaises(ObjNotReady) as err:
1735 obj = OctetString(value)
1736 self.assertTrue(obj.ready)
1740 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1741 def test_comparison(self, value1, value2, tag1, tag2):
1742 for klass in (OctetString, OctetStringInherited):
1743 obj1 = klass(value1)
1744 obj2 = klass(value2)
1745 self.assertEqual(obj1 == obj2, value1 == value2)
1746 self.assertEqual(obj1 != obj2, value1 != value2)
1747 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1748 obj1 = klass(value1, impl=tag1)
1749 obj2 = klass(value1, impl=tag2)
1750 self.assertEqual(obj1 == obj2, tag1 == tag2)
1751 self.assertEqual(obj1 != obj2, tag1 != tag2)
1753 @given(lists(binary()))
1754 def test_sorted_works(self, values):
1755 self.assertSequenceEqual(
1756 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1760 @given(data_strategy())
1761 def test_bounds_satisfied(self, d):
1762 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1763 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1764 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1765 OctetString(value=value, bounds=(bound_min, bound_max))
1767 @given(data_strategy())
1768 def test_bounds_unsatisfied(self, d):
1769 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1770 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1771 value = d.draw(binary(max_size=bound_min - 1))
1772 with self.assertRaises(BoundsError) as err:
1773 OctetString(value=value, bounds=(bound_min, bound_max))
1775 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1776 OctetString(bounds=(bound_min, bound_max)).decode(
1777 OctetString(value).encode()
1780 value = d.draw(binary(min_size=bound_max + 1))
1781 with self.assertRaises(BoundsError) as err:
1782 OctetString(value=value, bounds=(bound_min, bound_max))
1784 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1785 OctetString(bounds=(bound_min, bound_max)).decode(
1786 OctetString(value).encode()
1790 @given(data_strategy())
1791 def test_call(self, d):
1792 for klass in (OctetString, OctetStringInherited):
1801 ) = d.draw(octet_string_values_strategy())
1802 obj_initial = klass(
1808 optional_initial or False,
1819 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1820 if (default is None) and (obj_initial.default is not None):
1823 (bounds is None) and
1824 (value is not None) and
1825 (bounds_initial is not None) and
1826 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1830 (bounds is None) and
1831 (default is not None) and
1832 (bounds_initial is not None) and
1833 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1836 obj = obj_initial(value, bounds, impl, expl, default, optional)
1838 value_expected = default if value is None else value
1840 default_initial if value_expected is None
1843 self.assertEqual(obj, value_expected)
1844 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1845 self.assertEqual(obj.expl_tag, expl or expl_initial)
1848 default_initial if default is None else default,
1850 if obj.default is None:
1851 optional = optional_initial if optional is None else optional
1852 optional = False if optional is None else optional
1855 self.assertEqual(obj.optional, optional)
1857 (obj._bound_min, obj._bound_max),
1858 bounds or bounds_initial or (0, float("+inf")),
1861 @given(octet_string_values_strategy())
1862 def test_copy(self, values):
1863 for klass in (OctetString, OctetStringInherited):
1864 obj = klass(*values)
1865 obj_copied = obj.copy()
1866 self.assert_copied_basic_fields(obj, obj_copied)
1867 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1868 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1869 self.assertEqual(obj._value, obj_copied._value)
1873 integers(min_value=1).map(tag_encode),
1875 def test_stripped(self, value, tag_impl):
1876 obj = OctetString(value, impl=tag_impl)
1877 with self.assertRaises(NotEnoughData):
1878 obj.decode(obj.encode()[:-1])
1882 integers(min_value=1).map(tag_ctxc),
1884 def test_stripped_expl(self, value, tag_expl):
1885 obj = OctetString(value, expl=tag_expl)
1886 with self.assertRaises(NotEnoughData):
1887 obj.decode(obj.encode()[:-1])
1890 integers(min_value=31),
1891 integers(min_value=0),
1894 def test_bad_tag(self, tag, offset, decode_path):
1895 with self.assertRaises(DecodeError) as err:
1896 OctetString().decode(
1897 tag_encode(tag)[:-1],
1899 decode_path=decode_path,
1902 self.assertEqual(err.exception.offset, offset)
1903 self.assertEqual(err.exception.decode_path, decode_path)
1906 integers(min_value=128),
1907 integers(min_value=0),
1910 def test_bad_len(self, l, offset, decode_path):
1911 with self.assertRaises(DecodeError) as err:
1912 OctetString().decode(
1913 OctetString.tag_default + len_encode(l)[:-1],
1915 decode_path=decode_path,
1918 self.assertEqual(err.exception.offset, offset)
1919 self.assertEqual(err.exception.decode_path, decode_path)
1922 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1923 integers(min_value=0),
1926 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1927 value, bound_min = list(sorted(ints))
1929 class String(OctetString):
1930 bounds = (bound_min, bound_min)
1931 with self.assertRaises(DecodeError) as err:
1933 OctetString(b"\x00" * value).encode(),
1935 decode_path=decode_path,
1938 self.assertEqual(err.exception.offset, offset)
1939 self.assertEqual(err.exception.decode_path, decode_path)
1941 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1943 octet_string_values_strategy(),
1945 integers(min_value=1).map(tag_ctxc),
1946 integers(min_value=0),
1949 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1950 for klass in (OctetString, OctetStringInherited):
1951 _, _, _, _, default, optional, _decoded = values
1960 self.assertFalse(obj.expled)
1961 obj_encoded = obj.encode()
1962 obj_expled = obj(value, expl=tag_expl)
1963 self.assertTrue(obj_expled.expled)
1966 obj_expled_encoded = obj_expled.encode()
1967 obj_decoded, tail = obj_expled.decode(
1968 obj_expled_encoded + tail_junk,
1973 self.assertEqual(tail, tail_junk)
1974 self.assertEqual(obj_decoded, obj_expled)
1975 self.assertNotEqual(obj_decoded, obj)
1976 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1977 self.assertEqual(bytes(obj_decoded), bytes(obj))
1978 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1979 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1980 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1982 obj_decoded.expl_llen,
1983 len(len_encode(len(obj_encoded))),
1985 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1986 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1989 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1991 self.assertEqual(obj_decoded.expl_offset, offset)
1994 integers(min_value=1, max_value=30),
1997 binary(min_size=1, max_size=5),
1999 binary(min_size=1, max_size=5),
2009 def test_constructed(self, impl, chunk_inputs, junk):
2010 def chunk_constructed(contents):
2012 tag_encode(form=TagFormConstructed, num=4) +
2014 b"".join(OctetString(content).encode() for content in contents) +
2018 payload_expected = b""
2019 for chunk_input in chunk_inputs:
2020 if isinstance(chunk_input, binary_type):
2021 chunks.append(OctetString(chunk_input).encode())
2022 payload_expected += chunk_input
2024 chunks.append(chunk_constructed(chunk_input))
2025 payload = b"".join(chunk_input)
2026 payload_expected += payload
2027 encoded_indefinite = (
2028 tag_encode(form=TagFormConstructed, num=impl) +
2033 encoded_definite = (
2034 tag_encode(form=TagFormConstructed, num=impl) +
2035 len_encode(len(b"".join(chunks))) +
2038 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2039 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2040 for lenindef_expected, encoded in (
2041 (True, encoded_indefinite),
2042 (False, encoded_definite),
2044 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2046 ctx={"bered": True},
2048 self.assertSequenceEqual(tail, junk)
2049 self.assertSequenceEqual(bytes(obj), payload_expected)
2050 self.assertTrue(obj.bered)
2051 self.assertEqual(obj.lenindef, lenindef_expected)
2052 self.assertEqual(len(encoded), obj.tlvlen)
2055 integers(min_value=0),
2058 def test_ber_definite_too_short(self, offset, decode_path):
2059 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2060 OctetString().decode(
2061 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2063 decode_path=decode_path,
2064 ctx={"bered": True},
2066 self.assertEqual(err.exception.decode_path, decode_path)
2067 self.assertEqual(err.exception.offset, offset)
2070 integers(min_value=0),
2072 integers(min_value=1, max_value=3),
2074 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2075 bs = OctetString(b"data").encode()
2076 with self.assertRaises(NotEnoughData) as err:
2077 OctetString().decode(
2078 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2080 decode_path=decode_path,
2081 ctx={"bered": True},
2083 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2084 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2087 integers(min_value=0),
2089 integers(min_value=1, max_value=3),
2091 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2092 bs = OctetString(b"data").encode()
2093 bs_longer = OctetString(b"data-longer").encode()
2094 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2095 OctetString().decode(
2097 tag_encode(4, form=TagFormConstructed) +
2098 len_encode((chunks + 1) * len(bs)) +
2103 decode_path=decode_path,
2104 ctx={"bered": True},
2106 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2107 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2111 def null_values_strategy(draw, do_expl=False):
2115 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2117 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2118 optional = draw(one_of(none(), booleans()))
2120 draw(integers(min_value=0)),
2121 draw(integers(min_value=0)),
2122 draw(integers(min_value=0)),
2124 return (impl, expl, optional, _decoded)
2127 class NullInherited(Null):
2131 class TestNull(CommonMixin, TestCase):
2134 def test_ready(self):
2136 self.assertTrue(obj.ready)
2140 @given(binary(), binary())
2141 def test_comparison(self, tag1, tag2):
2142 for klass in (Null, NullInherited):
2143 obj1 = klass(impl=tag1)
2144 obj2 = klass(impl=tag2)
2145 self.assertEqual(obj1 == obj2, tag1 == tag2)
2146 self.assertEqual(obj1 != obj2, tag1 != tag2)
2147 self.assertNotEqual(obj1, tag2)
2149 @given(data_strategy())
2150 def test_call(self, d):
2151 for klass in (Null, NullInherited):
2157 ) = d.draw(null_values_strategy())
2158 obj_initial = klass(
2161 optional=optional_initial or False,
2162 _decoded=_decoded_initial,
2169 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2170 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2171 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2172 self.assertEqual(obj.expl_tag, expl or expl_initial)
2173 optional = optional_initial if optional is None else optional
2174 optional = False if optional is None else optional
2175 self.assertEqual(obj.optional, optional)
2177 @given(null_values_strategy())
2178 def test_copy(self, values):
2179 for klass in (Null, NullInherited):
2180 impl, expl, optional, _decoded = values
2184 optional=optional or False,
2187 obj_copied = obj.copy()
2188 self.assert_copied_basic_fields(obj, obj_copied)
2190 @given(integers(min_value=1).map(tag_encode))
2191 def test_stripped(self, tag_impl):
2192 obj = Null(impl=tag_impl)
2193 with self.assertRaises(NotEnoughData):
2194 obj.decode(obj.encode()[:-1])
2196 @given(integers(min_value=1).map(tag_ctxc))
2197 def test_stripped_expl(self, tag_expl):
2198 obj = Null(expl=tag_expl)
2199 with self.assertRaises(NotEnoughData):
2200 obj.decode(obj.encode()[:-1])
2203 integers(min_value=31),
2204 integers(min_value=0),
2207 def test_bad_tag(self, tag, offset, decode_path):
2208 with self.assertRaises(DecodeError) as err:
2210 tag_encode(tag)[:-1],
2212 decode_path=decode_path,
2215 self.assertEqual(err.exception.offset, offset)
2216 self.assertEqual(err.exception.decode_path, decode_path)
2219 integers(min_value=128),
2220 integers(min_value=0),
2223 def test_bad_len(self, l, offset, decode_path):
2224 with self.assertRaises(DecodeError) as err:
2226 Null.tag_default + len_encode(l)[:-1],
2228 decode_path=decode_path,
2231 self.assertEqual(err.exception.offset, offset)
2232 self.assertEqual(err.exception.decode_path, decode_path)
2234 @given(binary(min_size=1))
2235 def test_tag_mismatch(self, impl):
2236 assume(impl != Null.tag_default)
2237 with self.assertRaises(TagMismatch):
2238 Null(impl=impl).decode(Null().encode())
2241 null_values_strategy(),
2242 integers(min_value=1).map(tag_ctxc),
2243 integers(min_value=0),
2246 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2247 for klass in (Null, NullInherited):
2248 _, _, optional, _decoded = values
2249 obj = klass(optional=optional, _decoded=_decoded)
2252 self.assertFalse(obj.expled)
2253 obj_encoded = obj.encode()
2254 obj_expled = obj(expl=tag_expl)
2255 self.assertTrue(obj_expled.expled)
2258 obj_expled_encoded = obj_expled.encode()
2259 obj_decoded, tail = obj_expled.decode(
2260 obj_expled_encoded + tail_junk,
2265 self.assertEqual(tail, tail_junk)
2266 self.assertEqual(obj_decoded, obj_expled)
2267 self.assertNotEqual(obj_decoded, obj)
2268 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2269 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2270 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2272 obj_decoded.expl_llen,
2273 len(len_encode(len(obj_encoded))),
2275 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2276 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2279 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2281 self.assertEqual(obj_decoded.expl_offset, offset)
2283 @given(integers(min_value=1))
2284 def test_invalid_len(self, l):
2285 with self.assertRaises(InvalidLength):
2286 Null().decode(b"".join((
2293 def oid_strategy(draw):
2294 first_arc = draw(integers(min_value=0, max_value=2))
2296 if first_arc in (0, 1):
2297 second_arc = draw(integers(min_value=0, max_value=39))
2299 second_arc = draw(integers(min_value=0))
2300 other_arcs = draw(lists(integers(min_value=0)))
2301 return tuple([first_arc, second_arc] + other_arcs)
2305 def oid_values_strategy(draw, do_expl=False):
2306 value = draw(one_of(none(), oid_strategy()))
2310 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2312 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2313 default = draw(one_of(none(), oid_strategy()))
2314 optional = draw(one_of(none(), booleans()))
2316 draw(integers(min_value=0)),
2317 draw(integers(min_value=0)),
2318 draw(integers(min_value=0)),
2320 return (value, impl, expl, default, optional, _decoded)
2323 class ObjectIdentifierInherited(ObjectIdentifier):
2327 class TestObjectIdentifier(CommonMixin, TestCase):
2328 base_klass = ObjectIdentifier
2330 def test_invalid_value_type(self):
2331 with self.assertRaises(InvalidValueType) as err:
2332 ObjectIdentifier(123)
2336 def test_optional(self, optional):
2337 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2338 self.assertTrue(obj.optional)
2340 @given(oid_strategy())
2341 def test_ready(self, value):
2342 obj = ObjectIdentifier()
2343 self.assertFalse(obj.ready)
2346 with self.assertRaises(ObjNotReady) as err:
2349 obj = ObjectIdentifier(value)
2350 self.assertTrue(obj.ready)
2355 @given(oid_strategy(), oid_strategy(), binary(), binary())
2356 def test_comparison(self, value1, value2, tag1, tag2):
2357 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2358 obj1 = klass(value1)
2359 obj2 = klass(value2)
2360 self.assertEqual(obj1 == obj2, value1 == value2)
2361 self.assertEqual(obj1 != obj2, value1 != value2)
2362 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2363 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2364 obj1 = klass(value1, impl=tag1)
2365 obj2 = klass(value1, impl=tag2)
2366 self.assertEqual(obj1 == obj2, tag1 == tag2)
2367 self.assertEqual(obj1 != obj2, tag1 != tag2)
2369 @given(lists(oid_strategy()))
2370 def test_sorted_works(self, values):
2371 self.assertSequenceEqual(
2372 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2376 @given(data_strategy())
2377 def test_call(self, d):
2378 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2386 ) = d.draw(oid_values_strategy())
2387 obj_initial = klass(
2388 value=value_initial,
2391 default=default_initial,
2392 optional=optional_initial or False,
2393 _decoded=_decoded_initial,
2402 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2411 value_expected = default if value is None else value
2413 default_initial if value_expected is None
2416 self.assertEqual(obj, value_expected)
2417 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2418 self.assertEqual(obj.expl_tag, expl or expl_initial)
2421 default_initial if default is None else default,
2423 if obj.default is None:
2424 optional = optional_initial if optional is None else optional
2425 optional = False if optional is None else optional
2428 self.assertEqual(obj.optional, optional)
2430 @given(oid_values_strategy())
2431 def test_copy(self, values):
2432 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2449 obj_copied = obj.copy()
2450 self.assert_copied_basic_fields(obj, obj_copied)
2451 self.assertEqual(obj._value, obj_copied._value)
2453 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2456 integers(min_value=1).map(tag_encode),
2458 def test_stripped(self, value, tag_impl):
2459 obj = ObjectIdentifier(value, impl=tag_impl)
2460 with self.assertRaises(NotEnoughData):
2461 obj.decode(obj.encode()[:-1])
2465 integers(min_value=1).map(tag_ctxc),
2467 def test_stripped_expl(self, value, tag_expl):
2468 obj = ObjectIdentifier(value, expl=tag_expl)
2469 with self.assertRaises(NotEnoughData):
2470 obj.decode(obj.encode()[:-1])
2473 integers(min_value=31),
2474 integers(min_value=0),
2477 def test_bad_tag(self, tag, offset, decode_path):
2478 with self.assertRaises(DecodeError) as err:
2479 ObjectIdentifier().decode(
2480 tag_encode(tag)[:-1],
2482 decode_path=decode_path,
2485 self.assertEqual(err.exception.offset, offset)
2486 self.assertEqual(err.exception.decode_path, decode_path)
2489 integers(min_value=128),
2490 integers(min_value=0),
2493 def test_bad_len(self, l, offset, decode_path):
2494 with self.assertRaises(DecodeError) as err:
2495 ObjectIdentifier().decode(
2496 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2498 decode_path=decode_path,
2501 self.assertEqual(err.exception.offset, offset)
2502 self.assertEqual(err.exception.decode_path, decode_path)
2504 def test_zero_oid(self):
2505 with self.assertRaises(NotEnoughData):
2506 ObjectIdentifier().decode(
2507 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2510 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2511 @given(oid_strategy())
2512 def test_unfinished_oid(self, value):
2513 assume(list(value)[-1] > 255)
2514 obj_encoded = ObjectIdentifier(value).encode()
2515 obj, _ = ObjectIdentifier().decode(obj_encoded)
2516 data = obj_encoded[obj.tlen + obj.llen:-1]
2518 ObjectIdentifier.tag_default,
2519 len_encode(len(data)),
2522 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2525 @given(integers(min_value=0))
2526 def test_invalid_short(self, value):
2527 with self.assertRaises(InvalidOID):
2528 ObjectIdentifier((value,))
2529 with self.assertRaises(InvalidOID):
2530 ObjectIdentifier("%d" % value)
2532 @given(integers(min_value=3), integers(min_value=0))
2533 def test_invalid_first_arc(self, first_arc, second_arc):
2534 with self.assertRaises(InvalidOID):
2535 ObjectIdentifier((first_arc, second_arc))
2536 with self.assertRaises(InvalidOID):
2537 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2539 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2540 def test_invalid_second_arc(self, first_arc, second_arc):
2541 with self.assertRaises(InvalidOID):
2542 ObjectIdentifier((first_arc, second_arc))
2543 with self.assertRaises(InvalidOID):
2544 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2546 @given(text(alphabet=ascii_letters + ".", min_size=1))
2547 def test_junk(self, oid):
2548 with self.assertRaises(InvalidOID):
2549 ObjectIdentifier(oid)
2551 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2552 @given(oid_strategy())
2553 def test_validness(self, oid):
2554 obj = ObjectIdentifier(oid)
2555 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2560 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2562 oid_values_strategy(),
2564 integers(min_value=1).map(tag_ctxc),
2565 integers(min_value=0),
2568 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2569 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2570 _, _, _, default, optional, _decoded = values
2579 self.assertFalse(obj.expled)
2580 obj_encoded = obj.encode()
2581 obj_expled = obj(value, expl=tag_expl)
2582 self.assertTrue(obj_expled.expled)
2585 obj_expled_encoded = obj_expled.encode()
2586 obj_decoded, tail = obj_expled.decode(
2587 obj_expled_encoded + tail_junk,
2592 self.assertEqual(tail, tail_junk)
2593 self.assertEqual(obj_decoded, obj_expled)
2594 self.assertNotEqual(obj_decoded, obj)
2595 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2596 self.assertEqual(tuple(obj_decoded), tuple(obj))
2597 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2598 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2599 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2601 obj_decoded.expl_llen,
2602 len(len_encode(len(obj_encoded))),
2604 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2605 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2608 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2610 self.assertEqual(obj_decoded.expl_offset, offset)
2613 oid_strategy().map(ObjectIdentifier),
2614 oid_strategy().map(ObjectIdentifier),
2616 def test_add(self, oid1, oid2):
2617 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2618 for oid_to_add in (oid2, tuple(oid2)):
2619 self.assertEqual(oid1 + oid_to_add, oid_expect)
2620 with self.assertRaises(InvalidValueType):
2623 def test_go_vectors_valid(self):
2624 for data, expect in (
2626 (b"\x55\x02", (2, 5, 2)),
2627 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2628 (b"\x81\x34\x03", (2, 100, 3)),
2631 ObjectIdentifier().decode(b"".join((
2632 ObjectIdentifier.tag_default,
2633 len_encode(len(data)),
2639 def test_go_vectors_invalid(self):
2640 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2641 with self.assertRaises(DecodeError):
2642 ObjectIdentifier().decode(b"".join((
2643 Integer.tag_default,
2644 len_encode(len(data)),
2648 def test_x690_vector(self):
2650 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2651 ObjectIdentifier((2, 999, 3)),
2656 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2658 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2659 values = list(draw(sets(
2661 min_size=len(schema),
2662 max_size=len(schema),
2664 schema = list(zip(schema, values))
2665 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2669 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2671 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2672 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2673 optional = draw(one_of(none(), booleans()))
2675 draw(integers(min_value=0)),
2676 draw(integers(min_value=0)),
2677 draw(integers(min_value=0)),
2679 return (schema, value, impl, expl, default, optional, _decoded)
2682 class TestEnumerated(CommonMixin, TestCase):
2683 class EWhatever(Enumerated):
2684 schema = (("whatever", 0),)
2686 base_klass = EWhatever
2688 def test_schema_required(self):
2689 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2692 def test_invalid_value_type(self):
2693 with self.assertRaises(InvalidValueType) as err:
2694 self.base_klass((1, 2))
2697 @given(sets(text_letters(), min_size=2))
2698 def test_unknown_name(self, schema_input):
2699 missing = schema_input.pop()
2701 class E(Enumerated):
2702 schema = [(n, 123) for n in schema_input]
2703 with self.assertRaises(ObjUnknown) as err:
2708 sets(text_letters(), min_size=2),
2709 sets(integers(), min_size=2),
2711 def test_unknown_value(self, schema_input, values_input):
2713 missing_value = values_input.pop()
2714 _input = list(zip(schema_input, values_input))
2716 class E(Enumerated):
2718 with self.assertRaises(DecodeError) as err:
2723 def test_optional(self, optional):
2724 obj = self.base_klass(default="whatever", optional=optional)
2725 self.assertTrue(obj.optional)
2727 def test_ready(self):
2728 obj = self.base_klass()
2729 self.assertFalse(obj.ready)
2732 with self.assertRaises(ObjNotReady) as err:
2735 obj = self.base_klass("whatever")
2736 self.assertTrue(obj.ready)
2740 @given(integers(), integers(), binary(), binary())
2741 def test_comparison(self, value1, value2, tag1, tag2):
2742 class E(Enumerated):
2744 ("whatever0", value1),
2745 ("whatever1", value2),
2748 class EInherited(E):
2750 for klass in (E, EInherited):
2751 obj1 = klass(value1)
2752 obj2 = klass(value2)
2753 self.assertEqual(obj1 == obj2, value1 == value2)
2754 self.assertEqual(obj1 != obj2, value1 != value2)
2755 self.assertEqual(obj1 == int(obj2), value1 == value2)
2756 obj1 = klass(value1, impl=tag1)
2757 obj2 = klass(value1, impl=tag2)
2758 self.assertEqual(obj1 == obj2, tag1 == tag2)
2759 self.assertEqual(obj1 != obj2, tag1 != tag2)
2761 @given(data_strategy())
2762 def test_call(self, d):
2771 ) = d.draw(enumerated_values_strategy())
2773 class E(Enumerated):
2774 schema = schema_initial
2776 value=value_initial,
2779 default=default_initial,
2780 optional=optional_initial or False,
2781 _decoded=_decoded_initial,
2791 ) = d.draw(enumerated_values_strategy(
2792 schema=schema_initial,
2793 do_expl=impl_initial is None,
2803 value_expected = default if value is None else value
2805 default_initial if value_expected is None
2810 dict(schema_initial).get(value_expected, value_expected),
2812 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2813 self.assertEqual(obj.expl_tag, expl or expl_initial)
2816 default_initial if default is None else default,
2818 if obj.default is None:
2819 optional = optional_initial if optional is None else optional
2820 optional = False if optional is None else optional
2823 self.assertEqual(obj.optional, optional)
2824 self.assertEqual(obj.specs, dict(schema_initial))
2826 @given(enumerated_values_strategy())
2827 def test_copy(self, values):
2828 schema_input, value, impl, expl, default, optional, _decoded = values
2830 class E(Enumerated):
2831 schema = schema_input
2840 obj_copied = obj.copy()
2841 self.assert_copied_basic_fields(obj, obj_copied)
2842 self.assertEqual(obj.specs, obj_copied.specs)
2844 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2845 @given(data_strategy())
2846 def test_symmetric(self, d):
2847 schema_input, _, _, _, default, optional, _decoded = d.draw(
2848 enumerated_values_strategy(),
2850 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2851 offset = d.draw(integers(min_value=0))
2852 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2853 tail_junk = d.draw(binary(max_size=5))
2855 class E(Enumerated):
2856 schema = schema_input
2865 self.assertFalse(obj.expled)
2866 obj_encoded = obj.encode()
2867 obj_expled = obj(value, expl=tag_expl)
2868 self.assertTrue(obj_expled.expled)
2871 obj_expled_encoded = obj_expled.encode()
2872 obj_decoded, tail = obj_expled.decode(
2873 obj_expled_encoded + tail_junk,
2878 self.assertEqual(tail, tail_junk)
2879 self.assertEqual(obj_decoded, obj_expled)
2880 self.assertNotEqual(obj_decoded, obj)
2881 self.assertEqual(int(obj_decoded), int(obj_expled))
2882 self.assertEqual(int(obj_decoded), int(obj))
2883 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2884 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2885 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2887 obj_decoded.expl_llen,
2888 len(len_encode(len(obj_encoded))),
2890 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2891 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2894 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2896 self.assertEqual(obj_decoded.expl_offset, offset)
2900 def string_values_strategy(draw, alphabet, do_expl=False):
2901 bound_min, bound_max = sorted(draw(sets(
2902 integers(min_value=0, max_value=1 << 7),
2906 value = draw(one_of(
2908 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2910 default = draw(one_of(
2912 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2915 if draw(booleans()):
2916 bounds = (bound_min, bound_max)
2920 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2922 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2923 optional = draw(one_of(none(), booleans()))
2925 draw(integers(min_value=0)),
2926 draw(integers(min_value=0)),
2927 draw(integers(min_value=0)),
2929 return (value, bounds, impl, expl, default, optional, _decoded)
2932 class StringMixin(object):
2933 def test_invalid_value_type(self):
2934 with self.assertRaises(InvalidValueType) as err:
2935 self.base_klass((1, 2))
2938 def text_alphabet(self):
2939 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2940 return printable + whitespace
2944 def test_optional(self, optional):
2945 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2946 self.assertTrue(obj.optional)
2948 @given(data_strategy())
2949 def test_ready(self, d):
2950 obj = self.base_klass()
2951 self.assertFalse(obj.ready)
2955 with self.assertRaises(ObjNotReady) as err:
2958 value = d.draw(text(alphabet=self.text_alphabet()))
2959 obj = self.base_klass(value)
2960 self.assertTrue(obj.ready)
2965 @given(data_strategy())
2966 def test_comparison(self, d):
2967 value1 = d.draw(text(alphabet=self.text_alphabet()))
2968 value2 = d.draw(text(alphabet=self.text_alphabet()))
2969 tag1 = d.draw(binary(min_size=1))
2970 tag2 = d.draw(binary(min_size=1))
2971 obj1 = self.base_klass(value1)
2972 obj2 = self.base_klass(value2)
2973 self.assertEqual(obj1 == obj2, value1 == value2)
2974 self.assertEqual(obj1 != obj2, value1 != value2)
2975 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2976 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2977 obj1 = self.base_klass(value1, impl=tag1)
2978 obj2 = self.base_klass(value1, impl=tag2)
2979 self.assertEqual(obj1 == obj2, tag1 == tag2)
2980 self.assertEqual(obj1 != obj2, tag1 != tag2)
2982 @given(data_strategy())
2983 def test_bounds_satisfied(self, d):
2984 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2985 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2986 value = d.draw(text(
2987 alphabet=self.text_alphabet(),
2991 self.base_klass(value=value, bounds=(bound_min, bound_max))
2993 @given(data_strategy())
2994 def test_bounds_unsatisfied(self, d):
2995 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2996 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2997 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2998 with self.assertRaises(BoundsError) as err:
2999 self.base_klass(value=value, bounds=(bound_min, bound_max))
3001 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3002 self.base_klass(bounds=(bound_min, bound_max)).decode(
3003 self.base_klass(value).encode()
3006 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3007 with self.assertRaises(BoundsError) as err:
3008 self.base_klass(value=value, bounds=(bound_min, bound_max))
3010 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3011 self.base_klass(bounds=(bound_min, bound_max)).decode(
3012 self.base_klass(value).encode()
3016 @given(data_strategy())
3017 def test_call(self, d):
3026 ) = d.draw(string_values_strategy(self.text_alphabet()))
3027 obj_initial = self.base_klass(
3033 optional_initial or False,
3044 ) = d.draw(string_values_strategy(
3045 self.text_alphabet(),
3046 do_expl=impl_initial is None,
3048 if (default is None) and (obj_initial.default is not None):
3051 (bounds is None) and
3052 (value is not None) and
3053 (bounds_initial is not None) and
3054 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3058 (bounds is None) and
3059 (default is not None) and
3060 (bounds_initial is not None) and
3061 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3064 obj = obj_initial(value, bounds, impl, expl, default, optional)
3066 value_expected = default if value is None else value
3068 default_initial if value_expected is None
3071 self.assertEqual(obj, value_expected)
3072 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3073 self.assertEqual(obj.expl_tag, expl or expl_initial)
3076 default_initial if default is None else default,
3078 if obj.default is None:
3079 optional = optional_initial if optional is None else optional
3080 optional = False if optional is None else optional
3083 self.assertEqual(obj.optional, optional)
3085 (obj._bound_min, obj._bound_max),
3086 bounds or bounds_initial or (0, float("+inf")),
3089 @given(data_strategy())
3090 def test_copy(self, d):
3091 values = d.draw(string_values_strategy(self.text_alphabet()))
3092 obj = self.base_klass(*values)
3093 obj_copied = obj.copy()
3094 self.assert_copied_basic_fields(obj, obj_copied)
3095 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3096 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3097 self.assertEqual(obj._value, obj_copied._value)
3099 @given(data_strategy())
3100 def test_stripped(self, d):
3101 value = d.draw(text(alphabet=self.text_alphabet()))
3102 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3103 obj = self.base_klass(value, impl=tag_impl)
3104 with self.assertRaises(NotEnoughData):
3105 obj.decode(obj.encode()[:-1])
3107 @given(data_strategy())
3108 def test_stripped_expl(self, d):
3109 value = d.draw(text(alphabet=self.text_alphabet()))
3110 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3111 obj = self.base_klass(value, expl=tag_expl)
3112 with self.assertRaises(NotEnoughData):
3113 obj.decode(obj.encode()[:-1])
3116 integers(min_value=31),
3117 integers(min_value=0),
3120 def test_bad_tag(self, tag, offset, decode_path):
3121 with self.assertRaises(DecodeError) as err:
3122 self.base_klass().decode(
3123 tag_encode(tag)[:-1],
3125 decode_path=decode_path,
3128 self.assertEqual(err.exception.offset, offset)
3129 self.assertEqual(err.exception.decode_path, decode_path)
3132 integers(min_value=128),
3133 integers(min_value=0),
3136 def test_bad_len(self, l, offset, decode_path):
3137 with self.assertRaises(DecodeError) as err:
3138 self.base_klass().decode(
3139 self.base_klass.tag_default + len_encode(l)[:-1],
3141 decode_path=decode_path,
3144 self.assertEqual(err.exception.offset, offset)
3145 self.assertEqual(err.exception.decode_path, decode_path)
3148 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3149 integers(min_value=0),
3152 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3153 value, bound_min = list(sorted(ints))
3155 class String(self.base_klass):
3156 # Multiply this value by four, to satisfy UTF-32 bounds
3157 # (4 bytes per character) validation
3158 bounds = (bound_min * 4, bound_min * 4)
3159 with self.assertRaises(DecodeError) as err:
3161 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3163 decode_path=decode_path,
3166 self.assertEqual(err.exception.offset, offset)
3167 self.assertEqual(err.exception.decode_path, decode_path)
3169 @given(data_strategy())
3170 def test_symmetric(self, d):
3171 values = d.draw(string_values_strategy(self.text_alphabet()))
3172 value = d.draw(text(alphabet=self.text_alphabet()))
3173 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3174 offset = d.draw(integers(min_value=0))
3175 tail_junk = d.draw(binary(max_size=5))
3176 _, _, _, _, default, optional, _decoded = values
3177 obj = self.base_klass(
3185 self.assertFalse(obj.expled)
3186 obj_encoded = obj.encode()
3187 obj_expled = obj(value, expl=tag_expl)
3188 self.assertTrue(obj_expled.expled)
3191 obj_expled_encoded = obj_expled.encode()
3192 obj_decoded, tail = obj_expled.decode(
3193 obj_expled_encoded + tail_junk,
3198 self.assertEqual(tail, tail_junk)
3199 self.assertEqual(obj_decoded, obj_expled)
3200 self.assertNotEqual(obj_decoded, obj)
3201 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3202 self.assertEqual(bytes(obj_decoded), bytes(obj))
3203 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3204 self.assertEqual(text_type(obj_decoded), text_type(obj))
3205 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3206 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3207 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3209 obj_decoded.expl_llen,
3210 len(len_encode(len(obj_encoded))),
3212 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3213 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3216 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3218 self.assertEqual(obj_decoded.expl_offset, offset)
3221 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3222 base_klass = UTF8String
3225 class UnicodeDecodeErrorMixin(object):
3227 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3231 def test_unicode_decode_error(self, cyrillic_text):
3232 with self.assertRaises(DecodeError):
3233 self.base_klass(cyrillic_text)
3236 class TestNumericString(StringMixin, CommonMixin, TestCase):
3237 base_klass = NumericString
3239 def text_alphabet(self):
3242 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3243 def test_non_numeric(self, cyrillic_text):
3244 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3245 self.base_klass(cyrillic_text)
3248 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3249 integers(min_value=0),
3252 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3253 value, bound_min = list(sorted(ints))
3255 class String(self.base_klass):
3256 bounds = (bound_min, bound_min)
3257 with self.assertRaises(DecodeError) as err:
3259 self.base_klass(b"1" * value).encode(),
3261 decode_path=decode_path,
3264 self.assertEqual(err.exception.offset, offset)
3265 self.assertEqual(err.exception.decode_path, decode_path)
3268 class TestPrintableString(
3269 UnicodeDecodeErrorMixin,
3274 base_klass = PrintableString
3277 class TestTeletexString(
3278 UnicodeDecodeErrorMixin,
3283 base_klass = TeletexString
3286 class TestVideotexString(
3287 UnicodeDecodeErrorMixin,
3292 base_klass = VideotexString
3295 class TestIA5String(
3296 UnicodeDecodeErrorMixin,
3301 base_klass = IA5String
3304 class TestGraphicString(
3305 UnicodeDecodeErrorMixin,
3310 base_klass = GraphicString
3313 class TestVisibleString(
3314 UnicodeDecodeErrorMixin,
3319 base_klass = VisibleString
3321 def test_x690_vector(self):
3322 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3323 self.assertSequenceEqual(tail, b"")
3324 self.assertEqual(str(obj), "Jones")
3325 self.assertFalse(obj.bered)
3326 self.assertFalse(obj.lenindef)
3328 obj, tail = VisibleString().decode(
3329 hexdec("3A0904034A6F6E04026573"),
3330 ctx={"bered": True},
3332 self.assertSequenceEqual(tail, b"")
3333 self.assertEqual(str(obj), "Jones")
3334 self.assertTrue(obj.bered)
3335 self.assertFalse(obj.lenindef)
3337 obj, tail = VisibleString().decode(
3338 hexdec("3A8004034A6F6E040265730000"),
3339 ctx={"bered": True},
3341 self.assertSequenceEqual(tail, b"")
3342 self.assertEqual(str(obj), "Jones")
3343 self.assertTrue(obj.bered)
3344 self.assertTrue(obj.lenindef)
3347 class TestGeneralString(
3348 UnicodeDecodeErrorMixin,
3353 base_klass = GeneralString
3356 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3357 base_klass = UniversalString
3360 class TestBMPString(StringMixin, CommonMixin, TestCase):
3361 base_klass = BMPString
3365 def generalized_time_values_strategy(
3373 if draw(booleans()):
3374 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3376 value = value.replace(microsecond=0)
3378 if draw(booleans()):
3379 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3381 default = default.replace(microsecond=0)
3385 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3387 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3388 optional = draw(one_of(none(), booleans()))
3390 draw(integers(min_value=0)),
3391 draw(integers(min_value=0)),
3392 draw(integers(min_value=0)),
3394 return (value, impl, expl, default, optional, _decoded)
3397 class TimeMixin(object):
3398 def test_invalid_value_type(self):
3399 with self.assertRaises(InvalidValueType) as err:
3400 self.base_klass(datetime.now().timetuple())
3403 @given(data_strategy())
3404 def test_optional(self, d):
3405 default = d.draw(datetimes(
3406 min_value=self.min_datetime,
3407 max_value=self.max_datetime,
3409 optional = d.draw(booleans())
3410 obj = self.base_klass(default=default, optional=optional)
3411 self.assertTrue(obj.optional)
3413 @given(data_strategy())
3414 def test_ready(self, d):
3415 obj = self.base_klass()
3416 self.assertFalse(obj.ready)
3419 with self.assertRaises(ObjNotReady) as err:
3422 value = d.draw(datetimes(min_value=self.min_datetime))
3423 obj = self.base_klass(value)
3424 self.assertTrue(obj.ready)
3428 @given(data_strategy())
3429 def test_comparison(self, d):
3430 value1 = d.draw(datetimes(
3431 min_value=self.min_datetime,
3432 max_value=self.max_datetime,
3434 value2 = d.draw(datetimes(
3435 min_value=self.min_datetime,
3436 max_value=self.max_datetime,
3438 tag1 = d.draw(binary(min_size=1))
3439 tag2 = d.draw(binary(min_size=1))
3441 value1 = value1.replace(microsecond=0)
3442 value2 = value2.replace(microsecond=0)
3443 obj1 = self.base_klass(value1)
3444 obj2 = self.base_klass(value2)
3445 self.assertEqual(obj1 == obj2, value1 == value2)
3446 self.assertEqual(obj1 != obj2, value1 != value2)
3447 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3448 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3449 obj1 = self.base_klass(value1, impl=tag1)
3450 obj2 = self.base_klass(value1, impl=tag2)
3451 self.assertEqual(obj1 == obj2, tag1 == tag2)
3452 self.assertEqual(obj1 != obj2, tag1 != tag2)
3454 @given(data_strategy())
3455 def test_call(self, d):
3463 ) = d.draw(generalized_time_values_strategy(
3464 min_datetime=self.min_datetime,
3465 max_datetime=self.max_datetime,
3466 omit_ms=self.omit_ms,
3468 obj_initial = self.base_klass(
3469 value=value_initial,
3472 default=default_initial,
3473 optional=optional_initial or False,
3474 _decoded=_decoded_initial,
3483 ) = d.draw(generalized_time_values_strategy(
3484 min_datetime=self.min_datetime,
3485 max_datetime=self.max_datetime,
3486 omit_ms=self.omit_ms,
3487 do_expl=impl_initial is None,
3497 value_expected = default if value is None else value
3499 default_initial if value_expected is None
3502 self.assertEqual(obj, value_expected)
3503 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3504 self.assertEqual(obj.expl_tag, expl or expl_initial)
3507 default_initial if default is None else default,
3509 if obj.default is None:
3510 optional = optional_initial if optional is None else optional
3511 optional = False if optional is None else optional
3514 self.assertEqual(obj.optional, optional)
3516 @given(data_strategy())
3517 def test_copy(self, d):
3518 values = d.draw(generalized_time_values_strategy(
3519 min_datetime=self.min_datetime,
3520 max_datetime=self.max_datetime,
3522 obj = self.base_klass(*values)
3523 obj_copied = obj.copy()
3524 self.assert_copied_basic_fields(obj, obj_copied)
3525 self.assertEqual(obj._value, obj_copied._value)
3527 @given(data_strategy())
3528 def test_stripped(self, d):
3529 value = d.draw(datetimes(
3530 min_value=self.min_datetime,
3531 max_value=self.max_datetime,
3533 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3534 obj = self.base_klass(value, impl=tag_impl)
3535 with self.assertRaises(NotEnoughData):
3536 obj.decode(obj.encode()[:-1])
3538 @given(data_strategy())
3539 def test_stripped_expl(self, d):
3540 value = d.draw(datetimes(
3541 min_value=self.min_datetime,
3542 max_value=self.max_datetime,
3544 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3545 obj = self.base_klass(value, expl=tag_expl)
3546 with self.assertRaises(NotEnoughData):
3547 obj.decode(obj.encode()[:-1])
3549 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3550 @given(data_strategy())
3551 def test_symmetric(self, d):
3552 values = d.draw(generalized_time_values_strategy(
3553 min_datetime=self.min_datetime,
3554 max_datetime=self.max_datetime,
3556 value = d.draw(datetimes(
3557 min_value=self.min_datetime,
3558 max_value=self.max_datetime,
3560 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3561 offset = d.draw(integers(min_value=0))
3562 tail_junk = d.draw(binary(max_size=5))
3563 _, _, _, default, optional, _decoded = values
3564 obj = self.base_klass(
3572 self.assertFalse(obj.expled)
3573 obj_encoded = obj.encode()
3574 obj_expled = obj(value, expl=tag_expl)
3575 self.assertTrue(obj_expled.expled)
3578 obj_expled_encoded = obj_expled.encode()
3579 obj_decoded, tail = obj_expled.decode(
3580 obj_expled_encoded + tail_junk,
3585 self.assertEqual(tail, tail_junk)
3586 self.assertEqual(obj_decoded, obj_expled)
3587 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3588 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3589 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3590 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3591 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3593 obj_decoded.expl_llen,
3594 len(len_encode(len(obj_encoded))),
3596 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3597 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3600 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3602 self.assertEqual(obj_decoded.expl_offset, offset)
3605 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3606 base_klass = GeneralizedTime
3608 min_datetime = datetime(1900, 1, 1)
3609 max_datetime = datetime(9999, 12, 31)
3611 def test_go_vectors_invalid(self):
3623 b"-20100102030410Z",
3624 b"2010-0102030410Z",
3625 b"2010-0002030410Z",
3626 b"201001-02030410Z",
3627 b"20100102-030410Z",
3628 b"2010010203-0410Z",
3629 b"201001020304-10Z",
3630 # These ones are INVALID in *DER*, but accepted
3631 # by Go's encoding/asn1
3632 b"20100102030405+0607",
3633 b"20100102030405-0607",
3635 with self.assertRaises(DecodeError) as err:
3636 GeneralizedTime(data)
3639 def test_go_vectors_valid(self):
3641 GeneralizedTime(b"20100102030405Z").todatetime(),
3642 datetime(2010, 1, 2, 3, 4, 5, 0),
3647 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3648 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3650 binary(min_size=1, max_size=1),
3652 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3653 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3656 def test_junk(self, part0, part1, part2):
3657 junk = part0 + part1 + part2
3658 assume(not (set(junk) <= set(digits.encode("ascii"))))
3659 with self.assertRaises(DecodeError):
3660 GeneralizedTime().decode(
3661 GeneralizedTime.tag_default +
3662 len_encode(len(junk)) +
3668 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3669 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3671 binary(min_size=1, max_size=1),
3673 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3674 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3677 def test_junk_dm(self, part0, part1, part2):
3678 junk = part0 + part1 + part2
3679 assume(not (set(junk) <= set(digits.encode("ascii"))))
3680 with self.assertRaises(DecodeError):
3681 GeneralizedTime().decode(
3682 GeneralizedTime.tag_default +
3683 len_encode(len(junk)) +
3688 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3689 base_klass = UTCTime
3691 min_datetime = datetime(2000, 1, 1)
3692 max_datetime = datetime(2049, 12, 31)
3694 def test_go_vectors_invalid(self):
3720 # These ones are INVALID in *DER*, but accepted
3721 # by Go's encoding/asn1
3722 b"910506164540-0700",
3723 b"910506164540+0730",
3727 with self.assertRaises(DecodeError) as err:
3731 def test_go_vectors_valid(self):
3733 UTCTime(b"910506234540Z").todatetime(),
3734 datetime(1991, 5, 6, 23, 45, 40, 0),
3737 @given(integers(min_value=0, max_value=49))
3738 def test_pre50(self, year):
3740 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3744 @given(integers(min_value=50, max_value=99))
3745 def test_post50(self, year):
3747 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3753 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3754 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3756 binary(min_size=1, max_size=1),
3758 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3759 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3762 def test_junk(self, part0, part1, part2):
3763 junk = part0 + part1 + part2
3764 assume(not (set(junk) <= set(digits.encode("ascii"))))
3765 with self.assertRaises(DecodeError):
3767 UTCTime.tag_default +
3768 len_encode(len(junk)) +
3774 def any_values_strategy(draw, do_expl=False):
3775 value = draw(one_of(none(), binary()))
3778 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3779 optional = draw(one_of(none(), booleans()))
3781 draw(integers(min_value=0)),
3782 draw(integers(min_value=0)),
3783 draw(integers(min_value=0)),
3785 return (value, expl, optional, _decoded)
3788 class AnyInherited(Any):
3792 class TestAny(CommonMixin, TestCase):
3795 def test_invalid_value_type(self):
3796 with self.assertRaises(InvalidValueType) as err:
3801 def test_optional(self, optional):
3802 obj = Any(optional=optional)
3803 self.assertEqual(obj.optional, optional)
3806 def test_ready(self, value):
3808 self.assertFalse(obj.ready)
3811 with self.assertRaises(ObjNotReady) as err:
3815 self.assertTrue(obj.ready)
3820 def test_basic(self, value):
3821 integer_encoded = Integer(value).encode()
3823 Any(integer_encoded),
3824 Any(Integer(value)),
3825 Any(Any(Integer(value))),
3827 self.assertSequenceEqual(bytes(obj), integer_encoded)
3829 obj.decode(obj.encode())[0].vlen,
3830 len(integer_encoded),
3834 self.assertSequenceEqual(obj.encode(), integer_encoded)
3836 @given(binary(), binary())
3837 def test_comparison(self, value1, value2):
3838 for klass in (Any, AnyInherited):
3839 obj1 = klass(value1)
3840 obj2 = klass(value2)
3841 self.assertEqual(obj1 == obj2, value1 == value2)
3842 self.assertEqual(obj1 != obj2, value1 != value2)
3843 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3845 @given(data_strategy())
3846 def test_call(self, d):
3847 for klass in (Any, AnyInherited):
3853 ) = d.draw(any_values_strategy())
3854 obj_initial = klass(
3857 optional_initial or False,
3865 ) = d.draw(any_values_strategy(do_expl=True))
3866 obj = obj_initial(value, expl, optional)
3868 value_expected = None if value is None else value
3869 self.assertEqual(obj, value_expected)
3870 self.assertEqual(obj.expl_tag, expl or expl_initial)
3871 if obj.default is None:
3872 optional = optional_initial if optional is None else optional
3873 optional = False if optional is None else optional
3874 self.assertEqual(obj.optional, optional)
3876 def test_simultaneous_impl_expl(self):
3877 # override it, as Any does not have implicit tag
3880 def test_decoded(self):
3881 # override it, as Any does not have implicit tag
3884 @given(any_values_strategy())
3885 def test_copy(self, values):
3886 for klass in (Any, AnyInherited):
3887 obj = klass(*values)
3888 obj_copied = obj.copy()
3889 self.assert_copied_basic_fields(obj, obj_copied)
3890 self.assertEqual(obj._value, obj_copied._value)
3892 @given(binary().map(OctetString))
3893 def test_stripped(self, value):
3895 with self.assertRaises(NotEnoughData):
3896 obj.decode(obj.encode()[:-1])
3900 integers(min_value=1).map(tag_ctxc),
3902 def test_stripped_expl(self, value, tag_expl):
3903 obj = Any(value, expl=tag_expl)
3904 with self.assertRaises(NotEnoughData):
3905 obj.decode(obj.encode()[:-1])
3908 integers(min_value=31),
3909 integers(min_value=0),
3912 def test_bad_tag(self, tag, offset, decode_path):
3913 with self.assertRaises(DecodeError) as err:
3915 tag_encode(tag)[:-1],
3917 decode_path=decode_path,
3920 self.assertEqual(err.exception.offset, offset)
3921 self.assertEqual(err.exception.decode_path, decode_path)
3924 integers(min_value=128),
3925 integers(min_value=0),
3928 def test_bad_len(self, l, offset, decode_path):
3929 with self.assertRaises(DecodeError) as err:
3931 Any.tag_default + len_encode(l)[:-1],
3933 decode_path=decode_path,
3936 self.assertEqual(err.exception.offset, offset)
3937 self.assertEqual(err.exception.decode_path, decode_path)
3939 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3941 any_values_strategy(),
3942 integers().map(lambda x: Integer(x).encode()),
3943 integers(min_value=1).map(tag_ctxc),
3944 integers(min_value=0),
3947 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3948 for klass in (Any, AnyInherited):
3949 _, _, optional, _decoded = values
3950 obj = klass(value=value, optional=optional, _decoded=_decoded)
3953 self.assertFalse(obj.expled)
3954 obj_encoded = obj.encode()
3955 obj_expled = obj(value, expl=tag_expl)
3956 self.assertTrue(obj_expled.expled)
3959 obj_expled_encoded = obj_expled.encode()
3960 obj_decoded, tail = obj_expled.decode(
3961 obj_expled_encoded + tail_junk,
3966 self.assertEqual(tail, tail_junk)
3967 self.assertEqual(obj_decoded, obj_expled)
3968 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3969 self.assertEqual(bytes(obj_decoded), bytes(obj))
3970 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3971 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3972 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3974 obj_decoded.expl_llen,
3975 len(len_encode(len(obj_encoded))),
3977 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3978 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3981 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3983 self.assertEqual(obj_decoded.expl_offset, offset)
3984 self.assertEqual(obj_decoded.tlen, 0)
3985 self.assertEqual(obj_decoded.llen, 0)
3986 self.assertEqual(obj_decoded.vlen, len(value))
3989 integers(min_value=1).map(tag_ctxc),
3990 integers(min_value=0, max_value=3),
3991 integers(min_value=0),
3995 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
3996 chunk = Boolean(False, expl=expl).encode()
3998 OctetString.tag_default +
4000 b"".join([chunk] * chunks) +
4003 obj, tail = Any().decode(
4006 decode_path=decode_path,
4007 ctx={"bered": True},
4009 self.assertSequenceEqual(tail, junk)
4010 self.assertEqual(obj.offset, offset)
4011 self.assertEqual(obj.tlvlen, len(encoded))
4012 with self.assertRaises(NotEnoughData) as err:
4016 decode_path=decode_path,
4017 ctx={"bered": True},
4019 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4020 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4024 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4026 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4027 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4029 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4030 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4032 min_size=len(names),
4033 max_size=len(names),
4036 (name, Integer(**tag_kwargs))
4037 for name, tag_kwargs in zip(names, tags)
4040 if value_required or draw(booleans()):
4041 value = draw(tuples(
4042 sampled_from([name for name, _ in schema]),
4043 integers().map(Integer),
4047 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4048 default = draw(one_of(
4050 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4052 optional = draw(one_of(none(), booleans()))
4054 draw(integers(min_value=0)),
4055 draw(integers(min_value=0)),
4056 draw(integers(min_value=0)),
4058 return (schema, value, expl, default, optional, _decoded)
4061 class ChoiceInherited(Choice):
4065 class TestChoice(CommonMixin, TestCase):
4067 schema = (("whatever", Boolean()),)
4070 def test_schema_required(self):
4071 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4074 def test_impl_forbidden(self):
4075 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4076 Choice(impl=b"whatever")
4078 def test_invalid_value_type(self):
4079 with self.assertRaises(InvalidValueType) as err:
4080 self.base_klass(123)
4082 with self.assertRaises(ObjUnknown) as err:
4083 self.base_klass(("whenever", Boolean(False)))
4085 with self.assertRaises(InvalidValueType) as err:
4086 self.base_klass(("whatever", Integer(123)))
4090 def test_optional(self, optional):
4091 obj = self.base_klass(
4092 default=self.base_klass(("whatever", Boolean(False))),
4095 self.assertTrue(obj.optional)
4098 def test_ready(self, value):
4099 obj = self.base_klass()
4100 self.assertFalse(obj.ready)
4103 self.assertIsNone(obj["whatever"])
4104 with self.assertRaises(ObjNotReady) as err:
4107 obj["whatever"] = Boolean()
4108 self.assertFalse(obj.ready)
4111 obj["whatever"] = Boolean(value)
4112 self.assertTrue(obj.ready)
4116 @given(booleans(), booleans())
4117 def test_comparison(self, value1, value2):
4118 class WahlInherited(self.base_klass):
4120 for klass in (self.base_klass, WahlInherited):
4121 obj1 = klass(("whatever", Boolean(value1)))
4122 obj2 = klass(("whatever", Boolean(value2)))
4123 self.assertEqual(obj1 == obj2, value1 == value2)
4124 self.assertEqual(obj1 != obj2, value1 != value2)
4125 self.assertEqual(obj1 == obj2._value, value1 == value2)
4126 self.assertFalse(obj1 == obj2._value[1])
4128 @given(data_strategy())
4129 def test_call(self, d):
4130 for klass in (Choice, ChoiceInherited):
4138 ) = d.draw(choice_values_strategy())
4141 schema = schema_initial
4143 value=value_initial,
4145 default=default_initial,
4146 optional=optional_initial or False,
4147 _decoded=_decoded_initial,
4156 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4157 obj = obj_initial(value, expl, default, optional)
4159 value_expected = default if value is None else value
4161 default_initial if value_expected is None
4164 self.assertEqual(obj.choice, value_expected[0])
4165 self.assertEqual(obj.value, int(value_expected[1]))
4166 self.assertEqual(obj.expl_tag, expl or expl_initial)
4167 default_expect = default_initial if default is None else default
4168 if default_expect is not None:
4169 self.assertEqual(obj.default.choice, default_expect[0])
4170 self.assertEqual(obj.default.value, int(default_expect[1]))
4171 if obj.default is None:
4172 optional = optional_initial if optional is None else optional
4173 optional = False if optional is None else optional
4176 self.assertEqual(obj.optional, optional)
4177 self.assertEqual(obj.specs, obj_initial.specs)
4179 def test_simultaneous_impl_expl(self):
4180 # override it, as Any does not have implicit tag
4183 def test_decoded(self):
4184 # override it, as Any does not have implicit tag
4187 @given(choice_values_strategy())
4188 def test_copy(self, values):
4189 _schema, value, expl, default, optional, _decoded = values
4191 class Wahl(self.base_klass):
4197 optional=optional or False,
4200 obj_copied = obj.copy()
4201 self.assertIsNone(obj.tag)
4202 self.assertIsNone(obj_copied.tag)
4203 # hack for assert_copied_basic_fields
4204 obj.tag = "whatever"
4205 obj_copied.tag = "whatever"
4206 self.assert_copied_basic_fields(obj, obj_copied)
4207 self.assertEqual(obj._value, obj_copied._value)
4208 self.assertEqual(obj.specs, obj_copied.specs)
4211 def test_stripped(self, value):
4212 obj = self.base_klass(("whatever", Boolean(value)))
4213 with self.assertRaises(NotEnoughData):
4214 obj.decode(obj.encode()[:-1])
4218 integers(min_value=1).map(tag_ctxc),
4220 def test_stripped_expl(self, value, tag_expl):
4221 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4222 with self.assertRaises(NotEnoughData):
4223 obj.decode(obj.encode()[:-1])
4225 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4226 @given(data_strategy())
4227 def test_symmetric(self, d):
4228 _schema, value, _, default, optional, _decoded = d.draw(
4229 choice_values_strategy(value_required=True)
4231 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4232 offset = d.draw(integers(min_value=0))
4233 tail_junk = d.draw(binary(max_size=5))
4235 class Wahl(self.base_klass):
4245 self.assertFalse(obj.expled)
4246 obj_encoded = obj.encode()
4247 obj_expled = obj(value, expl=tag_expl)
4248 self.assertTrue(obj_expled.expled)
4251 obj_expled_encoded = obj_expled.encode()
4252 obj_decoded, tail = obj_expled.decode(
4253 obj_expled_encoded + tail_junk,
4258 self.assertEqual(tail, tail_junk)
4259 self.assertEqual(obj_decoded, obj_expled)
4260 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4261 self.assertEqual(obj_decoded.value, obj_expled.value)
4262 self.assertEqual(obj_decoded.choice, obj.choice)
4263 self.assertEqual(obj_decoded.value, obj.value)
4264 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4265 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4266 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4268 obj_decoded.expl_llen,
4269 len(len_encode(len(obj_encoded))),
4271 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4272 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4275 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4277 self.assertEqual(obj_decoded.expl_offset, offset)
4278 self.assertSequenceEqual(
4280 obj_decoded.value.fulloffset - offset:
4281 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4287 def test_set_get(self, value):
4290 ("erste", Boolean()),
4291 ("zweite", Integer()),
4294 with self.assertRaises(ObjUnknown) as err:
4295 obj["whatever"] = "whenever"
4296 with self.assertRaises(InvalidValueType) as err:
4297 obj["zweite"] = Boolean(False)
4298 obj["zweite"] = Integer(value)
4300 with self.assertRaises(ObjUnknown) as err:
4303 self.assertIsNone(obj["erste"])
4304 self.assertEqual(obj["zweite"], Integer(value))
4306 def test_tag_mismatch(self):
4309 ("erste", Boolean()),
4311 int_encoded = Integer(123).encode()
4312 bool_encoded = Boolean(False).encode()
4314 obj.decode(bool_encoded)
4315 with self.assertRaises(TagMismatch):
4316 obj.decode(int_encoded)
4318 def test_tag_mismatch_underlying(self):
4319 class SeqOfBoolean(SequenceOf):
4322 class SeqOfInteger(SequenceOf):
4327 ("erste", SeqOfBoolean()),
4330 int_encoded = SeqOfInteger((Integer(123),)).encode()
4331 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4333 obj.decode(bool_encoded)
4334 with self.assertRaises(TagMismatch) as err:
4335 obj.decode(int_encoded)
4336 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4340 def seq_values_strategy(draw, seq_klass, do_expl=False):
4342 if draw(booleans()):
4345 k: v for k, v in draw(dictionaries(
4348 booleans().map(Boolean),
4349 integers().map(Integer),
4354 if draw(booleans()):
4355 schema = list(draw(dictionaries(
4358 booleans().map(Boolean),
4359 integers().map(Integer),
4365 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4367 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4369 if draw(booleans()):
4370 default = seq_klass()
4372 k: v for k, v in draw(dictionaries(
4375 booleans().map(Boolean),
4376 integers().map(Integer),
4380 optional = draw(one_of(none(), booleans()))
4382 draw(integers(min_value=0)),
4383 draw(integers(min_value=0)),
4384 draw(integers(min_value=0)),
4386 return (value, schema, impl, expl, default, optional, _decoded)
4390 def sequence_strategy(draw, seq_klass):
4391 inputs = draw(lists(
4393 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4394 tuples(just(Integer), integers(), one_of(none(), integers())),
4399 integers(min_value=1),
4400 min_size=len(inputs),
4401 max_size=len(inputs),
4404 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4405 for tag, expled in zip(tags, draw(lists(
4407 min_size=len(inputs),
4408 max_size=len(inputs),
4412 for i, optional in enumerate(draw(lists(
4413 sampled_from(("required", "optional", "empty")),
4414 min_size=len(inputs),
4415 max_size=len(inputs),
4417 if optional in ("optional", "empty"):
4418 inits[i]["optional"] = True
4419 if optional == "empty":
4421 empties = set(empties)
4422 names = list(draw(sets(
4424 min_size=len(inputs),
4425 max_size=len(inputs),
4428 for i, (klass, value, default) in enumerate(inputs):
4429 schema.append((names[i], klass(default=default, **inits[i])))
4430 seq_name = draw(text_letters())
4431 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4434 for i, (klass, value, default) in enumerate(inputs):
4441 "default_value": None if spec.default is None else default,
4445 expect["optional"] = True
4447 expect["presented"] = True
4448 expect["value"] = value
4450 expect["optional"] = True
4451 if default is not None and default == value:
4452 expect["presented"] = False
4453 seq[name] = klass(value)
4454 expects.append(expect)
4459 def sequences_strategy(draw, seq_klass):
4460 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4462 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4463 for tag, expled in zip(tags, draw(lists(
4470 i for i, is_default in enumerate(draw(lists(
4476 names = list(draw(sets(
4481 seq_expectses = draw(lists(
4482 sequence_strategy(seq_klass=seq_klass),
4486 seqs = [seq for seq, _ in seq_expectses]
4488 for i, (name, seq) in enumerate(zip(names, seqs)):
4491 seq(default=(seq if i in defaulted else None), **inits[i]),
4493 seq_name = draw(text_letters())
4494 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4497 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4500 "expects": expects_inner,
4503 seq_outer[name] = seq_inner
4504 if seq_outer.specs[name].default is None:
4505 expect["presented"] = True
4506 expect_outers.append(expect)
4507 return seq_outer, expect_outers
4510 class SeqMixing(object):
4511 def test_invalid_value_type(self):
4512 with self.assertRaises(InvalidValueType) as err:
4513 self.base_klass(123)
4516 def test_invalid_value_type_set(self):
4517 class Seq(self.base_klass):
4518 schema = (("whatever", Boolean()),)
4520 with self.assertRaises(InvalidValueType) as err:
4521 seq["whatever"] = Integer(123)
4525 def test_optional(self, optional):
4526 obj = self.base_klass(default=self.base_klass(), optional=optional)
4527 self.assertTrue(obj.optional)
4529 @given(data_strategy())
4530 def test_ready(self, d):
4532 str(i): v for i, v in enumerate(d.draw(lists(
4539 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4546 for name in d.draw(permutations(
4547 list(ready.keys()) + list(non_ready.keys()),
4549 schema_input.append((name, Boolean()))
4551 class Seq(self.base_klass):
4552 schema = tuple(schema_input)
4554 for name in ready.keys():
4556 seq[name] = Boolean()
4557 self.assertFalse(seq.ready)
4560 for name, value in ready.items():
4561 seq[name] = Boolean(value)
4562 self.assertFalse(seq.ready)
4565 with self.assertRaises(ObjNotReady) as err:
4568 for name, value in non_ready.items():
4569 seq[name] = Boolean(value)
4570 self.assertTrue(seq.ready)
4574 @given(data_strategy())
4575 def test_call(self, d):
4576 class SeqInherited(self.base_klass):
4578 for klass in (self.base_klass, SeqInherited):
4587 ) = d.draw(seq_values_strategy(seq_klass=klass))
4588 obj_initial = klass(
4594 optional_initial or False,
4605 ) = d.draw(seq_values_strategy(
4607 do_expl=impl_initial is None,
4609 obj = obj_initial(value, impl, expl, default, optional)
4610 value_expected = default if value is None else value
4612 default_initial if value_expected is None
4615 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4616 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4617 self.assertEqual(obj.expl_tag, expl or expl_initial)
4619 {} if obj.default is None else obj.default._value,
4620 getattr(default_initial if default is None else default, "_value", {}),
4622 if obj.default is None:
4623 optional = optional_initial if optional is None else optional
4624 optional = False if optional is None else optional
4627 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4628 self.assertEqual(obj.optional, optional)
4630 @given(data_strategy())
4631 def test_copy(self, d):
4632 class SeqInherited(self.base_klass):
4634 for klass in (self.base_klass, SeqInherited):
4635 values = d.draw(seq_values_strategy(seq_klass=klass))
4636 obj = klass(*values)
4637 obj_copied = obj.copy()
4638 self.assert_copied_basic_fields(obj, obj_copied)
4639 self.assertEqual(obj.specs, obj_copied.specs)
4640 self.assertEqual(obj._value, obj_copied._value)
4642 @given(data_strategy())
4643 def test_stripped(self, d):
4644 value = d.draw(integers())
4645 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4647 class Seq(self.base_klass):
4649 schema = (("whatever", Integer()),)
4651 seq["whatever"] = Integer(value)
4652 with self.assertRaises(NotEnoughData):
4653 seq.decode(seq.encode()[:-1])
4655 @given(data_strategy())
4656 def test_stripped_expl(self, d):
4657 value = d.draw(integers())
4658 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4660 class Seq(self.base_klass):
4662 schema = (("whatever", Integer()),)
4664 seq["whatever"] = Integer(value)
4665 with self.assertRaises(NotEnoughData):
4666 seq.decode(seq.encode()[:-1])
4668 @given(binary(min_size=2))
4669 def test_non_tag_mismatch_raised(self, junk):
4671 _, _, len_encoded = tag_strip(memoryview(junk))
4672 len_decode(len_encoded)
4678 class Seq(self.base_klass):
4680 ("whatever", Integer()),
4682 ("whenever", Integer()),
4685 seq["whatever"] = Integer(123)
4686 seq["junk"] = Any(junk)
4687 seq["whenever"] = Integer(123)
4688 with self.assertRaises(DecodeError):
4689 seq.decode(seq.encode())
4692 integers(min_value=31),
4693 integers(min_value=0),
4696 def test_bad_tag(self, tag, offset, decode_path):
4697 with self.assertRaises(DecodeError) as err:
4698 self.base_klass().decode(
4699 tag_encode(tag)[:-1],
4701 decode_path=decode_path,
4704 self.assertEqual(err.exception.offset, offset)
4705 self.assertEqual(err.exception.decode_path, decode_path)
4708 integers(min_value=128),
4709 integers(min_value=0),
4712 def test_bad_len(self, l, offset, decode_path):
4713 with self.assertRaises(DecodeError) as err:
4714 self.base_klass().decode(
4715 self.base_klass.tag_default + len_encode(l)[:-1],
4717 decode_path=decode_path,
4720 self.assertEqual(err.exception.offset, offset)
4721 self.assertEqual(err.exception.decode_path, decode_path)
4723 def _assert_expects(self, seq, expects):
4724 for expect in expects:
4726 seq.specs[expect["name"]].optional,
4729 if expect["default_value"] is not None:
4731 seq.specs[expect["name"]].default,
4732 expect["default_value"],
4734 if expect["presented"]:
4735 self.assertIn(expect["name"], seq)
4736 self.assertEqual(seq[expect["name"]], expect["value"])
4738 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4739 @given(data_strategy())
4740 def test_symmetric(self, d):
4741 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4742 tail_junk = d.draw(binary(max_size=5))
4743 self.assertTrue(seq.ready)
4744 self.assertFalse(seq.decoded)
4745 self._assert_expects(seq, expects)
4748 self.assertTrue(seq.ready)
4749 seq_encoded = seq.encode()
4750 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4751 self.assertFalse(seq_decoded.lenindef)
4753 t, _, lv = tag_strip(seq_encoded)
4754 _, _, v = len_decode(lv)
4755 seq_encoded_lenindef = t + LENINDEF + v + EOC
4756 seq_decoded_lenindef, tail_lenindef = seq.decode(
4757 seq_encoded_lenindef + tail_junk,
4758 ctx={"bered": True},
4760 self.assertTrue(seq_decoded_lenindef.lenindef)
4761 with self.assertRaises(DecodeError):
4762 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4763 with self.assertRaises(DecodeError):
4764 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4765 repr(seq_decoded_lenindef)
4766 pprint(seq_decoded_lenindef)
4767 self.assertTrue(seq_decoded_lenindef.ready)
4769 for decoded, decoded_tail, encoded in (
4770 (seq_decoded, tail, seq_encoded),
4771 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4773 self.assertEqual(decoded_tail, tail_junk)
4774 self._assert_expects(decoded, expects)
4775 self.assertEqual(seq, decoded)
4776 self.assertEqual(decoded.encode(), seq_encoded)
4777 self.assertEqual(decoded.tlvlen, len(encoded))
4778 for expect in expects:
4779 if not expect["presented"]:
4780 self.assertNotIn(expect["name"], decoded)
4782 self.assertIn(expect["name"], decoded)
4783 obj = decoded[expect["name"]]
4784 self.assertTrue(obj.decoded)
4785 offset = obj.expl_offset if obj.expled else obj.offset
4786 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4787 self.assertSequenceEqual(
4788 seq_encoded[offset:offset + tlvlen],
4792 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4793 @given(data_strategy())
4794 def test_symmetric_with_seq(self, d):
4795 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4796 self.assertTrue(seq.ready)
4797 seq_encoded = seq.encode()
4798 seq_decoded, tail = seq.decode(seq_encoded)
4799 self.assertEqual(tail, b"")
4800 self.assertTrue(seq.ready)
4801 self.assertEqual(seq, seq_decoded)
4802 self.assertEqual(seq_decoded.encode(), seq_encoded)
4803 for expect_outer in expect_outers:
4804 if not expect_outer["presented"]:
4805 self.assertNotIn(expect_outer["name"], seq_decoded)
4807 self.assertIn(expect_outer["name"], seq_decoded)
4808 obj = seq_decoded[expect_outer["name"]]
4809 self.assertTrue(obj.decoded)
4810 offset = obj.expl_offset if obj.expled else obj.offset
4811 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4812 self.assertSequenceEqual(
4813 seq_encoded[offset:offset + tlvlen],
4816 self._assert_expects(obj, expect_outer["expects"])
4818 @given(data_strategy())
4819 def test_default_disappears(self, d):
4820 _schema = list(d.draw(dictionaries(
4822 sets(integers(), min_size=2, max_size=2),
4826 class Seq(self.base_klass):
4828 (n, Integer(default=d))
4829 for n, (_, d) in _schema
4832 for name, (value, _) in _schema:
4833 seq[name] = Integer(value)
4834 self.assertEqual(len(seq._value), len(_schema))
4835 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4836 self.assertGreater(len(seq.encode()), len(empty_seq))
4837 for name, (_, default) in _schema:
4838 seq[name] = Integer(default)
4839 self.assertEqual(len(seq._value), 0)
4840 self.assertSequenceEqual(seq.encode(), empty_seq)
4842 @given(data_strategy())
4843 def test_encoded_default_accepted(self, d):
4844 _schema = list(d.draw(dictionaries(
4849 tags = [tag_encode(tag) for tag in d.draw(sets(
4850 integers(min_value=0),
4851 min_size=len(_schema),
4852 max_size=len(_schema),
4855 class SeqWithoutDefault(self.base_klass):
4857 (n, Integer(impl=t))
4858 for (n, _), t in zip(_schema, tags)
4860 seq_without_default = SeqWithoutDefault()
4861 for name, value in _schema:
4862 seq_without_default[name] = Integer(value)
4863 seq_encoded = seq_without_default.encode()
4865 class SeqWithDefault(self.base_klass):
4867 (n, Integer(default=v, impl=t))
4868 for (n, v), t in zip(_schema, tags)
4870 seq_with_default = SeqWithDefault()
4871 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4872 for name, value in _schema:
4873 self.assertEqual(seq_decoded[name], seq_with_default[name])
4874 self.assertEqual(seq_decoded[name], value)
4876 @given(data_strategy())
4877 def test_missing_from_spec(self, d):
4878 names = list(d.draw(sets(text_letters(), min_size=2)))
4879 tags = [tag_encode(tag) for tag in d.draw(sets(
4880 integers(min_value=0),
4881 min_size=len(names),
4882 max_size=len(names),
4884 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4886 class SeqFull(self.base_klass):
4887 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4888 seq_full = SeqFull()
4889 for i, name in enumerate(names):
4890 seq_full[name] = Integer(i)
4891 seq_encoded = seq_full.encode()
4892 altered = names_tags[:-2] + names_tags[-1:]
4894 class SeqMissing(self.base_klass):
4895 schema = [(n, Integer(impl=t)) for n, t in altered]
4896 seq_missing = SeqMissing()
4897 with self.assertRaises(TagMismatch):
4898 seq_missing.decode(seq_encoded)
4901 class TestSequence(SeqMixing, CommonMixin, TestCase):
4902 base_klass = Sequence
4908 def test_remaining(self, value, junk):
4909 class Seq(Sequence):
4911 ("whatever", Integer()),
4913 int_encoded = Integer(value).encode()
4915 Sequence.tag_default,
4916 len_encode(len(int_encoded + junk)),
4919 with assertRaisesRegex(self, DecodeError, "remaining"):
4920 Seq().decode(junked)
4922 @given(sets(text_letters(), min_size=2))
4923 def test_obj_unknown(self, names):
4924 missing = names.pop()
4926 class Seq(Sequence):
4927 schema = [(n, Boolean()) for n in names]
4929 with self.assertRaises(ObjUnknown) as err:
4932 with self.assertRaises(ObjUnknown) as err:
4933 seq[missing] = Boolean()
4936 def test_x690_vector(self):
4937 class Seq(Sequence):
4939 ("name", IA5String()),
4942 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4943 self.assertEqual(seq["name"], "Smith")
4944 self.assertEqual(seq["ok"], True)
4947 class TestSet(SeqMixing, CommonMixin, TestCase):
4950 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4951 @given(data_strategy())
4952 def test_sorted(self, d):
4954 tag_encode(tag) for tag in
4955 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4959 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4961 for name, _ in Seq.schema:
4962 seq[name] = OctetString(b"")
4963 seq_encoded = seq.encode()
4964 seq_decoded, _ = seq.decode(seq_encoded)
4965 self.assertSequenceEqual(
4966 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4967 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4972 def seqof_values_strategy(draw, schema=None, do_expl=False):
4974 schema = draw(sampled_from((Boolean(), Integer())))
4975 bound_min, bound_max = sorted(draw(sets(
4976 integers(min_value=0, max_value=10),
4980 if isinstance(schema, Boolean):
4981 values_generator = booleans().map(Boolean)
4982 elif isinstance(schema, Integer):
4983 values_generator = integers().map(Integer)
4984 values_generator = lists(
4989 values = draw(one_of(none(), values_generator))
4993 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4995 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4996 default = draw(one_of(none(), values_generator))
4997 optional = draw(one_of(none(), booleans()))
4999 draw(integers(min_value=0)),
5000 draw(integers(min_value=0)),
5001 draw(integers(min_value=0)),
5006 (bound_min, bound_max),
5015 class SeqOfMixing(object):
5016 def test_invalid_value_type(self):
5017 with self.assertRaises(InvalidValueType) as err:
5018 self.base_klass(123)
5021 def test_invalid_values_type(self):
5022 class SeqOf(self.base_klass):
5024 with self.assertRaises(InvalidValueType) as err:
5025 SeqOf([Integer(123), Boolean(False), Integer(234)])
5028 def test_schema_required(self):
5029 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5030 self.base_klass.__mro__[1]()
5032 @given(booleans(), booleans(), binary(), binary())
5033 def test_comparison(self, value1, value2, tag1, tag2):
5034 class SeqOf(self.base_klass):
5036 obj1 = SeqOf([Boolean(value1)])
5037 obj2 = SeqOf([Boolean(value2)])
5038 self.assertEqual(obj1 == obj2, value1 == value2)
5039 self.assertEqual(obj1 != obj2, value1 != value2)
5040 self.assertEqual(obj1 == list(obj2), value1 == value2)
5041 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5042 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5043 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5044 self.assertEqual(obj1 == obj2, tag1 == tag2)
5045 self.assertEqual(obj1 != obj2, tag1 != tag2)
5047 @given(lists(booleans()))
5048 def test_iter(self, values):
5049 class SeqOf(self.base_klass):
5051 obj = SeqOf([Boolean(value) for value in values])
5052 self.assertEqual(len(obj), len(values))
5053 for i, value in enumerate(obj):
5054 self.assertEqual(value, values[i])
5056 @given(data_strategy())
5057 def test_ready(self, d):
5058 ready = [Integer(v) for v in d.draw(lists(
5065 range(d.draw(integers(min_value=1, max_value=5)))
5068 class SeqOf(self.base_klass):
5070 values = d.draw(permutations(ready + non_ready))
5072 for value in values:
5074 self.assertFalse(seqof.ready)
5077 with self.assertRaises(ObjNotReady) as err:
5080 for i, value in enumerate(values):
5081 self.assertEqual(seqof[i], value)
5082 if not seqof[i].ready:
5083 seqof[i] = Integer(i)
5084 self.assertTrue(seqof.ready)
5088 def test_spec_mismatch(self):
5089 class SeqOf(self.base_klass):
5092 seqof.append(Integer(123))
5093 with self.assertRaises(ValueError):
5094 seqof.append(Boolean(False))
5095 with self.assertRaises(ValueError):
5096 seqof[0] = Boolean(False)
5098 @given(data_strategy())
5099 def test_bounds_satisfied(self, d):
5100 class SeqOf(self.base_klass):
5102 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5103 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5104 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5105 SeqOf(value=value, bounds=(bound_min, bound_max))
5107 @given(data_strategy())
5108 def test_bounds_unsatisfied(self, d):
5109 class SeqOf(self.base_klass):
5111 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5112 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5113 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5114 with self.assertRaises(BoundsError) as err:
5115 SeqOf(value=value, bounds=(bound_min, bound_max))
5117 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5118 SeqOf(bounds=(bound_min, bound_max)).decode(
5119 SeqOf(value).encode()
5122 value = [Boolean(True)] * d.draw(integers(
5123 min_value=bound_max + 1,
5124 max_value=bound_max + 10,
5126 with self.assertRaises(BoundsError) as err:
5127 SeqOf(value=value, bounds=(bound_min, bound_max))
5129 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5130 SeqOf(bounds=(bound_min, bound_max)).decode(
5131 SeqOf(value).encode()
5135 @given(integers(min_value=1, max_value=10))
5136 def test_out_of_bounds(self, bound_max):
5137 class SeqOf(self.base_klass):
5139 bounds = (0, bound_max)
5141 for _ in range(bound_max):
5142 seqof.append(Integer(123))
5143 with self.assertRaises(BoundsError):
5144 seqof.append(Integer(123))
5146 @given(data_strategy())
5147 def test_call(self, d):
5157 ) = d.draw(seqof_values_strategy())
5159 class SeqOf(self.base_klass):
5160 schema = schema_initial
5161 obj_initial = SeqOf(
5162 value=value_initial,
5163 bounds=bounds_initial,
5166 default=default_initial,
5167 optional=optional_initial or False,
5168 _decoded=_decoded_initial,
5179 ) = d.draw(seqof_values_strategy(
5180 schema=schema_initial,
5181 do_expl=impl_initial is None,
5183 if (default is None) and (obj_initial.default is not None):
5186 (bounds is None) and
5187 (value is not None) and
5188 (bounds_initial is not None) and
5189 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5193 (bounds is None) and
5194 (default is not None) and
5195 (bounds_initial is not None) and
5196 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5208 value_expected = default if value is None else value
5210 default_initial if value_expected is None
5213 value_expected = () if value_expected is None else value_expected
5214 self.assertEqual(obj, value_expected)
5215 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5216 self.assertEqual(obj.expl_tag, expl or expl_initial)
5219 default_initial if default is None else default,
5221 if obj.default is None:
5222 optional = optional_initial if optional is None else optional
5223 optional = False if optional is None else optional
5226 self.assertEqual(obj.optional, optional)
5228 (obj._bound_min, obj._bound_max),
5229 bounds or bounds_initial or (0, float("+inf")),
5232 @given(seqof_values_strategy())
5233 def test_copy(self, values):
5234 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5236 class SeqOf(self.base_klass):
5244 optional=optional or False,
5247 obj_copied = obj.copy()
5248 self.assert_copied_basic_fields(obj, obj_copied)
5249 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5250 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5251 self.assertEqual(obj._value, obj_copied._value)
5255 integers(min_value=1).map(tag_encode),
5257 def test_stripped(self, values, tag_impl):
5258 class SeqOf(self.base_klass):
5259 schema = OctetString()
5260 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5261 with self.assertRaises(NotEnoughData):
5262 obj.decode(obj.encode()[:-1])
5266 integers(min_value=1).map(tag_ctxc),
5268 def test_stripped_expl(self, values, tag_expl):
5269 class SeqOf(self.base_klass):
5270 schema = OctetString()
5271 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5272 with self.assertRaises(NotEnoughData):
5273 obj.decode(obj.encode()[:-1])
5276 integers(min_value=31),
5277 integers(min_value=0),
5280 def test_bad_tag(self, tag, offset, decode_path):
5281 with self.assertRaises(DecodeError) as err:
5282 self.base_klass().decode(
5283 tag_encode(tag)[:-1],
5285 decode_path=decode_path,
5288 self.assertEqual(err.exception.offset, offset)
5289 self.assertEqual(err.exception.decode_path, decode_path)
5292 integers(min_value=128),
5293 integers(min_value=0),
5296 def test_bad_len(self, l, offset, decode_path):
5297 with self.assertRaises(DecodeError) as err:
5298 self.base_klass().decode(
5299 self.base_klass.tag_default + len_encode(l)[:-1],
5301 decode_path=decode_path,
5304 self.assertEqual(err.exception.offset, offset)
5305 self.assertEqual(err.exception.decode_path, decode_path)
5307 @given(binary(min_size=1))
5308 def test_tag_mismatch(self, impl):
5309 assume(impl != self.base_klass.tag_default)
5310 with self.assertRaises(TagMismatch):
5311 self.base_klass(impl=impl).decode(self.base_klass().encode())
5313 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5315 seqof_values_strategy(schema=Integer()),
5316 lists(integers().map(Integer)),
5317 integers(min_value=1).map(tag_ctxc),
5318 integers(min_value=0),
5321 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5322 _, _, _, _, _, default, optional, _decoded = values
5324 class SeqOf(self.base_klass):
5334 self.assertFalse(obj.expled)
5335 obj_encoded = obj.encode()
5336 obj_expled = obj(value, expl=tag_expl)
5337 self.assertTrue(obj_expled.expled)
5340 obj_expled_encoded = obj_expled.encode()
5341 obj_decoded, tail = obj_expled.decode(
5342 obj_expled_encoded + tail_junk,
5347 self.assertEqual(tail, tail_junk)
5348 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5349 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5350 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5351 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5353 obj_decoded.expl_llen,
5354 len(len_encode(len(obj_encoded))),
5356 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5357 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5360 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5362 self.assertEqual(obj_decoded.expl_offset, offset)
5363 for obj_inner in obj_decoded:
5364 self.assertIn(obj_inner, obj_decoded)
5365 self.assertSequenceEqual(
5368 obj_inner.offset - offset:
5369 obj_inner.offset + obj_inner.tlvlen - offset
5373 t, _, lv = tag_strip(obj_encoded)
5374 _, _, v = len_decode(lv)
5375 obj_encoded_lenindef = t + LENINDEF + v + EOC
5376 obj_decoded_lenindef, tail_lenindef = obj.decode(
5377 obj_encoded_lenindef + tail_junk,
5378 ctx={"bered": True},
5380 self.assertTrue(obj_decoded_lenindef.lenindef)
5381 repr(obj_decoded_lenindef)
5382 pprint(obj_decoded_lenindef)
5383 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5384 with self.assertRaises(DecodeError):
5385 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5386 with self.assertRaises(DecodeError):
5387 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5390 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5391 class SeqOf(SequenceOf):
5395 def _test_symmetric_compare_objs(self, obj1, obj2):
5396 self.assertEqual(obj1, obj2)
5397 self.assertSequenceEqual(list(obj1), list(obj2))
5400 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5405 def _test_symmetric_compare_objs(self, obj1, obj2):
5406 self.assertSetEqual(
5407 set(int(v) for v in obj1),
5408 set(int(v) for v in obj2),
5411 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5412 @given(data_strategy())
5413 def test_sorted(self, d):
5414 values = [OctetString(v) for v in d.draw(lists(binary()))]
5417 schema = OctetString()
5419 seq_encoded = seq.encode()
5420 seq_decoded, _ = seq.decode(seq_encoded)
5421 self.assertSequenceEqual(
5422 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5423 b"".join(sorted([v.encode() for v in values])),
5427 class TestGoMarshalVectors(TestCase):
5429 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5430 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5431 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5432 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5433 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5435 class Seq(Sequence):
5437 ("erste", Integer()),
5438 ("zweite", Integer(optional=True))
5441 seq["erste"] = Integer(64)
5442 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5443 seq["erste"] = Integer(0x123456)
5444 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5445 seq["erste"] = Integer(64)
5446 seq["zweite"] = Integer(65)
5447 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5449 class NestedSeq(Sequence):
5453 seq["erste"] = Integer(127)
5454 seq["zweite"] = None
5455 nested = NestedSeq()
5456 nested["nest"] = seq
5457 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5459 self.assertSequenceEqual(
5460 OctetString(b"\x01\x02\x03").encode(),
5461 hexdec("0403010203"),
5464 class Seq(Sequence):
5466 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5469 seq["erste"] = Integer(64)
5470 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5472 class Seq(Sequence):
5474 ("erste", Integer(expl=tag_ctxc(5))),
5477 seq["erste"] = Integer(64)
5478 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5480 class Seq(Sequence):
5483 impl=tag_encode(0, klass=TagClassContext),
5488 seq["erste"] = Null()
5489 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5491 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5493 self.assertSequenceEqual(
5494 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5495 hexdec("170d3730303130313030303030305a"),
5497 self.assertSequenceEqual(
5498 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5499 hexdec("170d3039313131353232353631365a"),
5501 self.assertSequenceEqual(
5502 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5503 hexdec("180f32313030303430353132303130315a"),
5506 class Seq(Sequence):
5508 ("erste", GeneralizedTime()),
5511 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5512 self.assertSequenceEqual(
5514 hexdec("3011180f32303039313131353232353631365a"),
5517 self.assertSequenceEqual(
5518 BitString((1, b"\x80")).encode(),
5521 self.assertSequenceEqual(
5522 BitString((12, b"\x81\xF0")).encode(),
5523 hexdec("03030481f0"),
5526 self.assertSequenceEqual(
5527 ObjectIdentifier("1.2.3.4").encode(),
5528 hexdec("06032a0304"),
5530 self.assertSequenceEqual(
5531 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5532 hexdec("06092a864888932d010105"),
5534 self.assertSequenceEqual(
5535 ObjectIdentifier("2.100.3").encode(),
5536 hexdec("0603813403"),
5539 self.assertSequenceEqual(
5540 PrintableString("test").encode(),
5541 hexdec("130474657374"),
5543 self.assertSequenceEqual(
5544 PrintableString("x" * 127).encode(),
5545 hexdec("137F" + "78" * 127),
5547 self.assertSequenceEqual(
5548 PrintableString("x" * 128).encode(),
5549 hexdec("138180" + "78" * 128),
5551 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5553 class Seq(Sequence):
5555 ("erste", IA5String()),
5558 seq["erste"] = IA5String("test")
5559 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5561 class Seq(Sequence):
5563 ("erste", PrintableString()),
5566 seq["erste"] = PrintableString("test")
5567 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5568 seq["erste"] = PrintableString("test*")
5569 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5571 class Seq(Sequence):
5573 ("erste", Any(optional=True)),
5574 ("zweite", Integer()),
5577 seq["zweite"] = Integer(64)
5578 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5583 seq.append(Integer(10))
5584 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5586 class _SeqOf(SequenceOf):
5587 schema = PrintableString()
5589 class SeqOf(SequenceOf):
5592 _seqof.append(PrintableString("1"))
5594 seqof.append(_seqof)
5595 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5597 class Seq(Sequence):
5599 ("erste", Integer(default=1)),
5602 seq["erste"] = Integer(0)
5603 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5604 seq["erste"] = Integer(1)
5605 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5606 seq["erste"] = Integer(2)
5607 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5610 class TestPP(TestCase):
5611 @given(data_strategy())
5612 def test_oid_printing(self, d):
5614 str(ObjectIdentifier(k)): v * 2
5615 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5617 chosen = d.draw(sampled_from(sorted(oids)))
5618 chosen_id = oids[chosen]
5619 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5620 self.assertNotIn(chosen_id, pp_console_row(pp))
5621 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5624 class TestAutoAddSlots(TestCase):
5626 class Inher(Integer):
5629 with self.assertRaises(AttributeError):
5631 inher.unexistent = "whatever"
5634 class TestOIDDefines(TestCase):
5635 @given(data_strategy())
5636 def runTest(self, d):
5637 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5638 value_name_chosen = d.draw(sampled_from(value_names))
5640 ObjectIdentifier(oid)
5641 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5643 oid_chosen = d.draw(sampled_from(oids))
5644 values = d.draw(lists(
5646 min_size=len(value_names),
5647 max_size=len(value_names),
5650 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5651 oid: Integer() for oid in oids[:-1]
5654 for i, value_name in enumerate(value_names):
5655 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5657 class Seq(Sequence):
5660 for value_name, value in zip(value_names, values):
5661 seq[value_name] = Any(Integer(value).encode())
5662 seq["type"] = oid_chosen
5663 seq, _ = Seq().decode(seq.encode())
5664 for value_name in value_names:
5665 if value_name == value_name_chosen:
5667 self.assertIsNone(seq[value_name].defined)
5668 if value_name_chosen in oids[:-1]:
5669 self.assertIsNotNone(seq[value_name_chosen].defined)
5670 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5671 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5674 class TestDefinesByPath(TestCase):
5675 def test_generated(self):
5676 class Seq(Sequence):
5678 ("type", ObjectIdentifier()),
5679 ("value", OctetString(expl=tag_ctxc(123))),
5682 class SeqInner(Sequence):
5684 ("typeInner", ObjectIdentifier()),
5685 ("valueInner", Any()),
5688 class PairValue(SetOf):
5691 class Pair(Sequence):
5693 ("type", ObjectIdentifier()),
5694 ("value", PairValue()),
5697 class Pairs(SequenceOf):
5704 type_octet_stringed,
5706 ObjectIdentifier(oid)
5707 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5709 seq_integered = Seq()
5710 seq_integered["type"] = type_integered
5711 seq_integered["value"] = OctetString(Integer(123).encode())
5712 seq_integered_raw = seq_integered.encode()
5716 (type_octet_stringed, OctetString(b"whatever")),
5717 (type_integered, Integer(123)),
5718 (type_octet_stringed, OctetString(b"whenever")),
5719 (type_integered, Integer(234)),
5721 for t, v in pairs_input:
5724 pair["value"] = PairValue((Any(v),))
5726 seq_inner = SeqInner()
5727 seq_inner["typeInner"] = type_innered
5728 seq_inner["valueInner"] = Any(pairs)
5729 seq_sequenced = Seq()
5730 seq_sequenced["type"] = type_sequenced
5731 seq_sequenced["value"] = OctetString(seq_inner.encode())
5732 seq_sequenced_raw = seq_sequenced.encode()
5734 defines_by_path = []
5735 seq_integered, _ = Seq().decode(seq_integered_raw)
5736 self.assertIsNone(seq_integered["value"].defined)
5737 defines_by_path.append(
5738 (("type",), ((("value",), {
5739 type_integered: Integer(),
5740 type_sequenced: SeqInner(),
5743 seq_integered, _ = Seq().decode(
5745 ctx={"defines_by_path": defines_by_path},
5747 self.assertIsNotNone(seq_integered["value"].defined)
5748 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5749 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5750 self.assertTrue(seq_integered_raw[
5751 seq_integered["value"].defined[1].offset:
5752 ].startswith(Integer(123).encode()))
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.assertIsNone(seq_inner["valueInner"].defined)
5763 defines_by_path.append((
5764 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5765 ((("valueInner",), {type_innered: Pairs()}),),
5767 seq_sequenced, _ = Seq().decode(
5769 ctx={"defines_by_path": defines_by_path},
5771 self.assertIsNotNone(seq_sequenced["value"].defined)
5772 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5773 seq_inner = seq_sequenced["value"].defined[1]
5774 self.assertIsNotNone(seq_inner["valueInner"].defined)
5775 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5776 pairs = seq_inner["valueInner"].defined[1]
5778 self.assertIsNone(pair["value"][0].defined)
5780 defines_by_path.append((
5783 DecodePathDefBy(type_sequenced),
5785 DecodePathDefBy(type_innered),
5790 type_integered: Integer(),
5791 type_octet_stringed: OctetString(),
5794 seq_sequenced, _ = Seq().decode(
5796 ctx={"defines_by_path": defines_by_path},
5798 self.assertIsNotNone(seq_sequenced["value"].defined)
5799 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5800 seq_inner = seq_sequenced["value"].defined[1]
5801 self.assertIsNotNone(seq_inner["valueInner"].defined)
5802 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5803 pairs_got = seq_inner["valueInner"].defined[1]
5804 for pair_input, pair_got in zip(pairs_input, pairs_got):
5805 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5806 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5808 @given(oid_strategy(), integers())
5809 def test_simple(self, oid, tgt):
5810 class Inner(Sequence):
5812 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5813 ObjectIdentifier(oid): Integer(),
5817 class Outer(Sequence):
5820 ("tgt", OctetString()),
5824 inner["oid"] = ObjectIdentifier(oid)
5826 outer["inner"] = inner
5827 outer["tgt"] = OctetString(Integer(tgt).encode())
5828 decoded, _ = Outer().decode(outer.encode())
5829 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5832 class TestAbsDecodePath(TestCase):
5834 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5835 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5837 def test_concat(self, decode_path, rel_path):
5838 self.assertSequenceEqual(
5839 abs_decode_path(decode_path, rel_path),
5840 decode_path + rel_path,
5844 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5845 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5847 def test_abs(self, decode_path, rel_path):
5848 self.assertSequenceEqual(
5849 abs_decode_path(decode_path, ("/",) + rel_path),
5854 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5855 integers(min_value=1, max_value=3),
5856 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5858 def test_dots(self, decode_path, number_of_dots, rel_path):
5859 self.assertSequenceEqual(
5860 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5861 decode_path[:-number_of_dots] + rel_path,
5865 class TestStrictDefaultExistence(TestCase):
5866 @given(data_strategy())
5867 def runTest(self, d):
5868 count = d.draw(integers(min_value=1, max_value=10))
5869 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5871 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5872 for i in range(count)
5875 class Seq(Sequence):
5878 for i in range(count):
5879 seq["int%d" % i] = Integer(123)
5881 chosen = "int%d" % chosen
5882 seq.specs[chosen] = seq.specs[chosen](default=123)
5884 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5885 seq.decode(raw, ctx={"strict_default_existence": True})
5888 class TestX690PrefixedType(TestCase):
5890 self.assertSequenceEqual(
5891 VisibleString("Jones").encode(),
5892 hexdec("1A054A6F6E6573"),
5894 self.assertSequenceEqual(
5897 impl=tag_encode(3, klass=TagClassApplication),
5899 hexdec("43054A6F6E6573"),
5901 self.assertSequenceEqual(
5905 impl=tag_encode(3, klass=TagClassApplication),
5909 hexdec("A20743054A6F6E6573"),
5911 self.assertSequenceEqual(
5915 impl=tag_encode(3, klass=TagClassApplication),
5917 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5919 hexdec("670743054A6F6E6573"),
5921 self.assertSequenceEqual(
5922 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5923 hexdec("82054A6F6E6573"),
5927 class TestExplOOB(TestCase):
5929 expl = tag_ctxc(123)
5930 raw = Integer(123).encode() + Integer(234).encode()
5931 raw = b"".join((expl, len_encode(len(raw)), raw))
5932 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
5933 Integer(expl=expl).decode(raw)
5934 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})