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)
4752 self.assertFalse(seq_decoded.bered)
4754 t, _, lv = tag_strip(seq_encoded)
4755 _, _, v = len_decode(lv)
4756 seq_encoded_lenindef = t + LENINDEF + v + EOC
4757 seq_decoded_lenindef, tail_lenindef = seq.decode(
4758 seq_encoded_lenindef + tail_junk,
4759 ctx={"bered": True},
4761 self.assertTrue(seq_decoded_lenindef.lenindef)
4762 with self.assertRaises(DecodeError):
4763 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4764 with self.assertRaises(DecodeError):
4765 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4766 repr(seq_decoded_lenindef)
4767 pprint(seq_decoded_lenindef)
4768 self.assertTrue(seq_decoded_lenindef.ready)
4770 for decoded, decoded_tail, encoded in (
4771 (seq_decoded, tail, seq_encoded),
4772 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4774 self.assertEqual(decoded_tail, tail_junk)
4775 self._assert_expects(decoded, expects)
4776 self.assertEqual(seq, decoded)
4777 self.assertEqual(decoded.encode(), seq_encoded)
4778 self.assertEqual(decoded.tlvlen, len(encoded))
4779 for expect in expects:
4780 if not expect["presented"]:
4781 self.assertNotIn(expect["name"], decoded)
4783 self.assertIn(expect["name"], decoded)
4784 obj = decoded[expect["name"]]
4785 self.assertTrue(obj.decoded)
4786 offset = obj.expl_offset if obj.expled else obj.offset
4787 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4788 self.assertSequenceEqual(
4789 seq_encoded[offset:offset + tlvlen],
4793 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4794 @given(data_strategy())
4795 def test_symmetric_with_seq(self, d):
4796 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4797 self.assertTrue(seq.ready)
4798 seq_encoded = seq.encode()
4799 seq_decoded, tail = seq.decode(seq_encoded)
4800 self.assertEqual(tail, b"")
4801 self.assertTrue(seq.ready)
4802 self.assertEqual(seq, seq_decoded)
4803 self.assertEqual(seq_decoded.encode(), seq_encoded)
4804 for expect_outer in expect_outers:
4805 if not expect_outer["presented"]:
4806 self.assertNotIn(expect_outer["name"], seq_decoded)
4808 self.assertIn(expect_outer["name"], seq_decoded)
4809 obj = seq_decoded[expect_outer["name"]]
4810 self.assertTrue(obj.decoded)
4811 offset = obj.expl_offset if obj.expled else obj.offset
4812 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4813 self.assertSequenceEqual(
4814 seq_encoded[offset:offset + tlvlen],
4817 self._assert_expects(obj, expect_outer["expects"])
4819 @given(data_strategy())
4820 def test_default_disappears(self, d):
4821 _schema = list(d.draw(dictionaries(
4823 sets(integers(), min_size=2, max_size=2),
4827 class Seq(self.base_klass):
4829 (n, Integer(default=d))
4830 for n, (_, d) in _schema
4833 for name, (value, _) in _schema:
4834 seq[name] = Integer(value)
4835 self.assertEqual(len(seq._value), len(_schema))
4836 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4837 self.assertGreater(len(seq.encode()), len(empty_seq))
4838 for name, (_, default) in _schema:
4839 seq[name] = Integer(default)
4840 self.assertEqual(len(seq._value), 0)
4841 self.assertSequenceEqual(seq.encode(), empty_seq)
4843 @given(data_strategy())
4844 def test_encoded_default_not_accepted(self, d):
4845 _schema = list(d.draw(dictionaries(
4850 tags = [tag_encode(tag) for tag in d.draw(sets(
4851 integers(min_value=0),
4852 min_size=len(_schema),
4853 max_size=len(_schema),
4856 class SeqWithoutDefault(self.base_klass):
4858 (n, Integer(impl=t))
4859 for (n, _), t in zip(_schema, tags)
4861 seq_without_default = SeqWithoutDefault()
4862 for name, value in _schema:
4863 seq_without_default[name] = Integer(value)
4864 seq_encoded = seq_without_default.encode()
4866 class SeqWithDefault(self.base_klass):
4868 (n, Integer(default=v, impl=t))
4869 for (n, v), t in zip(_schema, tags)
4871 seq_with_default = SeqWithDefault()
4872 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
4873 seq_with_default.decode(seq_encoded)
4874 for ctx in ({"bered": True}, {"allow_default_values": True}):
4875 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
4876 self.assertTrue(seq_decoded.bered)
4877 for name, value in _schema:
4878 self.assertEqual(seq_decoded[name], seq_with_default[name])
4879 self.assertEqual(seq_decoded[name], value)
4881 @given(data_strategy())
4882 def test_missing_from_spec(self, d):
4883 names = list(d.draw(sets(text_letters(), min_size=2)))
4884 tags = [tag_encode(tag) for tag in d.draw(sets(
4885 integers(min_value=0),
4886 min_size=len(names),
4887 max_size=len(names),
4889 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4891 class SeqFull(self.base_klass):
4892 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4893 seq_full = SeqFull()
4894 for i, name in enumerate(names):
4895 seq_full[name] = Integer(i)
4896 seq_encoded = seq_full.encode()
4897 altered = names_tags[:-2] + names_tags[-1:]
4899 class SeqMissing(self.base_klass):
4900 schema = [(n, Integer(impl=t)) for n, t in altered]
4901 seq_missing = SeqMissing()
4902 with self.assertRaises(TagMismatch):
4903 seq_missing.decode(seq_encoded)
4906 class TestSequence(SeqMixing, CommonMixin, TestCase):
4907 base_klass = Sequence
4913 def test_remaining(self, value, junk):
4914 class Seq(Sequence):
4916 ("whatever", Integer()),
4918 int_encoded = Integer(value).encode()
4920 Sequence.tag_default,
4921 len_encode(len(int_encoded + junk)),
4924 with assertRaisesRegex(self, DecodeError, "remaining"):
4925 Seq().decode(junked)
4927 @given(sets(text_letters(), min_size=2))
4928 def test_obj_unknown(self, names):
4929 missing = names.pop()
4931 class Seq(Sequence):
4932 schema = [(n, Boolean()) for n in names]
4934 with self.assertRaises(ObjUnknown) as err:
4937 with self.assertRaises(ObjUnknown) as err:
4938 seq[missing] = Boolean()
4941 def test_x690_vector(self):
4942 class Seq(Sequence):
4944 ("name", IA5String()),
4947 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4948 self.assertEqual(seq["name"], "Smith")
4949 self.assertEqual(seq["ok"], True)
4952 class TestSet(SeqMixing, CommonMixin, TestCase):
4955 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4956 @given(data_strategy())
4957 def test_sorted(self, d):
4959 tag_encode(tag) for tag in
4960 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4964 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4966 for name, _ in Seq.schema:
4967 seq[name] = OctetString(b"")
4968 seq_encoded = seq.encode()
4969 seq_decoded, _ = seq.decode(seq_encoded)
4970 self.assertSequenceEqual(
4971 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4972 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4977 def seqof_values_strategy(draw, schema=None, do_expl=False):
4979 schema = draw(sampled_from((Boolean(), Integer())))
4980 bound_min, bound_max = sorted(draw(sets(
4981 integers(min_value=0, max_value=10),
4985 if isinstance(schema, Boolean):
4986 values_generator = booleans().map(Boolean)
4987 elif isinstance(schema, Integer):
4988 values_generator = integers().map(Integer)
4989 values_generator = lists(
4994 values = draw(one_of(none(), values_generator))
4998 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5000 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5001 default = draw(one_of(none(), values_generator))
5002 optional = draw(one_of(none(), booleans()))
5004 draw(integers(min_value=0)),
5005 draw(integers(min_value=0)),
5006 draw(integers(min_value=0)),
5011 (bound_min, bound_max),
5020 class SeqOfMixing(object):
5021 def test_invalid_value_type(self):
5022 with self.assertRaises(InvalidValueType) as err:
5023 self.base_klass(123)
5026 def test_invalid_values_type(self):
5027 class SeqOf(self.base_klass):
5029 with self.assertRaises(InvalidValueType) as err:
5030 SeqOf([Integer(123), Boolean(False), Integer(234)])
5033 def test_schema_required(self):
5034 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5035 self.base_klass.__mro__[1]()
5037 @given(booleans(), booleans(), binary(), binary())
5038 def test_comparison(self, value1, value2, tag1, tag2):
5039 class SeqOf(self.base_klass):
5041 obj1 = SeqOf([Boolean(value1)])
5042 obj2 = SeqOf([Boolean(value2)])
5043 self.assertEqual(obj1 == obj2, value1 == value2)
5044 self.assertEqual(obj1 != obj2, value1 != value2)
5045 self.assertEqual(obj1 == list(obj2), value1 == value2)
5046 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5047 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5048 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5049 self.assertEqual(obj1 == obj2, tag1 == tag2)
5050 self.assertEqual(obj1 != obj2, tag1 != tag2)
5052 @given(lists(booleans()))
5053 def test_iter(self, values):
5054 class SeqOf(self.base_klass):
5056 obj = SeqOf([Boolean(value) for value in values])
5057 self.assertEqual(len(obj), len(values))
5058 for i, value in enumerate(obj):
5059 self.assertEqual(value, values[i])
5061 @given(data_strategy())
5062 def test_ready(self, d):
5063 ready = [Integer(v) for v in d.draw(lists(
5070 range(d.draw(integers(min_value=1, max_value=5)))
5073 class SeqOf(self.base_klass):
5075 values = d.draw(permutations(ready + non_ready))
5077 for value in values:
5079 self.assertFalse(seqof.ready)
5082 with self.assertRaises(ObjNotReady) as err:
5085 for i, value in enumerate(values):
5086 self.assertEqual(seqof[i], value)
5087 if not seqof[i].ready:
5088 seqof[i] = Integer(i)
5089 self.assertTrue(seqof.ready)
5093 def test_spec_mismatch(self):
5094 class SeqOf(self.base_klass):
5097 seqof.append(Integer(123))
5098 with self.assertRaises(ValueError):
5099 seqof.append(Boolean(False))
5100 with self.assertRaises(ValueError):
5101 seqof[0] = Boolean(False)
5103 @given(data_strategy())
5104 def test_bounds_satisfied(self, d):
5105 class SeqOf(self.base_klass):
5107 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5108 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5109 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5110 SeqOf(value=value, bounds=(bound_min, bound_max))
5112 @given(data_strategy())
5113 def test_bounds_unsatisfied(self, d):
5114 class SeqOf(self.base_klass):
5116 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5117 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5118 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5119 with self.assertRaises(BoundsError) as err:
5120 SeqOf(value=value, bounds=(bound_min, bound_max))
5122 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5123 SeqOf(bounds=(bound_min, bound_max)).decode(
5124 SeqOf(value).encode()
5127 value = [Boolean(True)] * d.draw(integers(
5128 min_value=bound_max + 1,
5129 max_value=bound_max + 10,
5131 with self.assertRaises(BoundsError) as err:
5132 SeqOf(value=value, bounds=(bound_min, bound_max))
5134 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5135 SeqOf(bounds=(bound_min, bound_max)).decode(
5136 SeqOf(value).encode()
5140 @given(integers(min_value=1, max_value=10))
5141 def test_out_of_bounds(self, bound_max):
5142 class SeqOf(self.base_klass):
5144 bounds = (0, bound_max)
5146 for _ in range(bound_max):
5147 seqof.append(Integer(123))
5148 with self.assertRaises(BoundsError):
5149 seqof.append(Integer(123))
5151 @given(data_strategy())
5152 def test_call(self, d):
5162 ) = d.draw(seqof_values_strategy())
5164 class SeqOf(self.base_klass):
5165 schema = schema_initial
5166 obj_initial = SeqOf(
5167 value=value_initial,
5168 bounds=bounds_initial,
5171 default=default_initial,
5172 optional=optional_initial or False,
5173 _decoded=_decoded_initial,
5184 ) = d.draw(seqof_values_strategy(
5185 schema=schema_initial,
5186 do_expl=impl_initial is None,
5188 if (default is None) and (obj_initial.default is not None):
5191 (bounds is None) and
5192 (value is not None) and
5193 (bounds_initial is not None) and
5194 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5198 (bounds is None) and
5199 (default is not None) and
5200 (bounds_initial is not None) and
5201 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5213 value_expected = default if value is None else value
5215 default_initial if value_expected is None
5218 value_expected = () if value_expected is None else value_expected
5219 self.assertEqual(obj, value_expected)
5220 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5221 self.assertEqual(obj.expl_tag, expl or expl_initial)
5224 default_initial if default is None else default,
5226 if obj.default is None:
5227 optional = optional_initial if optional is None else optional
5228 optional = False if optional is None else optional
5231 self.assertEqual(obj.optional, optional)
5233 (obj._bound_min, obj._bound_max),
5234 bounds or bounds_initial or (0, float("+inf")),
5237 @given(seqof_values_strategy())
5238 def test_copy(self, values):
5239 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5241 class SeqOf(self.base_klass):
5249 optional=optional or False,
5252 obj_copied = obj.copy()
5253 self.assert_copied_basic_fields(obj, obj_copied)
5254 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5255 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5256 self.assertEqual(obj._value, obj_copied._value)
5260 integers(min_value=1).map(tag_encode),
5262 def test_stripped(self, values, tag_impl):
5263 class SeqOf(self.base_klass):
5264 schema = OctetString()
5265 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5266 with self.assertRaises(NotEnoughData):
5267 obj.decode(obj.encode()[:-1])
5271 integers(min_value=1).map(tag_ctxc),
5273 def test_stripped_expl(self, values, tag_expl):
5274 class SeqOf(self.base_klass):
5275 schema = OctetString()
5276 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5277 with self.assertRaises(NotEnoughData):
5278 obj.decode(obj.encode()[:-1])
5281 integers(min_value=31),
5282 integers(min_value=0),
5285 def test_bad_tag(self, tag, offset, decode_path):
5286 with self.assertRaises(DecodeError) as err:
5287 self.base_klass().decode(
5288 tag_encode(tag)[:-1],
5290 decode_path=decode_path,
5293 self.assertEqual(err.exception.offset, offset)
5294 self.assertEqual(err.exception.decode_path, decode_path)
5297 integers(min_value=128),
5298 integers(min_value=0),
5301 def test_bad_len(self, l, offset, decode_path):
5302 with self.assertRaises(DecodeError) as err:
5303 self.base_klass().decode(
5304 self.base_klass.tag_default + len_encode(l)[:-1],
5306 decode_path=decode_path,
5309 self.assertEqual(err.exception.offset, offset)
5310 self.assertEqual(err.exception.decode_path, decode_path)
5312 @given(binary(min_size=1))
5313 def test_tag_mismatch(self, impl):
5314 assume(impl != self.base_klass.tag_default)
5315 with self.assertRaises(TagMismatch):
5316 self.base_klass(impl=impl).decode(self.base_klass().encode())
5318 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5320 seqof_values_strategy(schema=Integer()),
5321 lists(integers().map(Integer)),
5322 integers(min_value=1).map(tag_ctxc),
5323 integers(min_value=0),
5326 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5327 _, _, _, _, _, default, optional, _decoded = values
5329 class SeqOf(self.base_klass):
5339 self.assertFalse(obj.expled)
5340 obj_encoded = obj.encode()
5341 obj_expled = obj(value, expl=tag_expl)
5342 self.assertTrue(obj_expled.expled)
5345 obj_expled_encoded = obj_expled.encode()
5346 obj_decoded, tail = obj_expled.decode(
5347 obj_expled_encoded + tail_junk,
5352 self.assertEqual(tail, tail_junk)
5353 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5354 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5355 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5356 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5358 obj_decoded.expl_llen,
5359 len(len_encode(len(obj_encoded))),
5361 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5362 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5365 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5367 self.assertEqual(obj_decoded.expl_offset, offset)
5368 for obj_inner in obj_decoded:
5369 self.assertIn(obj_inner, obj_decoded)
5370 self.assertSequenceEqual(
5373 obj_inner.offset - offset:
5374 obj_inner.offset + obj_inner.tlvlen - offset
5378 t, _, lv = tag_strip(obj_encoded)
5379 _, _, v = len_decode(lv)
5380 obj_encoded_lenindef = t + LENINDEF + v + EOC
5381 obj_decoded_lenindef, tail_lenindef = obj.decode(
5382 obj_encoded_lenindef + tail_junk,
5383 ctx={"bered": True},
5385 self.assertTrue(obj_decoded_lenindef.lenindef)
5386 repr(obj_decoded_lenindef)
5387 pprint(obj_decoded_lenindef)
5388 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5389 with self.assertRaises(DecodeError):
5390 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5391 with self.assertRaises(DecodeError):
5392 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5395 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5396 class SeqOf(SequenceOf):
5400 def _test_symmetric_compare_objs(self, obj1, obj2):
5401 self.assertEqual(obj1, obj2)
5402 self.assertSequenceEqual(list(obj1), list(obj2))
5405 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5410 def _test_symmetric_compare_objs(self, obj1, obj2):
5411 self.assertSetEqual(
5412 set(int(v) for v in obj1),
5413 set(int(v) for v in obj2),
5416 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5417 @given(data_strategy())
5418 def test_sorted(self, d):
5419 values = [OctetString(v) for v in d.draw(lists(binary()))]
5422 schema = OctetString()
5424 seq_encoded = seq.encode()
5425 seq_decoded, _ = seq.decode(seq_encoded)
5426 self.assertSequenceEqual(
5427 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5428 b"".join(sorted([v.encode() for v in values])),
5432 class TestGoMarshalVectors(TestCase):
5434 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5435 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5436 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5437 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5438 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5440 class Seq(Sequence):
5442 ("erste", Integer()),
5443 ("zweite", Integer(optional=True))
5446 seq["erste"] = Integer(64)
5447 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5448 seq["erste"] = Integer(0x123456)
5449 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5450 seq["erste"] = Integer(64)
5451 seq["zweite"] = Integer(65)
5452 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5454 class NestedSeq(Sequence):
5458 seq["erste"] = Integer(127)
5459 seq["zweite"] = None
5460 nested = NestedSeq()
5461 nested["nest"] = seq
5462 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5464 self.assertSequenceEqual(
5465 OctetString(b"\x01\x02\x03").encode(),
5466 hexdec("0403010203"),
5469 class Seq(Sequence):
5471 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5474 seq["erste"] = Integer(64)
5475 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5477 class Seq(Sequence):
5479 ("erste", Integer(expl=tag_ctxc(5))),
5482 seq["erste"] = Integer(64)
5483 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5485 class Seq(Sequence):
5488 impl=tag_encode(0, klass=TagClassContext),
5493 seq["erste"] = Null()
5494 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5496 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5498 self.assertSequenceEqual(
5499 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5500 hexdec("170d3730303130313030303030305a"),
5502 self.assertSequenceEqual(
5503 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5504 hexdec("170d3039313131353232353631365a"),
5506 self.assertSequenceEqual(
5507 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5508 hexdec("180f32313030303430353132303130315a"),
5511 class Seq(Sequence):
5513 ("erste", GeneralizedTime()),
5516 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5517 self.assertSequenceEqual(
5519 hexdec("3011180f32303039313131353232353631365a"),
5522 self.assertSequenceEqual(
5523 BitString((1, b"\x80")).encode(),
5526 self.assertSequenceEqual(
5527 BitString((12, b"\x81\xF0")).encode(),
5528 hexdec("03030481f0"),
5531 self.assertSequenceEqual(
5532 ObjectIdentifier("1.2.3.4").encode(),
5533 hexdec("06032a0304"),
5535 self.assertSequenceEqual(
5536 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5537 hexdec("06092a864888932d010105"),
5539 self.assertSequenceEqual(
5540 ObjectIdentifier("2.100.3").encode(),
5541 hexdec("0603813403"),
5544 self.assertSequenceEqual(
5545 PrintableString("test").encode(),
5546 hexdec("130474657374"),
5548 self.assertSequenceEqual(
5549 PrintableString("x" * 127).encode(),
5550 hexdec("137F" + "78" * 127),
5552 self.assertSequenceEqual(
5553 PrintableString("x" * 128).encode(),
5554 hexdec("138180" + "78" * 128),
5556 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5558 class Seq(Sequence):
5560 ("erste", IA5String()),
5563 seq["erste"] = IA5String("test")
5564 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5566 class Seq(Sequence):
5568 ("erste", PrintableString()),
5571 seq["erste"] = PrintableString("test")
5572 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5573 seq["erste"] = PrintableString("test*")
5574 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5576 class Seq(Sequence):
5578 ("erste", Any(optional=True)),
5579 ("zweite", Integer()),
5582 seq["zweite"] = Integer(64)
5583 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5588 seq.append(Integer(10))
5589 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5591 class _SeqOf(SequenceOf):
5592 schema = PrintableString()
5594 class SeqOf(SequenceOf):
5597 _seqof.append(PrintableString("1"))
5599 seqof.append(_seqof)
5600 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5602 class Seq(Sequence):
5604 ("erste", Integer(default=1)),
5607 seq["erste"] = Integer(0)
5608 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5609 seq["erste"] = Integer(1)
5610 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5611 seq["erste"] = Integer(2)
5612 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5615 class TestPP(TestCase):
5616 @given(data_strategy())
5617 def test_oid_printing(self, d):
5619 str(ObjectIdentifier(k)): v * 2
5620 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5622 chosen = d.draw(sampled_from(sorted(oids)))
5623 chosen_id = oids[chosen]
5624 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5625 self.assertNotIn(chosen_id, pp_console_row(pp))
5626 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5629 class TestAutoAddSlots(TestCase):
5631 class Inher(Integer):
5634 with self.assertRaises(AttributeError):
5636 inher.unexistent = "whatever"
5639 class TestOIDDefines(TestCase):
5640 @given(data_strategy())
5641 def runTest(self, d):
5642 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5643 value_name_chosen = d.draw(sampled_from(value_names))
5645 ObjectIdentifier(oid)
5646 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5648 oid_chosen = d.draw(sampled_from(oids))
5649 values = d.draw(lists(
5651 min_size=len(value_names),
5652 max_size=len(value_names),
5655 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5656 oid: Integer() for oid in oids[:-1]
5659 for i, value_name in enumerate(value_names):
5660 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5662 class Seq(Sequence):
5665 for value_name, value in zip(value_names, values):
5666 seq[value_name] = Any(Integer(value).encode())
5667 seq["type"] = oid_chosen
5668 seq, _ = Seq().decode(seq.encode())
5669 for value_name in value_names:
5670 if value_name == value_name_chosen:
5672 self.assertIsNone(seq[value_name].defined)
5673 if value_name_chosen in oids[:-1]:
5674 self.assertIsNotNone(seq[value_name_chosen].defined)
5675 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5676 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5679 class TestDefinesByPath(TestCase):
5680 def test_generated(self):
5681 class Seq(Sequence):
5683 ("type", ObjectIdentifier()),
5684 ("value", OctetString(expl=tag_ctxc(123))),
5687 class SeqInner(Sequence):
5689 ("typeInner", ObjectIdentifier()),
5690 ("valueInner", Any()),
5693 class PairValue(SetOf):
5696 class Pair(Sequence):
5698 ("type", ObjectIdentifier()),
5699 ("value", PairValue()),
5702 class Pairs(SequenceOf):
5709 type_octet_stringed,
5711 ObjectIdentifier(oid)
5712 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5714 seq_integered = Seq()
5715 seq_integered["type"] = type_integered
5716 seq_integered["value"] = OctetString(Integer(123).encode())
5717 seq_integered_raw = seq_integered.encode()
5721 (type_octet_stringed, OctetString(b"whatever")),
5722 (type_integered, Integer(123)),
5723 (type_octet_stringed, OctetString(b"whenever")),
5724 (type_integered, Integer(234)),
5726 for t, v in pairs_input:
5729 pair["value"] = PairValue((Any(v),))
5731 seq_inner = SeqInner()
5732 seq_inner["typeInner"] = type_innered
5733 seq_inner["valueInner"] = Any(pairs)
5734 seq_sequenced = Seq()
5735 seq_sequenced["type"] = type_sequenced
5736 seq_sequenced["value"] = OctetString(seq_inner.encode())
5737 seq_sequenced_raw = seq_sequenced.encode()
5739 defines_by_path = []
5740 seq_integered, _ = Seq().decode(seq_integered_raw)
5741 self.assertIsNone(seq_integered["value"].defined)
5742 defines_by_path.append(
5743 (("type",), ((("value",), {
5744 type_integered: Integer(),
5745 type_sequenced: SeqInner(),
5748 seq_integered, _ = Seq().decode(
5750 ctx={"defines_by_path": defines_by_path},
5752 self.assertIsNotNone(seq_integered["value"].defined)
5753 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5754 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5755 self.assertTrue(seq_integered_raw[
5756 seq_integered["value"].defined[1].offset:
5757 ].startswith(Integer(123).encode()))
5759 seq_sequenced, _ = Seq().decode(
5761 ctx={"defines_by_path": defines_by_path},
5763 self.assertIsNotNone(seq_sequenced["value"].defined)
5764 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5765 seq_inner = seq_sequenced["value"].defined[1]
5766 self.assertIsNone(seq_inner["valueInner"].defined)
5768 defines_by_path.append((
5769 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5770 ((("valueInner",), {type_innered: Pairs()}),),
5772 seq_sequenced, _ = Seq().decode(
5774 ctx={"defines_by_path": defines_by_path},
5776 self.assertIsNotNone(seq_sequenced["value"].defined)
5777 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5778 seq_inner = seq_sequenced["value"].defined[1]
5779 self.assertIsNotNone(seq_inner["valueInner"].defined)
5780 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5781 pairs = seq_inner["valueInner"].defined[1]
5783 self.assertIsNone(pair["value"][0].defined)
5785 defines_by_path.append((
5788 DecodePathDefBy(type_sequenced),
5790 DecodePathDefBy(type_innered),
5795 type_integered: Integer(),
5796 type_octet_stringed: OctetString(),
5799 seq_sequenced, _ = Seq().decode(
5801 ctx={"defines_by_path": defines_by_path},
5803 self.assertIsNotNone(seq_sequenced["value"].defined)
5804 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5805 seq_inner = seq_sequenced["value"].defined[1]
5806 self.assertIsNotNone(seq_inner["valueInner"].defined)
5807 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5808 pairs_got = seq_inner["valueInner"].defined[1]
5809 for pair_input, pair_got in zip(pairs_input, pairs_got):
5810 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5811 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5813 @given(oid_strategy(), integers())
5814 def test_simple(self, oid, tgt):
5815 class Inner(Sequence):
5817 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5818 ObjectIdentifier(oid): Integer(),
5822 class Outer(Sequence):
5825 ("tgt", OctetString()),
5829 inner["oid"] = ObjectIdentifier(oid)
5831 outer["inner"] = inner
5832 outer["tgt"] = OctetString(Integer(tgt).encode())
5833 decoded, _ = Outer().decode(outer.encode())
5834 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5837 class TestAbsDecodePath(TestCase):
5839 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5840 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5842 def test_concat(self, decode_path, rel_path):
5843 self.assertSequenceEqual(
5844 abs_decode_path(decode_path, rel_path),
5845 decode_path + rel_path,
5849 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5850 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5852 def test_abs(self, decode_path, rel_path):
5853 self.assertSequenceEqual(
5854 abs_decode_path(decode_path, ("/",) + rel_path),
5859 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5860 integers(min_value=1, max_value=3),
5861 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5863 def test_dots(self, decode_path, number_of_dots, rel_path):
5864 self.assertSequenceEqual(
5865 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5866 decode_path[:-number_of_dots] + rel_path,
5870 class TestStrictDefaultExistence(TestCase):
5871 @given(data_strategy())
5872 def runTest(self, d):
5873 count = d.draw(integers(min_value=1, max_value=10))
5874 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5876 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5877 for i in range(count)
5879 for klass in (Sequence, Set):
5883 for i in range(count):
5884 seq["int%d" % i] = Integer(123)
5886 chosen_choice = "int%d" % chosen
5887 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
5888 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5890 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
5891 self.assertTrue(decoded.bered)
5892 decoded, _ = seq.decode(raw, ctx={"bered": True})
5893 self.assertTrue(decoded.bered)
5896 class TestX690PrefixedType(TestCase):
5898 self.assertSequenceEqual(
5899 VisibleString("Jones").encode(),
5900 hexdec("1A054A6F6E6573"),
5902 self.assertSequenceEqual(
5905 impl=tag_encode(3, klass=TagClassApplication),
5907 hexdec("43054A6F6E6573"),
5909 self.assertSequenceEqual(
5913 impl=tag_encode(3, klass=TagClassApplication),
5917 hexdec("A20743054A6F6E6573"),
5919 self.assertSequenceEqual(
5923 impl=tag_encode(3, klass=TagClassApplication),
5925 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5927 hexdec("670743054A6F6E6573"),
5929 self.assertSequenceEqual(
5930 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5931 hexdec("82054A6F6E6573"),
5935 class TestExplOOB(TestCase):
5937 expl = tag_ctxc(123)
5938 raw = Integer(123).encode() + Integer(234).encode()
5939 raw = b"".join((expl, len_encode(len(raw)), raw))
5940 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
5941 Integer(expl=expl).decode(raw)
5942 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})