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.ber_encoded)
612 self.assertFalse(obj.lenindef)
613 self.assertTrue(obj.bered)
616 integers(min_value=1).map(tag_ctxc),
617 binary().filter(lambda x: not x.startswith(EOC)),
619 def test_ber_expl_no_eoc(self, expl, junk):
620 encoded = expl + LENINDEF + Boolean(False).encode()
621 with assertRaisesRegex(self, DecodeError, "no EOC"):
622 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
623 obj, tail = Boolean(expl=expl).decode(
624 encoded + EOC + junk,
627 self.assertTrue(obj.expl_lenindef)
628 self.assertFalse(obj.lenindef)
629 self.assertFalse(obj.ber_encoded)
630 self.assertTrue(obj.bered)
631 self.assertSequenceEqual(tail, junk)
634 integers(min_value=1).map(tag_ctxc),
641 def test_ber_expl(self, expl, values):
647 Boolean(value).encode() +
650 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
652 class SeqOf(SequenceOf):
653 schema = Boolean(expl=expl)
654 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
655 self.assertSequenceEqual(tail, b"")
656 self.assertSequenceEqual([bool(v) for v in seqof], values)
672 len(expl) + 1 + 3 + EOC_LEN,
684 def integer_values_strategy(draw, do_expl=False):
685 bound_min, value, default, bound_max = sorted(draw(sets(
694 _specs = draw(sets(text_letters()))
697 min_size=len(_specs),
698 max_size=len(_specs),
700 _specs = list(zip(_specs, values))
703 bounds = (bound_min, bound_max)
707 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
709 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
712 optional = draw(one_of(none(), booleans()))
714 draw(integers(min_value=0)),
715 draw(integers(min_value=0)),
716 draw(integers(min_value=0)),
718 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
721 class IntegerInherited(Integer):
725 class TestInteger(CommonMixin, TestCase):
728 def test_invalid_value_type(self):
729 with self.assertRaises(InvalidValueType) as err:
733 @given(sets(text_letters(), min_size=2))
734 def test_unknown_name(self, names_input):
735 missing = names_input.pop()
738 schema = [(n, 123) for n in names_input]
739 with self.assertRaises(ObjUnknown) as err:
743 @given(sets(text_letters(), min_size=2))
744 def test_known_name(self, names_input):
746 schema = [(n, 123) for n in names_input]
747 Int(names_input.pop())
750 def test_optional(self, optional):
751 obj = Integer(default=Integer(0), optional=optional)
752 self.assertTrue(obj.optional)
755 def test_ready(self, value):
757 self.assertFalse(obj.ready)
760 with self.assertRaises(ObjNotReady) as err:
764 self.assertTrue(obj.ready)
769 @given(integers(), integers(), binary(), binary())
770 def test_comparison(self, value1, value2, tag1, tag2):
771 for klass in (Integer, IntegerInherited):
774 self.assertEqual(obj1 == obj2, value1 == value2)
775 self.assertEqual(obj1 != obj2, value1 != value2)
776 self.assertEqual(obj1 == int(obj2), value1 == value2)
777 obj1 = klass(value1, impl=tag1)
778 obj2 = klass(value1, impl=tag2)
779 self.assertEqual(obj1 == obj2, tag1 == tag2)
780 self.assertEqual(obj1 != obj2, tag1 != tag2)
782 @given(lists(integers()))
783 def test_sorted_works(self, values):
784 self.assertSequenceEqual(
785 [int(v) for v in sorted(Integer(v) for v in values)],
789 @given(data_strategy())
790 def test_named(self, d):
791 names_input = list(d.draw(sets(text_letters(), min_size=1)))
792 values_input = list(d.draw(sets(
794 min_size=len(names_input),
795 max_size=len(names_input),
797 chosen_name = d.draw(sampled_from(names_input))
798 names_input = dict(zip(names_input, values_input))
802 _int = Int(chosen_name)
803 self.assertEqual(_int.named, chosen_name)
804 self.assertEqual(int(_int), names_input[chosen_name])
806 @given(integers(), integers(min_value=0), integers(min_value=0))
807 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
808 value = bound_min + value_delta
809 bound_max = value + bound_delta
810 Integer(value=value, bounds=(bound_min, bound_max))
812 @given(sets(integers(), min_size=3, max_size=3))
813 def test_bounds_unsatisfied(self, values):
814 values = sorted(values)
815 with self.assertRaises(BoundsError) as err:
816 Integer(value=values[0], bounds=(values[1], values[2]))
818 with assertRaisesRegex(self, DecodeError, "bounds") as err:
819 Integer(bounds=(values[1], values[2])).decode(
820 Integer(values[0]).encode()
823 with self.assertRaises(BoundsError) as err:
824 Integer(value=values[2], bounds=(values[0], values[1]))
826 with assertRaisesRegex(self, DecodeError, "bounds") as err:
827 Integer(bounds=(values[0], values[1])).decode(
828 Integer(values[2]).encode()
832 @given(data_strategy())
833 def test_call(self, d):
834 for klass in (Integer, IntegerInherited):
844 ) = d.draw(integer_values_strategy())
851 optional_initial or False,
864 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
865 if (default is None) and (obj_initial.default is not None):
869 (value is not None) and
870 (bounds_initial is not None) and
871 not (bounds_initial[0] <= value <= bounds_initial[1])
876 (default is not None) and
877 (bounds_initial is not None) and
878 not (bounds_initial[0] <= default <= bounds_initial[1])
881 obj = obj_initial(value, bounds, impl, expl, default, optional)
883 value_expected = default if value is None else value
885 default_initial if value_expected is None
888 self.assertEqual(obj, value_expected)
889 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
890 self.assertEqual(obj.expl_tag, expl or expl_initial)
893 default_initial if default is None else default,
895 if obj.default is None:
896 optional = optional_initial if optional is None else optional
897 optional = False if optional is None else optional
900 self.assertEqual(obj.optional, optional)
902 (obj._bound_min, obj._bound_max),
903 bounds or bounds_initial or (float("-inf"), float("+inf")),
907 {} if _specs_initial is None else dict(_specs_initial),
910 @given(integer_values_strategy())
911 def test_copy(self, values):
912 for klass in (Integer, IntegerInherited):
914 obj_copied = obj.copy()
915 self.assert_copied_basic_fields(obj, obj_copied)
916 self.assertEqual(obj.specs, obj_copied.specs)
917 self.assertEqual(obj._bound_min, obj_copied._bound_min)
918 self.assertEqual(obj._bound_max, obj_copied._bound_max)
919 self.assertEqual(obj._value, obj_copied._value)
923 integers(min_value=1).map(tag_encode),
925 def test_stripped(self, value, tag_impl):
926 obj = Integer(value, impl=tag_impl)
927 with self.assertRaises(NotEnoughData):
928 obj.decode(obj.encode()[:-1])
932 integers(min_value=1).map(tag_ctxc),
934 def test_stripped_expl(self, value, tag_expl):
935 obj = Integer(value, expl=tag_expl)
936 with self.assertRaises(NotEnoughData):
937 obj.decode(obj.encode()[:-1])
939 def test_zero_len(self):
940 with self.assertRaises(NotEnoughData):
941 Integer().decode(b"".join((
947 integers(min_value=31),
948 integers(min_value=0),
951 def test_bad_tag(self, tag, offset, decode_path):
952 with self.assertRaises(DecodeError) as err:
954 tag_encode(tag)[:-1],
956 decode_path=decode_path,
959 self.assertEqual(err.exception.offset, offset)
960 self.assertEqual(err.exception.decode_path, decode_path)
963 integers(min_value=128),
964 integers(min_value=0),
967 def test_bad_len(self, l, offset, decode_path):
968 with self.assertRaises(DecodeError) as err:
970 Integer.tag_default + len_encode(l)[:-1],
972 decode_path=decode_path,
975 self.assertEqual(err.exception.offset, offset)
976 self.assertEqual(err.exception.decode_path, decode_path)
979 sets(integers(), min_size=2, max_size=2),
980 integers(min_value=0),
983 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
984 value, bound_min = list(sorted(ints))
987 bounds = (bound_min, bound_min)
988 with self.assertRaises(DecodeError) as err:
990 Integer(value).encode(),
992 decode_path=decode_path,
995 self.assertEqual(err.exception.offset, offset)
996 self.assertEqual(err.exception.decode_path, decode_path)
998 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1000 integer_values_strategy(),
1002 integers(min_value=1).map(tag_ctxc),
1003 integers(min_value=0),
1006 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1007 for klass in (Integer, IntegerInherited):
1008 _, _, _, _, default, optional, _, _decoded = values
1017 self.assertFalse(obj.expled)
1018 obj_encoded = obj.encode()
1019 obj_expled = obj(value, expl=tag_expl)
1020 self.assertTrue(obj_expled.expled)
1023 obj_expled_encoded = obj_expled.encode()
1024 obj_decoded, tail = obj_expled.decode(
1025 obj_expled_encoded + tail_junk,
1030 self.assertEqual(tail, tail_junk)
1031 self.assertEqual(obj_decoded, obj_expled)
1032 self.assertNotEqual(obj_decoded, obj)
1033 self.assertEqual(int(obj_decoded), int(obj_expled))
1034 self.assertEqual(int(obj_decoded), int(obj))
1035 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1036 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1037 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1039 obj_decoded.expl_llen,
1040 len(len_encode(len(obj_encoded))),
1042 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1043 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1046 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1048 self.assertEqual(obj_decoded.expl_offset, offset)
1050 def test_go_vectors_valid(self):
1051 for data, expect in ((
1055 (b"\xff\x7f", -129),
1059 (b"\xff\x00", -256),
1063 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1064 (b"\x80\x00\x00\x00", -2147483648),
1067 Integer().decode(b"".join((
1068 Integer.tag_default,
1069 len_encode(len(data)),
1075 def test_go_vectors_invalid(self):
1080 with self.assertRaises(DecodeError):
1081 Integer().decode(b"".join((
1082 Integer.tag_default,
1083 len_encode(len(data)),
1089 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1092 if draw(booleans()):
1093 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1095 integers(min_value=0, max_value=255),
1096 min_size=len(schema),
1097 max_size=len(schema),
1099 schema = list(zip(schema, bits))
1101 def _value(value_required):
1102 if not value_required and draw(booleans()):
1104 generation_choice = 0
1106 generation_choice = draw(sampled_from((1, 2, 3)))
1107 if generation_choice == 1 or draw(booleans()):
1108 return "'%s'B" % "".join(draw(lists(
1109 sampled_from(("0", "1")),
1110 max_size=len(schema),
1112 elif generation_choice == 2 or draw(booleans()):
1113 return draw(binary(max_size=len(schema) // 8))
1114 elif generation_choice == 3 or draw(booleans()):
1115 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1117 value = _value(value_required)
1118 default = _value(value_required=False)
1122 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1124 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1125 optional = draw(one_of(none(), booleans()))
1127 draw(integers(min_value=0)),
1128 draw(integers(min_value=0)),
1129 draw(integers(min_value=0)),
1131 return (schema, value, impl, expl, default, optional, _decoded)
1134 class BitStringInherited(BitString):
1138 class TestBitString(CommonMixin, TestCase):
1139 base_klass = BitString
1141 @given(lists(booleans()))
1142 def test_b_encoding(self, bits):
1143 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1144 self.assertEqual(obj.bit_len, len(bits))
1145 self.assertSequenceEqual(list(obj), bits)
1146 for i, bit in enumerate(bits):
1147 self.assertEqual(obj[i], bit)
1149 @given(lists(booleans()))
1150 def test_out_of_bounds_bits(self, bits):
1151 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1152 for i in range(len(bits), len(bits) * 2):
1153 self.assertFalse(obj[i])
1155 def test_bad_b_encoding(self):
1156 with self.assertRaises(ValueError):
1157 BitString("'010120101'B")
1160 integers(min_value=1, max_value=255),
1161 integers(min_value=1, max_value=255),
1163 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1164 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1165 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1166 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1168 class BS(BitString):
1169 schema = (("whatever", 0),)
1170 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1171 self.assertEqual(obj.bit_len, leading_zeros + 1)
1172 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1174 def test_zero_len(self):
1175 with self.assertRaises(NotEnoughData):
1176 BitString().decode(b"".join((
1177 BitString.tag_default,
1181 def test_invalid_value_type(self):
1182 with self.assertRaises(InvalidValueType) as err:
1185 with self.assertRaises(InvalidValueType) as err:
1189 def test_obj_unknown(self):
1190 with self.assertRaises(ObjUnknown) as err:
1191 BitString(b"whatever")["whenever"]
1194 def test_get_invalid_type(self):
1195 with self.assertRaises(InvalidValueType) as err:
1196 BitString(b"whatever")[(1, 2, 3)]
1199 @given(data_strategy())
1200 def test_unknown_name(self, d):
1201 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1202 missing = _schema.pop()
1204 class BS(BitString):
1205 schema = [(n, i) for i, n in enumerate(_schema)]
1206 with self.assertRaises(ObjUnknown) as err:
1211 def test_optional(self, optional):
1212 obj = BitString(default=BitString(b""), optional=optional)
1213 self.assertTrue(obj.optional)
1216 def test_ready(self, value):
1218 self.assertFalse(obj.ready)
1221 with self.assertRaises(ObjNotReady) as err:
1224 obj = BitString(value)
1225 self.assertTrue(obj.ready)
1230 tuples(integers(min_value=0), binary()),
1231 tuples(integers(min_value=0), binary()),
1235 def test_comparison(self, value1, value2, tag1, tag2):
1236 for klass in (BitString, BitStringInherited):
1237 obj1 = klass(value1)
1238 obj2 = klass(value2)
1239 self.assertEqual(obj1 == obj2, value1 == value2)
1240 self.assertEqual(obj1 != obj2, value1 != value2)
1241 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1242 obj1 = klass(value1, impl=tag1)
1243 obj2 = klass(value1, impl=tag2)
1244 self.assertEqual(obj1 == obj2, tag1 == tag2)
1245 self.assertEqual(obj1 != obj2, tag1 != tag2)
1247 @given(data_strategy())
1248 def test_call(self, d):
1249 for klass in (BitString, BitStringInherited):
1258 ) = d.draw(bit_string_values_strategy())
1261 schema = schema_initial
1263 value=value_initial,
1266 default=default_initial,
1267 optional=optional_initial or False,
1268 _decoded=_decoded_initial,
1278 ) = d.draw(bit_string_values_strategy(
1279 schema=schema_initial,
1280 do_expl=impl_initial is None,
1289 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1290 self.assertEqual(obj.expl_tag, expl or expl_initial)
1291 if obj.default is None:
1292 optional = optional_initial if optional is None else optional
1293 optional = False if optional is None else optional
1296 self.assertEqual(obj.optional, optional)
1297 self.assertEqual(obj.specs, obj_initial.specs)
1299 @given(bit_string_values_strategy())
1300 def test_copy(self, values):
1301 for klass in (BitString, BitStringInherited):
1302 _schema, value, impl, expl, default, optional, _decoded = values
1311 optional=optional or False,
1314 obj_copied = obj.copy()
1315 self.assert_copied_basic_fields(obj, obj_copied)
1316 self.assertEqual(obj.specs, obj_copied.specs)
1317 self.assertEqual(obj._value, obj_copied._value)
1321 integers(min_value=1).map(tag_encode),
1323 def test_stripped(self, value, tag_impl):
1324 obj = BitString(value, impl=tag_impl)
1325 with self.assertRaises(NotEnoughData):
1326 obj.decode(obj.encode()[:-1])
1330 integers(min_value=1).map(tag_ctxc),
1332 def test_stripped_expl(self, value, tag_expl):
1333 obj = BitString(value, expl=tag_expl)
1334 with self.assertRaises(NotEnoughData):
1335 obj.decode(obj.encode()[:-1])
1338 integers(min_value=31),
1339 integers(min_value=0),
1342 def test_bad_tag(self, tag, offset, decode_path):
1343 with self.assertRaises(DecodeError) as err:
1345 tag_encode(tag)[:-1],
1347 decode_path=decode_path,
1350 self.assertEqual(err.exception.offset, offset)
1351 self.assertEqual(err.exception.decode_path, decode_path)
1354 integers(min_value=128),
1355 integers(min_value=0),
1358 def test_bad_len(self, l, offset, decode_path):
1359 with self.assertRaises(DecodeError) as err:
1361 BitString.tag_default + len_encode(l)[:-1],
1363 decode_path=decode_path,
1366 self.assertEqual(err.exception.offset, offset)
1367 self.assertEqual(err.exception.decode_path, decode_path)
1369 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1370 @given(data_strategy())
1371 def test_symmetric(self, d):
1380 ) = d.draw(bit_string_values_strategy(value_required=True))
1381 tail_junk = d.draw(binary(max_size=5))
1382 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1383 offset = d.draw(integers(min_value=0))
1384 for klass in (BitString, BitStringInherited):
1395 self.assertFalse(obj.expled)
1396 obj_encoded = obj.encode()
1397 obj_expled = obj(value, expl=tag_expl)
1398 self.assertTrue(obj_expled.expled)
1401 obj_expled_encoded = obj_expled.encode()
1402 obj_decoded, tail = obj_expled.decode(
1403 obj_expled_encoded + tail_junk,
1408 self.assertEqual(tail, tail_junk)
1409 self.assertEqual(obj_decoded, obj_expled)
1410 self.assertNotEqual(obj_decoded, obj)
1411 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1412 self.assertEqual(bytes(obj_decoded), bytes(obj))
1413 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1414 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1415 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1417 obj_decoded.expl_llen,
1418 len(len_encode(len(obj_encoded))),
1420 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1421 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1424 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1426 self.assertEqual(obj_decoded.expl_offset, offset)
1427 if isinstance(value, tuple):
1428 self.assertSetEqual(set(value), set(obj_decoded.named))
1432 @given(integers(min_value=1, max_value=255))
1433 def test_bad_zero_value(self, pad_size):
1434 with self.assertRaises(DecodeError):
1435 BitString().decode(b"".join((
1436 BitString.tag_default,
1441 def test_go_vectors_invalid(self):
1447 with self.assertRaises(DecodeError):
1448 BitString().decode(b"".join((
1449 BitString.tag_default,
1454 def test_go_vectors_valid(self):
1455 obj, _ = BitString().decode(b"".join((
1456 BitString.tag_default,
1460 self.assertEqual(bytes(obj), b"")
1461 self.assertEqual(obj.bit_len, 0)
1463 obj, _ = BitString().decode(b"".join((
1464 BitString.tag_default,
1468 self.assertEqual(bytes(obj), b"\x00")
1469 self.assertEqual(obj.bit_len, 1)
1471 obj = BitString((16, b"\x82\x40"))
1472 self.assertTrue(obj[0])
1473 self.assertFalse(obj[1])
1474 self.assertTrue(obj[6])
1475 self.assertTrue(obj[9])
1476 self.assertFalse(obj[17])
1479 integers(min_value=1, max_value=30),
1482 binary(min_size=1, max_size=5),
1484 binary(min_size=1, max_size=5),
1492 lists(booleans(), min_size=1),
1495 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1496 def chunk_constructed(contents):
1498 tag_encode(form=TagFormConstructed, num=3) +
1500 b"".join(BitString(content).encode() for content in contents) +
1504 payload_expected = b""
1505 bit_len_expected = 0
1506 for chunk_input in chunk_inputs:
1507 if isinstance(chunk_input, binary_type):
1508 chunks.append(BitString(chunk_input).encode())
1509 payload_expected += chunk_input
1510 bit_len_expected += len(chunk_input) * 8
1512 chunks.append(chunk_constructed(chunk_input))
1513 payload = b"".join(chunk_input)
1514 payload_expected += payload
1515 bit_len_expected += len(payload) * 8
1516 chunk_last = BitString("'%s'B" % "".join(
1517 "1" if bit else "0" for bit in chunk_last_bits
1519 payload_expected += bytes(chunk_last)
1520 bit_len_expected += chunk_last.bit_len
1521 encoded_indefinite = (
1522 tag_encode(form=TagFormConstructed, num=impl) +
1525 chunk_last.encode() +
1528 encoded_definite = (
1529 tag_encode(form=TagFormConstructed, num=impl) +
1530 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1534 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1535 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1536 for lenindef_expected, encoded in (
1537 (True, encoded_indefinite),
1538 (False, encoded_definite),
1540 obj, tail = BitString(impl=tag_encode(impl)).decode(
1542 ctx={"bered": True},
1544 self.assertSequenceEqual(tail, junk)
1545 self.assertEqual(obj.bit_len, bit_len_expected)
1546 self.assertSequenceEqual(bytes(obj), payload_expected)
1547 self.assertTrue(obj.ber_encoded)
1548 self.assertEqual(obj.lenindef, lenindef_expected)
1549 self.assertTrue(obj.bered)
1550 self.assertEqual(len(encoded), obj.tlvlen)
1553 integers(min_value=0),
1556 def test_ber_definite_too_short(self, offset, decode_path):
1557 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1559 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1561 decode_path=decode_path,
1562 ctx={"bered": True},
1564 self.assertEqual(err.exception.decode_path, decode_path)
1565 self.assertEqual(err.exception.offset, offset)
1568 integers(min_value=0),
1571 def test_ber_definite_no_data(self, offset, decode_path):
1572 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1574 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1576 decode_path=decode_path,
1577 ctx={"bered": True},
1579 self.assertEqual(err.exception.decode_path, decode_path)
1580 self.assertEqual(err.exception.offset, offset)
1583 integers(min_value=0),
1585 integers(min_value=1, max_value=3),
1587 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1588 bs = BitString(b"data").encode()
1589 with self.assertRaises(NotEnoughData) as err:
1591 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1593 decode_path=decode_path,
1594 ctx={"bered": True},
1596 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1597 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1600 integers(min_value=0),
1602 integers(min_value=1, max_value=3),
1604 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1605 bs = BitString(b"data").encode()
1606 bs_longer = BitString(b"data-longer").encode()
1607 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1610 tag_encode(3, form=TagFormConstructed) +
1611 len_encode((chunks + 1) * len(bs)) +
1616 decode_path=decode_path,
1617 ctx={"bered": True},
1619 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1620 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1623 integers(min_value=0),
1626 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1627 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1629 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1631 decode_path=decode_path,
1632 ctx={"bered": True},
1634 self.assertEqual(err.exception.decode_path, decode_path)
1635 self.assertEqual(err.exception.offset, offset)
1637 @given(data_strategy())
1638 def test_ber_indefinite_not_multiple(self, d):
1639 bs_short = BitString("'A'H").encode()
1640 bs_full = BitString("'AA'H").encode()
1641 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1642 chunks.append(bs_short)
1643 d.draw(permutations(chunks))
1644 chunks.append(bs_short)
1645 offset = d.draw(integers(min_value=0))
1646 decode_path = d.draw(decode_path_strat)
1647 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1650 tag_encode(3, form=TagFormConstructed) +
1656 decode_path=decode_path,
1657 ctx={"bered": True},
1660 err.exception.decode_path,
1661 decode_path + (str(chunks.index(bs_short)),),
1664 err.exception.offset,
1665 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1668 def test_x690_vector(self):
1669 vector = BitString("'0A3B5F291CD'H")
1670 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1671 self.assertSequenceEqual(tail, b"")
1672 self.assertEqual(obj, vector)
1673 obj, tail = BitString().decode(
1674 hexdec("23800303000A3B0305045F291CD00000"),
1675 ctx={"bered": True},
1677 self.assertSequenceEqual(tail, b"")
1678 self.assertEqual(obj, vector)
1679 self.assertTrue(obj.ber_encoded)
1680 self.assertTrue(obj.lenindef)
1681 self.assertTrue(obj.bered)
1685 def octet_string_values_strategy(draw, do_expl=False):
1686 bound_min, bound_max = sorted(draw(sets(
1687 integers(min_value=0, max_value=1 << 7),
1691 value = draw(one_of(
1693 binary(min_size=bound_min, max_size=bound_max),
1695 default = draw(one_of(
1697 binary(min_size=bound_min, max_size=bound_max),
1700 if draw(booleans()):
1701 bounds = (bound_min, bound_max)
1705 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1707 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1708 optional = draw(one_of(none(), booleans()))
1710 draw(integers(min_value=0)),
1711 draw(integers(min_value=0)),
1712 draw(integers(min_value=0)),
1714 return (value, bounds, impl, expl, default, optional, _decoded)
1717 class OctetStringInherited(OctetString):
1721 class TestOctetString(CommonMixin, TestCase):
1722 base_klass = OctetString
1724 def test_invalid_value_type(self):
1725 with self.assertRaises(InvalidValueType) as err:
1726 OctetString(text_type(123))
1730 def test_optional(self, optional):
1731 obj = OctetString(default=OctetString(b""), optional=optional)
1732 self.assertTrue(obj.optional)
1735 def test_ready(self, value):
1737 self.assertFalse(obj.ready)
1740 with self.assertRaises(ObjNotReady) as err:
1743 obj = OctetString(value)
1744 self.assertTrue(obj.ready)
1748 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1749 def test_comparison(self, value1, value2, tag1, tag2):
1750 for klass in (OctetString, OctetStringInherited):
1751 obj1 = klass(value1)
1752 obj2 = klass(value2)
1753 self.assertEqual(obj1 == obj2, value1 == value2)
1754 self.assertEqual(obj1 != obj2, value1 != value2)
1755 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1756 obj1 = klass(value1, impl=tag1)
1757 obj2 = klass(value1, impl=tag2)
1758 self.assertEqual(obj1 == obj2, tag1 == tag2)
1759 self.assertEqual(obj1 != obj2, tag1 != tag2)
1761 @given(lists(binary()))
1762 def test_sorted_works(self, values):
1763 self.assertSequenceEqual(
1764 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1768 @given(data_strategy())
1769 def test_bounds_satisfied(self, d):
1770 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1771 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1772 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1773 OctetString(value=value, bounds=(bound_min, bound_max))
1775 @given(data_strategy())
1776 def test_bounds_unsatisfied(self, d):
1777 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1778 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1779 value = d.draw(binary(max_size=bound_min - 1))
1780 with self.assertRaises(BoundsError) as err:
1781 OctetString(value=value, bounds=(bound_min, bound_max))
1783 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1784 OctetString(bounds=(bound_min, bound_max)).decode(
1785 OctetString(value).encode()
1788 value = d.draw(binary(min_size=bound_max + 1))
1789 with self.assertRaises(BoundsError) as err:
1790 OctetString(value=value, bounds=(bound_min, bound_max))
1792 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1793 OctetString(bounds=(bound_min, bound_max)).decode(
1794 OctetString(value).encode()
1798 @given(data_strategy())
1799 def test_call(self, d):
1800 for klass in (OctetString, OctetStringInherited):
1809 ) = d.draw(octet_string_values_strategy())
1810 obj_initial = klass(
1816 optional_initial or False,
1827 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1828 if (default is None) and (obj_initial.default is not None):
1831 (bounds is None) and
1832 (value is not None) and
1833 (bounds_initial is not None) and
1834 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1838 (bounds is None) and
1839 (default is not None) and
1840 (bounds_initial is not None) and
1841 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1844 obj = obj_initial(value, bounds, impl, expl, default, optional)
1846 value_expected = default if value is None else value
1848 default_initial if value_expected is None
1851 self.assertEqual(obj, value_expected)
1852 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1853 self.assertEqual(obj.expl_tag, expl or expl_initial)
1856 default_initial if default is None else default,
1858 if obj.default is None:
1859 optional = optional_initial if optional is None else optional
1860 optional = False if optional is None else optional
1863 self.assertEqual(obj.optional, optional)
1865 (obj._bound_min, obj._bound_max),
1866 bounds or bounds_initial or (0, float("+inf")),
1869 @given(octet_string_values_strategy())
1870 def test_copy(self, values):
1871 for klass in (OctetString, OctetStringInherited):
1872 obj = klass(*values)
1873 obj_copied = obj.copy()
1874 self.assert_copied_basic_fields(obj, obj_copied)
1875 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1876 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1877 self.assertEqual(obj._value, obj_copied._value)
1881 integers(min_value=1).map(tag_encode),
1883 def test_stripped(self, value, tag_impl):
1884 obj = OctetString(value, impl=tag_impl)
1885 with self.assertRaises(NotEnoughData):
1886 obj.decode(obj.encode()[:-1])
1890 integers(min_value=1).map(tag_ctxc),
1892 def test_stripped_expl(self, value, tag_expl):
1893 obj = OctetString(value, expl=tag_expl)
1894 with self.assertRaises(NotEnoughData):
1895 obj.decode(obj.encode()[:-1])
1898 integers(min_value=31),
1899 integers(min_value=0),
1902 def test_bad_tag(self, tag, offset, decode_path):
1903 with self.assertRaises(DecodeError) as err:
1904 OctetString().decode(
1905 tag_encode(tag)[:-1],
1907 decode_path=decode_path,
1910 self.assertEqual(err.exception.offset, offset)
1911 self.assertEqual(err.exception.decode_path, decode_path)
1914 integers(min_value=128),
1915 integers(min_value=0),
1918 def test_bad_len(self, l, offset, decode_path):
1919 with self.assertRaises(DecodeError) as err:
1920 OctetString().decode(
1921 OctetString.tag_default + len_encode(l)[:-1],
1923 decode_path=decode_path,
1926 self.assertEqual(err.exception.offset, offset)
1927 self.assertEqual(err.exception.decode_path, decode_path)
1930 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1931 integers(min_value=0),
1934 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1935 value, bound_min = list(sorted(ints))
1937 class String(OctetString):
1938 bounds = (bound_min, bound_min)
1939 with self.assertRaises(DecodeError) as err:
1941 OctetString(b"\x00" * value).encode(),
1943 decode_path=decode_path,
1946 self.assertEqual(err.exception.offset, offset)
1947 self.assertEqual(err.exception.decode_path, decode_path)
1949 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1951 octet_string_values_strategy(),
1953 integers(min_value=1).map(tag_ctxc),
1954 integers(min_value=0),
1957 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1958 for klass in (OctetString, OctetStringInherited):
1959 _, _, _, _, default, optional, _decoded = values
1968 self.assertFalse(obj.expled)
1969 obj_encoded = obj.encode()
1970 obj_expled = obj(value, expl=tag_expl)
1971 self.assertTrue(obj_expled.expled)
1974 obj_expled_encoded = obj_expled.encode()
1975 obj_decoded, tail = obj_expled.decode(
1976 obj_expled_encoded + tail_junk,
1981 self.assertEqual(tail, tail_junk)
1982 self.assertEqual(obj_decoded, obj_expled)
1983 self.assertNotEqual(obj_decoded, obj)
1984 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1985 self.assertEqual(bytes(obj_decoded), bytes(obj))
1986 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1987 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1988 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1990 obj_decoded.expl_llen,
1991 len(len_encode(len(obj_encoded))),
1993 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1994 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1997 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1999 self.assertEqual(obj_decoded.expl_offset, offset)
2002 integers(min_value=1, max_value=30),
2005 binary(min_size=1, max_size=5),
2007 binary(min_size=1, max_size=5),
2017 def test_constructed(self, impl, chunk_inputs, junk):
2018 def chunk_constructed(contents):
2020 tag_encode(form=TagFormConstructed, num=4) +
2022 b"".join(OctetString(content).encode() for content in contents) +
2026 payload_expected = b""
2027 for chunk_input in chunk_inputs:
2028 if isinstance(chunk_input, binary_type):
2029 chunks.append(OctetString(chunk_input).encode())
2030 payload_expected += chunk_input
2032 chunks.append(chunk_constructed(chunk_input))
2033 payload = b"".join(chunk_input)
2034 payload_expected += payload
2035 encoded_indefinite = (
2036 tag_encode(form=TagFormConstructed, num=impl) +
2041 encoded_definite = (
2042 tag_encode(form=TagFormConstructed, num=impl) +
2043 len_encode(len(b"".join(chunks))) +
2046 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2047 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2048 for lenindef_expected, encoded in (
2049 (True, encoded_indefinite),
2050 (False, encoded_definite),
2052 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2054 ctx={"bered": True},
2056 self.assertSequenceEqual(tail, junk)
2057 self.assertSequenceEqual(bytes(obj), payload_expected)
2058 self.assertTrue(obj.ber_encoded)
2059 self.assertEqual(obj.lenindef, lenindef_expected)
2060 self.assertTrue(obj.bered)
2061 self.assertEqual(len(encoded), obj.tlvlen)
2064 integers(min_value=0),
2067 def test_ber_definite_too_short(self, offset, decode_path):
2068 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2069 OctetString().decode(
2070 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2072 decode_path=decode_path,
2073 ctx={"bered": True},
2075 self.assertEqual(err.exception.decode_path, decode_path)
2076 self.assertEqual(err.exception.offset, offset)
2079 integers(min_value=0),
2081 integers(min_value=1, max_value=3),
2083 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2084 bs = OctetString(b"data").encode()
2085 with self.assertRaises(NotEnoughData) as err:
2086 OctetString().decode(
2087 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2089 decode_path=decode_path,
2090 ctx={"bered": True},
2092 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2093 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2096 integers(min_value=0),
2098 integers(min_value=1, max_value=3),
2100 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2101 bs = OctetString(b"data").encode()
2102 bs_longer = OctetString(b"data-longer").encode()
2103 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2104 OctetString().decode(
2106 tag_encode(4, form=TagFormConstructed) +
2107 len_encode((chunks + 1) * len(bs)) +
2112 decode_path=decode_path,
2113 ctx={"bered": True},
2115 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2116 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2120 def null_values_strategy(draw, do_expl=False):
2124 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2126 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2127 optional = draw(one_of(none(), booleans()))
2129 draw(integers(min_value=0)),
2130 draw(integers(min_value=0)),
2131 draw(integers(min_value=0)),
2133 return (impl, expl, optional, _decoded)
2136 class NullInherited(Null):
2140 class TestNull(CommonMixin, TestCase):
2143 def test_ready(self):
2145 self.assertTrue(obj.ready)
2149 @given(binary(), binary())
2150 def test_comparison(self, tag1, tag2):
2151 for klass in (Null, NullInherited):
2152 obj1 = klass(impl=tag1)
2153 obj2 = klass(impl=tag2)
2154 self.assertEqual(obj1 == obj2, tag1 == tag2)
2155 self.assertEqual(obj1 != obj2, tag1 != tag2)
2156 self.assertNotEqual(obj1, tag2)
2158 @given(data_strategy())
2159 def test_call(self, d):
2160 for klass in (Null, NullInherited):
2166 ) = d.draw(null_values_strategy())
2167 obj_initial = klass(
2170 optional=optional_initial or False,
2171 _decoded=_decoded_initial,
2178 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2179 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2180 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2181 self.assertEqual(obj.expl_tag, expl or expl_initial)
2182 optional = optional_initial if optional is None else optional
2183 optional = False if optional is None else optional
2184 self.assertEqual(obj.optional, optional)
2186 @given(null_values_strategy())
2187 def test_copy(self, values):
2188 for klass in (Null, NullInherited):
2189 impl, expl, optional, _decoded = values
2193 optional=optional or False,
2196 obj_copied = obj.copy()
2197 self.assert_copied_basic_fields(obj, obj_copied)
2199 @given(integers(min_value=1).map(tag_encode))
2200 def test_stripped(self, tag_impl):
2201 obj = Null(impl=tag_impl)
2202 with self.assertRaises(NotEnoughData):
2203 obj.decode(obj.encode()[:-1])
2205 @given(integers(min_value=1).map(tag_ctxc))
2206 def test_stripped_expl(self, tag_expl):
2207 obj = Null(expl=tag_expl)
2208 with self.assertRaises(NotEnoughData):
2209 obj.decode(obj.encode()[:-1])
2212 integers(min_value=31),
2213 integers(min_value=0),
2216 def test_bad_tag(self, tag, offset, decode_path):
2217 with self.assertRaises(DecodeError) as err:
2219 tag_encode(tag)[:-1],
2221 decode_path=decode_path,
2224 self.assertEqual(err.exception.offset, offset)
2225 self.assertEqual(err.exception.decode_path, decode_path)
2228 integers(min_value=128),
2229 integers(min_value=0),
2232 def test_bad_len(self, l, offset, decode_path):
2233 with self.assertRaises(DecodeError) as err:
2235 Null.tag_default + len_encode(l)[:-1],
2237 decode_path=decode_path,
2240 self.assertEqual(err.exception.offset, offset)
2241 self.assertEqual(err.exception.decode_path, decode_path)
2243 @given(binary(min_size=1))
2244 def test_tag_mismatch(self, impl):
2245 assume(impl != Null.tag_default)
2246 with self.assertRaises(TagMismatch):
2247 Null(impl=impl).decode(Null().encode())
2250 null_values_strategy(),
2251 integers(min_value=1).map(tag_ctxc),
2252 integers(min_value=0),
2255 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2256 for klass in (Null, NullInherited):
2257 _, _, optional, _decoded = values
2258 obj = klass(optional=optional, _decoded=_decoded)
2261 self.assertFalse(obj.expled)
2262 obj_encoded = obj.encode()
2263 obj_expled = obj(expl=tag_expl)
2264 self.assertTrue(obj_expled.expled)
2267 obj_expled_encoded = obj_expled.encode()
2268 obj_decoded, tail = obj_expled.decode(
2269 obj_expled_encoded + tail_junk,
2274 self.assertEqual(tail, tail_junk)
2275 self.assertEqual(obj_decoded, obj_expled)
2276 self.assertNotEqual(obj_decoded, obj)
2277 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2278 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2279 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2281 obj_decoded.expl_llen,
2282 len(len_encode(len(obj_encoded))),
2284 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2285 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2288 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2290 self.assertEqual(obj_decoded.expl_offset, offset)
2292 @given(integers(min_value=1))
2293 def test_invalid_len(self, l):
2294 with self.assertRaises(InvalidLength):
2295 Null().decode(b"".join((
2302 def oid_strategy(draw):
2303 first_arc = draw(integers(min_value=0, max_value=2))
2305 if first_arc in (0, 1):
2306 second_arc = draw(integers(min_value=0, max_value=39))
2308 second_arc = draw(integers(min_value=0))
2309 other_arcs = draw(lists(integers(min_value=0)))
2310 return tuple([first_arc, second_arc] + other_arcs)
2314 def oid_values_strategy(draw, do_expl=False):
2315 value = draw(one_of(none(), oid_strategy()))
2319 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2321 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2322 default = draw(one_of(none(), oid_strategy()))
2323 optional = draw(one_of(none(), booleans()))
2325 draw(integers(min_value=0)),
2326 draw(integers(min_value=0)),
2327 draw(integers(min_value=0)),
2329 return (value, impl, expl, default, optional, _decoded)
2332 class ObjectIdentifierInherited(ObjectIdentifier):
2336 class TestObjectIdentifier(CommonMixin, TestCase):
2337 base_klass = ObjectIdentifier
2339 def test_invalid_value_type(self):
2340 with self.assertRaises(InvalidValueType) as err:
2341 ObjectIdentifier(123)
2345 def test_optional(self, optional):
2346 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2347 self.assertTrue(obj.optional)
2349 @given(oid_strategy())
2350 def test_ready(self, value):
2351 obj = ObjectIdentifier()
2352 self.assertFalse(obj.ready)
2355 with self.assertRaises(ObjNotReady) as err:
2358 obj = ObjectIdentifier(value)
2359 self.assertTrue(obj.ready)
2364 @given(oid_strategy(), oid_strategy(), binary(), binary())
2365 def test_comparison(self, value1, value2, tag1, tag2):
2366 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2367 obj1 = klass(value1)
2368 obj2 = klass(value2)
2369 self.assertEqual(obj1 == obj2, value1 == value2)
2370 self.assertEqual(obj1 != obj2, value1 != value2)
2371 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2372 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2373 obj1 = klass(value1, impl=tag1)
2374 obj2 = klass(value1, impl=tag2)
2375 self.assertEqual(obj1 == obj2, tag1 == tag2)
2376 self.assertEqual(obj1 != obj2, tag1 != tag2)
2378 @given(lists(oid_strategy()))
2379 def test_sorted_works(self, values):
2380 self.assertSequenceEqual(
2381 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2385 @given(data_strategy())
2386 def test_call(self, d):
2387 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2395 ) = d.draw(oid_values_strategy())
2396 obj_initial = klass(
2397 value=value_initial,
2400 default=default_initial,
2401 optional=optional_initial or False,
2402 _decoded=_decoded_initial,
2411 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2420 value_expected = default if value is None else value
2422 default_initial if value_expected is None
2425 self.assertEqual(obj, value_expected)
2426 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2427 self.assertEqual(obj.expl_tag, expl or expl_initial)
2430 default_initial if default is None else default,
2432 if obj.default is None:
2433 optional = optional_initial if optional is None else optional
2434 optional = False if optional is None else optional
2437 self.assertEqual(obj.optional, optional)
2439 @given(oid_values_strategy())
2440 def test_copy(self, values):
2441 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2458 obj_copied = obj.copy()
2459 self.assert_copied_basic_fields(obj, obj_copied)
2460 self.assertEqual(obj._value, obj_copied._value)
2462 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2465 integers(min_value=1).map(tag_encode),
2467 def test_stripped(self, value, tag_impl):
2468 obj = ObjectIdentifier(value, impl=tag_impl)
2469 with self.assertRaises(NotEnoughData):
2470 obj.decode(obj.encode()[:-1])
2474 integers(min_value=1).map(tag_ctxc),
2476 def test_stripped_expl(self, value, tag_expl):
2477 obj = ObjectIdentifier(value, expl=tag_expl)
2478 with self.assertRaises(NotEnoughData):
2479 obj.decode(obj.encode()[:-1])
2482 integers(min_value=31),
2483 integers(min_value=0),
2486 def test_bad_tag(self, tag, offset, decode_path):
2487 with self.assertRaises(DecodeError) as err:
2488 ObjectIdentifier().decode(
2489 tag_encode(tag)[:-1],
2491 decode_path=decode_path,
2494 self.assertEqual(err.exception.offset, offset)
2495 self.assertEqual(err.exception.decode_path, decode_path)
2498 integers(min_value=128),
2499 integers(min_value=0),
2502 def test_bad_len(self, l, offset, decode_path):
2503 with self.assertRaises(DecodeError) as err:
2504 ObjectIdentifier().decode(
2505 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2507 decode_path=decode_path,
2510 self.assertEqual(err.exception.offset, offset)
2511 self.assertEqual(err.exception.decode_path, decode_path)
2513 def test_zero_oid(self):
2514 with self.assertRaises(NotEnoughData):
2515 ObjectIdentifier().decode(
2516 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2519 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2520 @given(oid_strategy())
2521 def test_unfinished_oid(self, value):
2522 assume(list(value)[-1] > 255)
2523 obj_encoded = ObjectIdentifier(value).encode()
2524 obj, _ = ObjectIdentifier().decode(obj_encoded)
2525 data = obj_encoded[obj.tlen + obj.llen:-1]
2527 ObjectIdentifier.tag_default,
2528 len_encode(len(data)),
2531 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2534 @given(integers(min_value=0))
2535 def test_invalid_short(self, value):
2536 with self.assertRaises(InvalidOID):
2537 ObjectIdentifier((value,))
2538 with self.assertRaises(InvalidOID):
2539 ObjectIdentifier("%d" % value)
2541 @given(integers(min_value=3), integers(min_value=0))
2542 def test_invalid_first_arc(self, first_arc, second_arc):
2543 with self.assertRaises(InvalidOID):
2544 ObjectIdentifier((first_arc, second_arc))
2545 with self.assertRaises(InvalidOID):
2546 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2548 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2549 def test_invalid_second_arc(self, first_arc, second_arc):
2550 with self.assertRaises(InvalidOID):
2551 ObjectIdentifier((first_arc, second_arc))
2552 with self.assertRaises(InvalidOID):
2553 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2555 @given(text(alphabet=ascii_letters + ".", min_size=1))
2556 def test_junk(self, oid):
2557 with self.assertRaises(InvalidOID):
2558 ObjectIdentifier(oid)
2560 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2561 @given(oid_strategy())
2562 def test_validness(self, oid):
2563 obj = ObjectIdentifier(oid)
2564 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2569 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2571 oid_values_strategy(),
2573 integers(min_value=1).map(tag_ctxc),
2574 integers(min_value=0),
2577 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2578 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2579 _, _, _, default, optional, _decoded = values
2588 self.assertFalse(obj.expled)
2589 obj_encoded = obj.encode()
2590 obj_expled = obj(value, expl=tag_expl)
2591 self.assertTrue(obj_expled.expled)
2594 obj_expled_encoded = obj_expled.encode()
2595 obj_decoded, tail = obj_expled.decode(
2596 obj_expled_encoded + tail_junk,
2601 self.assertEqual(tail, tail_junk)
2602 self.assertEqual(obj_decoded, obj_expled)
2603 self.assertNotEqual(obj_decoded, obj)
2604 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2605 self.assertEqual(tuple(obj_decoded), tuple(obj))
2606 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2607 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2608 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2610 obj_decoded.expl_llen,
2611 len(len_encode(len(obj_encoded))),
2613 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2614 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2617 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2619 self.assertEqual(obj_decoded.expl_offset, offset)
2622 oid_strategy().map(ObjectIdentifier),
2623 oid_strategy().map(ObjectIdentifier),
2625 def test_add(self, oid1, oid2):
2626 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2627 for oid_to_add in (oid2, tuple(oid2)):
2628 self.assertEqual(oid1 + oid_to_add, oid_expect)
2629 with self.assertRaises(InvalidValueType):
2632 def test_go_vectors_valid(self):
2633 for data, expect in (
2635 (b"\x55\x02", (2, 5, 2)),
2636 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2637 (b"\x81\x34\x03", (2, 100, 3)),
2640 ObjectIdentifier().decode(b"".join((
2641 ObjectIdentifier.tag_default,
2642 len_encode(len(data)),
2648 def test_go_vectors_invalid(self):
2649 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2650 with self.assertRaises(DecodeError):
2651 ObjectIdentifier().decode(b"".join((
2652 Integer.tag_default,
2653 len_encode(len(data)),
2657 def test_x690_vector(self):
2659 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2660 ObjectIdentifier((2, 999, 3)),
2665 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2667 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2668 values = list(draw(sets(
2670 min_size=len(schema),
2671 max_size=len(schema),
2673 schema = list(zip(schema, values))
2674 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2678 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2680 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2681 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2682 optional = draw(one_of(none(), booleans()))
2684 draw(integers(min_value=0)),
2685 draw(integers(min_value=0)),
2686 draw(integers(min_value=0)),
2688 return (schema, value, impl, expl, default, optional, _decoded)
2691 class TestEnumerated(CommonMixin, TestCase):
2692 class EWhatever(Enumerated):
2693 schema = (("whatever", 0),)
2695 base_klass = EWhatever
2697 def test_schema_required(self):
2698 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2701 def test_invalid_value_type(self):
2702 with self.assertRaises(InvalidValueType) as err:
2703 self.base_klass((1, 2))
2706 @given(sets(text_letters(), min_size=2))
2707 def test_unknown_name(self, schema_input):
2708 missing = schema_input.pop()
2710 class E(Enumerated):
2711 schema = [(n, 123) for n in schema_input]
2712 with self.assertRaises(ObjUnknown) as err:
2717 sets(text_letters(), min_size=2),
2718 sets(integers(), min_size=2),
2720 def test_unknown_value(self, schema_input, values_input):
2722 missing_value = values_input.pop()
2723 _input = list(zip(schema_input, values_input))
2725 class E(Enumerated):
2727 with self.assertRaises(DecodeError) as err:
2732 def test_optional(self, optional):
2733 obj = self.base_klass(default="whatever", optional=optional)
2734 self.assertTrue(obj.optional)
2736 def test_ready(self):
2737 obj = self.base_klass()
2738 self.assertFalse(obj.ready)
2741 with self.assertRaises(ObjNotReady) as err:
2744 obj = self.base_klass("whatever")
2745 self.assertTrue(obj.ready)
2749 @given(integers(), integers(), binary(), binary())
2750 def test_comparison(self, value1, value2, tag1, tag2):
2751 class E(Enumerated):
2753 ("whatever0", value1),
2754 ("whatever1", value2),
2757 class EInherited(E):
2759 for klass in (E, EInherited):
2760 obj1 = klass(value1)
2761 obj2 = klass(value2)
2762 self.assertEqual(obj1 == obj2, value1 == value2)
2763 self.assertEqual(obj1 != obj2, value1 != value2)
2764 self.assertEqual(obj1 == int(obj2), value1 == value2)
2765 obj1 = klass(value1, impl=tag1)
2766 obj2 = klass(value1, impl=tag2)
2767 self.assertEqual(obj1 == obj2, tag1 == tag2)
2768 self.assertEqual(obj1 != obj2, tag1 != tag2)
2770 @given(data_strategy())
2771 def test_call(self, d):
2780 ) = d.draw(enumerated_values_strategy())
2782 class E(Enumerated):
2783 schema = schema_initial
2785 value=value_initial,
2788 default=default_initial,
2789 optional=optional_initial or False,
2790 _decoded=_decoded_initial,
2800 ) = d.draw(enumerated_values_strategy(
2801 schema=schema_initial,
2802 do_expl=impl_initial is None,
2812 value_expected = default if value is None else value
2814 default_initial if value_expected is None
2819 dict(schema_initial).get(value_expected, value_expected),
2821 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2822 self.assertEqual(obj.expl_tag, expl or expl_initial)
2825 default_initial if default is None else default,
2827 if obj.default is None:
2828 optional = optional_initial if optional is None else optional
2829 optional = False if optional is None else optional
2832 self.assertEqual(obj.optional, optional)
2833 self.assertEqual(obj.specs, dict(schema_initial))
2835 @given(enumerated_values_strategy())
2836 def test_copy(self, values):
2837 schema_input, value, impl, expl, default, optional, _decoded = values
2839 class E(Enumerated):
2840 schema = schema_input
2849 obj_copied = obj.copy()
2850 self.assert_copied_basic_fields(obj, obj_copied)
2851 self.assertEqual(obj.specs, obj_copied.specs)
2853 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2854 @given(data_strategy())
2855 def test_symmetric(self, d):
2856 schema_input, _, _, _, default, optional, _decoded = d.draw(
2857 enumerated_values_strategy(),
2859 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2860 offset = d.draw(integers(min_value=0))
2861 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2862 tail_junk = d.draw(binary(max_size=5))
2864 class E(Enumerated):
2865 schema = schema_input
2874 self.assertFalse(obj.expled)
2875 obj_encoded = obj.encode()
2876 obj_expled = obj(value, expl=tag_expl)
2877 self.assertTrue(obj_expled.expled)
2880 obj_expled_encoded = obj_expled.encode()
2881 obj_decoded, tail = obj_expled.decode(
2882 obj_expled_encoded + tail_junk,
2887 self.assertEqual(tail, tail_junk)
2888 self.assertEqual(obj_decoded, obj_expled)
2889 self.assertNotEqual(obj_decoded, obj)
2890 self.assertEqual(int(obj_decoded), int(obj_expled))
2891 self.assertEqual(int(obj_decoded), int(obj))
2892 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2893 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2894 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2896 obj_decoded.expl_llen,
2897 len(len_encode(len(obj_encoded))),
2899 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2900 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2903 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2905 self.assertEqual(obj_decoded.expl_offset, offset)
2909 def string_values_strategy(draw, alphabet, do_expl=False):
2910 bound_min, bound_max = sorted(draw(sets(
2911 integers(min_value=0, max_value=1 << 7),
2915 value = draw(one_of(
2917 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2919 default = draw(one_of(
2921 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2924 if draw(booleans()):
2925 bounds = (bound_min, bound_max)
2929 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2931 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2932 optional = draw(one_of(none(), booleans()))
2934 draw(integers(min_value=0)),
2935 draw(integers(min_value=0)),
2936 draw(integers(min_value=0)),
2938 return (value, bounds, impl, expl, default, optional, _decoded)
2941 class StringMixin(object):
2942 def test_invalid_value_type(self):
2943 with self.assertRaises(InvalidValueType) as err:
2944 self.base_klass((1, 2))
2947 def text_alphabet(self):
2948 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2949 return printable + whitespace
2953 def test_optional(self, optional):
2954 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2955 self.assertTrue(obj.optional)
2957 @given(data_strategy())
2958 def test_ready(self, d):
2959 obj = self.base_klass()
2960 self.assertFalse(obj.ready)
2964 with self.assertRaises(ObjNotReady) as err:
2967 value = d.draw(text(alphabet=self.text_alphabet()))
2968 obj = self.base_klass(value)
2969 self.assertTrue(obj.ready)
2974 @given(data_strategy())
2975 def test_comparison(self, d):
2976 value1 = d.draw(text(alphabet=self.text_alphabet()))
2977 value2 = d.draw(text(alphabet=self.text_alphabet()))
2978 tag1 = d.draw(binary(min_size=1))
2979 tag2 = d.draw(binary(min_size=1))
2980 obj1 = self.base_klass(value1)
2981 obj2 = self.base_klass(value2)
2982 self.assertEqual(obj1 == obj2, value1 == value2)
2983 self.assertEqual(obj1 != obj2, value1 != value2)
2984 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2985 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2986 obj1 = self.base_klass(value1, impl=tag1)
2987 obj2 = self.base_klass(value1, impl=tag2)
2988 self.assertEqual(obj1 == obj2, tag1 == tag2)
2989 self.assertEqual(obj1 != obj2, tag1 != tag2)
2991 @given(data_strategy())
2992 def test_bounds_satisfied(self, d):
2993 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2994 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2995 value = d.draw(text(
2996 alphabet=self.text_alphabet(),
3000 self.base_klass(value=value, bounds=(bound_min, bound_max))
3002 @given(data_strategy())
3003 def test_bounds_unsatisfied(self, d):
3004 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3005 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3006 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 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()
3015 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3016 with self.assertRaises(BoundsError) as err:
3017 self.base_klass(value=value, bounds=(bound_min, bound_max))
3019 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3020 self.base_klass(bounds=(bound_min, bound_max)).decode(
3021 self.base_klass(value).encode()
3025 @given(data_strategy())
3026 def test_call(self, d):
3035 ) = d.draw(string_values_strategy(self.text_alphabet()))
3036 obj_initial = self.base_klass(
3042 optional_initial or False,
3053 ) = d.draw(string_values_strategy(
3054 self.text_alphabet(),
3055 do_expl=impl_initial is None,
3057 if (default is None) and (obj_initial.default is not None):
3060 (bounds is None) and
3061 (value is not None) and
3062 (bounds_initial is not None) and
3063 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3067 (bounds is None) and
3068 (default is not None) and
3069 (bounds_initial is not None) and
3070 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3073 obj = obj_initial(value, bounds, impl, expl, default, optional)
3075 value_expected = default if value is None else value
3077 default_initial if value_expected is None
3080 self.assertEqual(obj, value_expected)
3081 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3082 self.assertEqual(obj.expl_tag, expl or expl_initial)
3085 default_initial if default is None else default,
3087 if obj.default is None:
3088 optional = optional_initial if optional is None else optional
3089 optional = False if optional is None else optional
3092 self.assertEqual(obj.optional, optional)
3094 (obj._bound_min, obj._bound_max),
3095 bounds or bounds_initial or (0, float("+inf")),
3098 @given(data_strategy())
3099 def test_copy(self, d):
3100 values = d.draw(string_values_strategy(self.text_alphabet()))
3101 obj = self.base_klass(*values)
3102 obj_copied = obj.copy()
3103 self.assert_copied_basic_fields(obj, obj_copied)
3104 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3105 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3106 self.assertEqual(obj._value, obj_copied._value)
3108 @given(data_strategy())
3109 def test_stripped(self, d):
3110 value = d.draw(text(alphabet=self.text_alphabet()))
3111 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3112 obj = self.base_klass(value, impl=tag_impl)
3113 with self.assertRaises(NotEnoughData):
3114 obj.decode(obj.encode()[:-1])
3116 @given(data_strategy())
3117 def test_stripped_expl(self, d):
3118 value = d.draw(text(alphabet=self.text_alphabet()))
3119 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3120 obj = self.base_klass(value, expl=tag_expl)
3121 with self.assertRaises(NotEnoughData):
3122 obj.decode(obj.encode()[:-1])
3125 integers(min_value=31),
3126 integers(min_value=0),
3129 def test_bad_tag(self, tag, offset, decode_path):
3130 with self.assertRaises(DecodeError) as err:
3131 self.base_klass().decode(
3132 tag_encode(tag)[:-1],
3134 decode_path=decode_path,
3137 self.assertEqual(err.exception.offset, offset)
3138 self.assertEqual(err.exception.decode_path, decode_path)
3141 integers(min_value=128),
3142 integers(min_value=0),
3145 def test_bad_len(self, l, offset, decode_path):
3146 with self.assertRaises(DecodeError) as err:
3147 self.base_klass().decode(
3148 self.base_klass.tag_default + len_encode(l)[:-1],
3150 decode_path=decode_path,
3153 self.assertEqual(err.exception.offset, offset)
3154 self.assertEqual(err.exception.decode_path, decode_path)
3157 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3158 integers(min_value=0),
3161 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3162 value, bound_min = list(sorted(ints))
3164 class String(self.base_klass):
3165 # Multiply this value by four, to satisfy UTF-32 bounds
3166 # (4 bytes per character) validation
3167 bounds = (bound_min * 4, bound_min * 4)
3168 with self.assertRaises(DecodeError) as err:
3170 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3172 decode_path=decode_path,
3175 self.assertEqual(err.exception.offset, offset)
3176 self.assertEqual(err.exception.decode_path, decode_path)
3178 @given(data_strategy())
3179 def test_symmetric(self, d):
3180 values = d.draw(string_values_strategy(self.text_alphabet()))
3181 value = d.draw(text(alphabet=self.text_alphabet()))
3182 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3183 offset = d.draw(integers(min_value=0))
3184 tail_junk = d.draw(binary(max_size=5))
3185 _, _, _, _, default, optional, _decoded = values
3186 obj = self.base_klass(
3194 self.assertFalse(obj.expled)
3195 obj_encoded = obj.encode()
3196 obj_expled = obj(value, expl=tag_expl)
3197 self.assertTrue(obj_expled.expled)
3200 obj_expled_encoded = obj_expled.encode()
3201 obj_decoded, tail = obj_expled.decode(
3202 obj_expled_encoded + tail_junk,
3207 self.assertEqual(tail, tail_junk)
3208 self.assertEqual(obj_decoded, obj_expled)
3209 self.assertNotEqual(obj_decoded, obj)
3210 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3211 self.assertEqual(bytes(obj_decoded), bytes(obj))
3212 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3213 self.assertEqual(text_type(obj_decoded), text_type(obj))
3214 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3215 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3216 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3218 obj_decoded.expl_llen,
3219 len(len_encode(len(obj_encoded))),
3221 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3222 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3225 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3227 self.assertEqual(obj_decoded.expl_offset, offset)
3230 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3231 base_klass = UTF8String
3234 class UnicodeDecodeErrorMixin(object):
3236 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3240 def test_unicode_decode_error(self, cyrillic_text):
3241 with self.assertRaises(DecodeError):
3242 self.base_klass(cyrillic_text)
3245 class TestNumericString(StringMixin, CommonMixin, TestCase):
3246 base_klass = NumericString
3248 def text_alphabet(self):
3251 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3252 def test_non_numeric(self, cyrillic_text):
3253 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3254 self.base_klass(cyrillic_text)
3257 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3258 integers(min_value=0),
3261 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3262 value, bound_min = list(sorted(ints))
3264 class String(self.base_klass):
3265 bounds = (bound_min, bound_min)
3266 with self.assertRaises(DecodeError) as err:
3268 self.base_klass(b"1" * value).encode(),
3270 decode_path=decode_path,
3273 self.assertEqual(err.exception.offset, offset)
3274 self.assertEqual(err.exception.decode_path, decode_path)
3277 class TestPrintableString(
3278 UnicodeDecodeErrorMixin,
3283 base_klass = PrintableString
3286 class TestTeletexString(
3287 UnicodeDecodeErrorMixin,
3292 base_klass = TeletexString
3295 class TestVideotexString(
3296 UnicodeDecodeErrorMixin,
3301 base_klass = VideotexString
3304 class TestIA5String(
3305 UnicodeDecodeErrorMixin,
3310 base_klass = IA5String
3313 class TestGraphicString(
3314 UnicodeDecodeErrorMixin,
3319 base_klass = GraphicString
3322 class TestVisibleString(
3323 UnicodeDecodeErrorMixin,
3328 base_klass = VisibleString
3330 def test_x690_vector(self):
3331 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3332 self.assertSequenceEqual(tail, b"")
3333 self.assertEqual(str(obj), "Jones")
3334 self.assertFalse(obj.ber_encoded)
3335 self.assertFalse(obj.lenindef)
3336 self.assertFalse(obj.bered)
3338 obj, tail = VisibleString().decode(
3339 hexdec("3A0904034A6F6E04026573"),
3340 ctx={"bered": True},
3342 self.assertSequenceEqual(tail, b"")
3343 self.assertEqual(str(obj), "Jones")
3344 self.assertTrue(obj.ber_encoded)
3345 self.assertFalse(obj.lenindef)
3346 self.assertTrue(obj.bered)
3348 obj, tail = VisibleString().decode(
3349 hexdec("3A8004034A6F6E040265730000"),
3350 ctx={"bered": True},
3352 self.assertSequenceEqual(tail, b"")
3353 self.assertEqual(str(obj), "Jones")
3354 self.assertTrue(obj.ber_encoded)
3355 self.assertTrue(obj.lenindef)
3356 self.assertTrue(obj.bered)
3359 class TestGeneralString(
3360 UnicodeDecodeErrorMixin,
3365 base_klass = GeneralString
3368 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3369 base_klass = UniversalString
3372 class TestBMPString(StringMixin, CommonMixin, TestCase):
3373 base_klass = BMPString
3377 def generalized_time_values_strategy(
3385 if draw(booleans()):
3386 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3388 value = value.replace(microsecond=0)
3390 if draw(booleans()):
3391 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3393 default = default.replace(microsecond=0)
3397 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3399 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3400 optional = draw(one_of(none(), booleans()))
3402 draw(integers(min_value=0)),
3403 draw(integers(min_value=0)),
3404 draw(integers(min_value=0)),
3406 return (value, impl, expl, default, optional, _decoded)
3409 class TimeMixin(object):
3410 def test_invalid_value_type(self):
3411 with self.assertRaises(InvalidValueType) as err:
3412 self.base_klass(datetime.now().timetuple())
3415 @given(data_strategy())
3416 def test_optional(self, d):
3417 default = d.draw(datetimes(
3418 min_value=self.min_datetime,
3419 max_value=self.max_datetime,
3421 optional = d.draw(booleans())
3422 obj = self.base_klass(default=default, optional=optional)
3423 self.assertTrue(obj.optional)
3425 @given(data_strategy())
3426 def test_ready(self, d):
3427 obj = self.base_klass()
3428 self.assertFalse(obj.ready)
3431 with self.assertRaises(ObjNotReady) as err:
3434 value = d.draw(datetimes(min_value=self.min_datetime))
3435 obj = self.base_klass(value)
3436 self.assertTrue(obj.ready)
3440 @given(data_strategy())
3441 def test_comparison(self, d):
3442 value1 = d.draw(datetimes(
3443 min_value=self.min_datetime,
3444 max_value=self.max_datetime,
3446 value2 = d.draw(datetimes(
3447 min_value=self.min_datetime,
3448 max_value=self.max_datetime,
3450 tag1 = d.draw(binary(min_size=1))
3451 tag2 = d.draw(binary(min_size=1))
3453 value1 = value1.replace(microsecond=0)
3454 value2 = value2.replace(microsecond=0)
3455 obj1 = self.base_klass(value1)
3456 obj2 = self.base_klass(value2)
3457 self.assertEqual(obj1 == obj2, value1 == value2)
3458 self.assertEqual(obj1 != obj2, value1 != value2)
3459 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3460 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3461 obj1 = self.base_klass(value1, impl=tag1)
3462 obj2 = self.base_klass(value1, impl=tag2)
3463 self.assertEqual(obj1 == obj2, tag1 == tag2)
3464 self.assertEqual(obj1 != obj2, tag1 != tag2)
3466 @given(data_strategy())
3467 def test_call(self, d):
3475 ) = d.draw(generalized_time_values_strategy(
3476 min_datetime=self.min_datetime,
3477 max_datetime=self.max_datetime,
3478 omit_ms=self.omit_ms,
3480 obj_initial = self.base_klass(
3481 value=value_initial,
3484 default=default_initial,
3485 optional=optional_initial or False,
3486 _decoded=_decoded_initial,
3495 ) = d.draw(generalized_time_values_strategy(
3496 min_datetime=self.min_datetime,
3497 max_datetime=self.max_datetime,
3498 omit_ms=self.omit_ms,
3499 do_expl=impl_initial is None,
3509 value_expected = default if value is None else value
3511 default_initial if value_expected is None
3514 self.assertEqual(obj, value_expected)
3515 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3516 self.assertEqual(obj.expl_tag, expl or expl_initial)
3519 default_initial if default is None else default,
3521 if obj.default is None:
3522 optional = optional_initial if optional is None else optional
3523 optional = False if optional is None else optional
3526 self.assertEqual(obj.optional, optional)
3528 @given(data_strategy())
3529 def test_copy(self, d):
3530 values = d.draw(generalized_time_values_strategy(
3531 min_datetime=self.min_datetime,
3532 max_datetime=self.max_datetime,
3534 obj = self.base_klass(*values)
3535 obj_copied = obj.copy()
3536 self.assert_copied_basic_fields(obj, obj_copied)
3537 self.assertEqual(obj._value, obj_copied._value)
3539 @given(data_strategy())
3540 def test_stripped(self, d):
3541 value = d.draw(datetimes(
3542 min_value=self.min_datetime,
3543 max_value=self.max_datetime,
3545 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3546 obj = self.base_klass(value, impl=tag_impl)
3547 with self.assertRaises(NotEnoughData):
3548 obj.decode(obj.encode()[:-1])
3550 @given(data_strategy())
3551 def test_stripped_expl(self, d):
3552 value = d.draw(datetimes(
3553 min_value=self.min_datetime,
3554 max_value=self.max_datetime,
3556 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3557 obj = self.base_klass(value, expl=tag_expl)
3558 with self.assertRaises(NotEnoughData):
3559 obj.decode(obj.encode()[:-1])
3561 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3562 @given(data_strategy())
3563 def test_symmetric(self, d):
3564 values = d.draw(generalized_time_values_strategy(
3565 min_datetime=self.min_datetime,
3566 max_datetime=self.max_datetime,
3568 value = d.draw(datetimes(
3569 min_value=self.min_datetime,
3570 max_value=self.max_datetime,
3572 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3573 offset = d.draw(integers(min_value=0))
3574 tail_junk = d.draw(binary(max_size=5))
3575 _, _, _, default, optional, _decoded = values
3576 obj = self.base_klass(
3584 self.assertFalse(obj.expled)
3585 obj_encoded = obj.encode()
3586 obj_expled = obj(value, expl=tag_expl)
3587 self.assertTrue(obj_expled.expled)
3590 obj_expled_encoded = obj_expled.encode()
3591 obj_decoded, tail = obj_expled.decode(
3592 obj_expled_encoded + tail_junk,
3597 self.assertEqual(tail, tail_junk)
3598 self.assertEqual(obj_decoded, obj_expled)
3599 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3600 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3601 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3602 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3603 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3605 obj_decoded.expl_llen,
3606 len(len_encode(len(obj_encoded))),
3608 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3609 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3612 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3614 self.assertEqual(obj_decoded.expl_offset, offset)
3617 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3618 base_klass = GeneralizedTime
3620 min_datetime = datetime(1900, 1, 1)
3621 max_datetime = datetime(9999, 12, 31)
3623 def test_go_vectors_invalid(self):
3635 b"-20100102030410Z",
3636 b"2010-0102030410Z",
3637 b"2010-0002030410Z",
3638 b"201001-02030410Z",
3639 b"20100102-030410Z",
3640 b"2010010203-0410Z",
3641 b"201001020304-10Z",
3642 # These ones are INVALID in *DER*, but accepted
3643 # by Go's encoding/asn1
3644 b"20100102030405+0607",
3645 b"20100102030405-0607",
3647 with self.assertRaises(DecodeError) as err:
3648 GeneralizedTime(data)
3651 def test_go_vectors_valid(self):
3653 GeneralizedTime(b"20100102030405Z").todatetime(),
3654 datetime(2010, 1, 2, 3, 4, 5, 0),
3659 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3660 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3662 binary(min_size=1, max_size=1),
3664 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3665 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3668 def test_junk(self, part0, part1, part2):
3669 junk = part0 + part1 + part2
3670 assume(not (set(junk) <= set(digits.encode("ascii"))))
3671 with self.assertRaises(DecodeError):
3672 GeneralizedTime().decode(
3673 GeneralizedTime.tag_default +
3674 len_encode(len(junk)) +
3680 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3681 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3683 binary(min_size=1, max_size=1),
3685 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3686 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3689 def test_junk_dm(self, part0, part1, part2):
3690 junk = part0 + part1 + part2
3691 assume(not (set(junk) <= set(digits.encode("ascii"))))
3692 with self.assertRaises(DecodeError):
3693 GeneralizedTime().decode(
3694 GeneralizedTime.tag_default +
3695 len_encode(len(junk)) +
3700 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3701 base_klass = UTCTime
3703 min_datetime = datetime(2000, 1, 1)
3704 max_datetime = datetime(2049, 12, 31)
3706 def test_go_vectors_invalid(self):
3732 # These ones are INVALID in *DER*, but accepted
3733 # by Go's encoding/asn1
3734 b"910506164540-0700",
3735 b"910506164540+0730",
3739 with self.assertRaises(DecodeError) as err:
3743 def test_go_vectors_valid(self):
3745 UTCTime(b"910506234540Z").todatetime(),
3746 datetime(1991, 5, 6, 23, 45, 40, 0),
3749 @given(integers(min_value=0, max_value=49))
3750 def test_pre50(self, year):
3752 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3756 @given(integers(min_value=50, max_value=99))
3757 def test_post50(self, year):
3759 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3765 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3766 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3768 binary(min_size=1, max_size=1),
3770 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3771 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3774 def test_junk(self, part0, part1, part2):
3775 junk = part0 + part1 + part2
3776 assume(not (set(junk) <= set(digits.encode("ascii"))))
3777 with self.assertRaises(DecodeError):
3779 UTCTime.tag_default +
3780 len_encode(len(junk)) +
3786 def any_values_strategy(draw, do_expl=False):
3787 value = draw(one_of(none(), binary()))
3790 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3791 optional = draw(one_of(none(), booleans()))
3793 draw(integers(min_value=0)),
3794 draw(integers(min_value=0)),
3795 draw(integers(min_value=0)),
3797 return (value, expl, optional, _decoded)
3800 class AnyInherited(Any):
3804 class TestAny(CommonMixin, TestCase):
3807 def test_invalid_value_type(self):
3808 with self.assertRaises(InvalidValueType) as err:
3813 def test_optional(self, optional):
3814 obj = Any(optional=optional)
3815 self.assertEqual(obj.optional, optional)
3818 def test_ready(self, value):
3820 self.assertFalse(obj.ready)
3823 with self.assertRaises(ObjNotReady) as err:
3827 self.assertTrue(obj.ready)
3832 def test_basic(self, value):
3833 integer_encoded = Integer(value).encode()
3835 Any(integer_encoded),
3836 Any(Integer(value)),
3837 Any(Any(Integer(value))),
3839 self.assertSequenceEqual(bytes(obj), integer_encoded)
3841 obj.decode(obj.encode())[0].vlen,
3842 len(integer_encoded),
3846 self.assertSequenceEqual(obj.encode(), integer_encoded)
3848 @given(binary(), binary())
3849 def test_comparison(self, value1, value2):
3850 for klass in (Any, AnyInherited):
3851 obj1 = klass(value1)
3852 obj2 = klass(value2)
3853 self.assertEqual(obj1 == obj2, value1 == value2)
3854 self.assertEqual(obj1 != obj2, value1 != value2)
3855 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3857 @given(data_strategy())
3858 def test_call(self, d):
3859 for klass in (Any, AnyInherited):
3865 ) = d.draw(any_values_strategy())
3866 obj_initial = klass(
3869 optional_initial or False,
3877 ) = d.draw(any_values_strategy(do_expl=True))
3878 obj = obj_initial(value, expl, optional)
3880 value_expected = None if value is None else value
3881 self.assertEqual(obj, value_expected)
3882 self.assertEqual(obj.expl_tag, expl or expl_initial)
3883 if obj.default is None:
3884 optional = optional_initial if optional is None else optional
3885 optional = False if optional is None else optional
3886 self.assertEqual(obj.optional, optional)
3888 def test_simultaneous_impl_expl(self):
3889 # override it, as Any does not have implicit tag
3892 def test_decoded(self):
3893 # override it, as Any does not have implicit tag
3896 @given(any_values_strategy())
3897 def test_copy(self, values):
3898 for klass in (Any, AnyInherited):
3899 obj = klass(*values)
3900 obj_copied = obj.copy()
3901 self.assert_copied_basic_fields(obj, obj_copied)
3902 self.assertEqual(obj._value, obj_copied._value)
3904 @given(binary().map(OctetString))
3905 def test_stripped(self, value):
3907 with self.assertRaises(NotEnoughData):
3908 obj.decode(obj.encode()[:-1])
3912 integers(min_value=1).map(tag_ctxc),
3914 def test_stripped_expl(self, value, tag_expl):
3915 obj = Any(value, expl=tag_expl)
3916 with self.assertRaises(NotEnoughData):
3917 obj.decode(obj.encode()[:-1])
3920 integers(min_value=31),
3921 integers(min_value=0),
3924 def test_bad_tag(self, tag, offset, decode_path):
3925 with self.assertRaises(DecodeError) as err:
3927 tag_encode(tag)[:-1],
3929 decode_path=decode_path,
3932 self.assertEqual(err.exception.offset, offset)
3933 self.assertEqual(err.exception.decode_path, decode_path)
3936 integers(min_value=128),
3937 integers(min_value=0),
3940 def test_bad_len(self, l, offset, decode_path):
3941 with self.assertRaises(DecodeError) as err:
3943 Any.tag_default + len_encode(l)[:-1],
3945 decode_path=decode_path,
3948 self.assertEqual(err.exception.offset, offset)
3949 self.assertEqual(err.exception.decode_path, decode_path)
3951 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3953 any_values_strategy(),
3954 integers().map(lambda x: Integer(x).encode()),
3955 integers(min_value=1).map(tag_ctxc),
3956 integers(min_value=0),
3959 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3960 for klass in (Any, AnyInherited):
3961 _, _, optional, _decoded = values
3962 obj = klass(value=value, optional=optional, _decoded=_decoded)
3965 self.assertFalse(obj.expled)
3966 obj_encoded = obj.encode()
3967 obj_expled = obj(value, expl=tag_expl)
3968 self.assertTrue(obj_expled.expled)
3971 obj_expled_encoded = obj_expled.encode()
3972 obj_decoded, tail = obj_expled.decode(
3973 obj_expled_encoded + tail_junk,
3978 self.assertEqual(tail, tail_junk)
3979 self.assertEqual(obj_decoded, obj_expled)
3980 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3981 self.assertEqual(bytes(obj_decoded), bytes(obj))
3982 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3983 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3984 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3986 obj_decoded.expl_llen,
3987 len(len_encode(len(obj_encoded))),
3989 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3990 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3993 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3995 self.assertEqual(obj_decoded.expl_offset, offset)
3996 self.assertEqual(obj_decoded.tlen, 0)
3997 self.assertEqual(obj_decoded.llen, 0)
3998 self.assertEqual(obj_decoded.vlen, len(value))
4001 integers(min_value=1).map(tag_ctxc),
4002 integers(min_value=0, max_value=3),
4003 integers(min_value=0),
4007 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4008 chunk = Boolean(False, expl=expl).encode()
4010 OctetString.tag_default +
4012 b"".join([chunk] * chunks) +
4015 obj, tail = Any().decode(
4018 decode_path=decode_path,
4019 ctx={"bered": True},
4021 self.assertSequenceEqual(tail, junk)
4022 self.assertEqual(obj.offset, offset)
4023 self.assertEqual(obj.tlvlen, len(encoded))
4024 self.assertTrue(obj.lenindef)
4025 self.assertFalse(obj.ber_encoded)
4026 self.assertTrue(obj.bered)
4027 with self.assertRaises(NotEnoughData) as err:
4031 decode_path=decode_path,
4032 ctx={"bered": True},
4034 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4035 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4039 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4041 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4042 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4044 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4045 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4047 min_size=len(names),
4048 max_size=len(names),
4051 (name, Integer(**tag_kwargs))
4052 for name, tag_kwargs in zip(names, tags)
4055 if value_required or draw(booleans()):
4056 value = draw(tuples(
4057 sampled_from([name for name, _ in schema]),
4058 integers().map(Integer),
4062 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4063 default = draw(one_of(
4065 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4067 optional = draw(one_of(none(), booleans()))
4069 draw(integers(min_value=0)),
4070 draw(integers(min_value=0)),
4071 draw(integers(min_value=0)),
4073 return (schema, value, expl, default, optional, _decoded)
4076 class ChoiceInherited(Choice):
4080 class TestChoice(CommonMixin, TestCase):
4082 schema = (("whatever", Boolean()),)
4085 def test_schema_required(self):
4086 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4089 def test_impl_forbidden(self):
4090 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4091 Choice(impl=b"whatever")
4093 def test_invalid_value_type(self):
4094 with self.assertRaises(InvalidValueType) as err:
4095 self.base_klass(123)
4097 with self.assertRaises(ObjUnknown) as err:
4098 self.base_klass(("whenever", Boolean(False)))
4100 with self.assertRaises(InvalidValueType) as err:
4101 self.base_klass(("whatever", Integer(123)))
4105 def test_optional(self, optional):
4106 obj = self.base_klass(
4107 default=self.base_klass(("whatever", Boolean(False))),
4110 self.assertTrue(obj.optional)
4113 def test_ready(self, value):
4114 obj = self.base_klass()
4115 self.assertFalse(obj.ready)
4118 self.assertIsNone(obj["whatever"])
4119 with self.assertRaises(ObjNotReady) as err:
4122 obj["whatever"] = Boolean()
4123 self.assertFalse(obj.ready)
4126 obj["whatever"] = Boolean(value)
4127 self.assertTrue(obj.ready)
4131 @given(booleans(), booleans())
4132 def test_comparison(self, value1, value2):
4133 class WahlInherited(self.base_klass):
4135 for klass in (self.base_klass, WahlInherited):
4136 obj1 = klass(("whatever", Boolean(value1)))
4137 obj2 = klass(("whatever", Boolean(value2)))
4138 self.assertEqual(obj1 == obj2, value1 == value2)
4139 self.assertEqual(obj1 != obj2, value1 != value2)
4140 self.assertEqual(obj1 == obj2._value, value1 == value2)
4141 self.assertFalse(obj1 == obj2._value[1])
4143 @given(data_strategy())
4144 def test_call(self, d):
4145 for klass in (Choice, ChoiceInherited):
4153 ) = d.draw(choice_values_strategy())
4156 schema = schema_initial
4158 value=value_initial,
4160 default=default_initial,
4161 optional=optional_initial or False,
4162 _decoded=_decoded_initial,
4171 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4172 obj = obj_initial(value, expl, default, optional)
4174 value_expected = default if value is None else value
4176 default_initial if value_expected is None
4179 self.assertEqual(obj.choice, value_expected[0])
4180 self.assertEqual(obj.value, int(value_expected[1]))
4181 self.assertEqual(obj.expl_tag, expl or expl_initial)
4182 default_expect = default_initial if default is None else default
4183 if default_expect is not None:
4184 self.assertEqual(obj.default.choice, default_expect[0])
4185 self.assertEqual(obj.default.value, int(default_expect[1]))
4186 if obj.default is None:
4187 optional = optional_initial if optional is None else optional
4188 optional = False if optional is None else optional
4191 self.assertEqual(obj.optional, optional)
4192 self.assertEqual(obj.specs, obj_initial.specs)
4194 def test_simultaneous_impl_expl(self):
4195 # override it, as Any does not have implicit tag
4198 def test_decoded(self):
4199 # override it, as Any does not have implicit tag
4202 @given(choice_values_strategy())
4203 def test_copy(self, values):
4204 _schema, value, expl, default, optional, _decoded = values
4206 class Wahl(self.base_klass):
4212 optional=optional or False,
4215 obj_copied = obj.copy()
4216 self.assertIsNone(obj.tag)
4217 self.assertIsNone(obj_copied.tag)
4218 # hack for assert_copied_basic_fields
4219 obj.tag = "whatever"
4220 obj_copied.tag = "whatever"
4221 self.assert_copied_basic_fields(obj, obj_copied)
4222 self.assertEqual(obj._value, obj_copied._value)
4223 self.assertEqual(obj.specs, obj_copied.specs)
4226 def test_stripped(self, value):
4227 obj = self.base_klass(("whatever", Boolean(value)))
4228 with self.assertRaises(NotEnoughData):
4229 obj.decode(obj.encode()[:-1])
4233 integers(min_value=1).map(tag_ctxc),
4235 def test_stripped_expl(self, value, tag_expl):
4236 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4237 with self.assertRaises(NotEnoughData):
4238 obj.decode(obj.encode()[:-1])
4240 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4241 @given(data_strategy())
4242 def test_symmetric(self, d):
4243 _schema, value, _, default, optional, _decoded = d.draw(
4244 choice_values_strategy(value_required=True)
4246 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4247 offset = d.draw(integers(min_value=0))
4248 tail_junk = d.draw(binary(max_size=5))
4250 class Wahl(self.base_klass):
4260 self.assertFalse(obj.expled)
4261 obj_encoded = obj.encode()
4262 obj_expled = obj(value, expl=tag_expl)
4263 self.assertTrue(obj_expled.expled)
4266 obj_expled_encoded = obj_expled.encode()
4267 obj_decoded, tail = obj_expled.decode(
4268 obj_expled_encoded + tail_junk,
4273 self.assertEqual(tail, tail_junk)
4274 self.assertEqual(obj_decoded, obj_expled)
4275 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4276 self.assertEqual(obj_decoded.value, obj_expled.value)
4277 self.assertEqual(obj_decoded.choice, obj.choice)
4278 self.assertEqual(obj_decoded.value, obj.value)
4279 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4280 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4281 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4283 obj_decoded.expl_llen,
4284 len(len_encode(len(obj_encoded))),
4286 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4287 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4290 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4292 self.assertEqual(obj_decoded.expl_offset, offset)
4293 self.assertSequenceEqual(
4295 obj_decoded.value.fulloffset - offset:
4296 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4302 def test_set_get(self, value):
4305 ("erste", Boolean()),
4306 ("zweite", Integer()),
4309 with self.assertRaises(ObjUnknown) as err:
4310 obj["whatever"] = "whenever"
4311 with self.assertRaises(InvalidValueType) as err:
4312 obj["zweite"] = Boolean(False)
4313 obj["zweite"] = Integer(value)
4315 with self.assertRaises(ObjUnknown) as err:
4318 self.assertIsNone(obj["erste"])
4319 self.assertEqual(obj["zweite"], Integer(value))
4321 def test_tag_mismatch(self):
4324 ("erste", Boolean()),
4326 int_encoded = Integer(123).encode()
4327 bool_encoded = Boolean(False).encode()
4329 obj.decode(bool_encoded)
4330 with self.assertRaises(TagMismatch):
4331 obj.decode(int_encoded)
4333 def test_tag_mismatch_underlying(self):
4334 class SeqOfBoolean(SequenceOf):
4337 class SeqOfInteger(SequenceOf):
4342 ("erste", SeqOfBoolean()),
4345 int_encoded = SeqOfInteger((Integer(123),)).encode()
4346 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4348 obj.decode(bool_encoded)
4349 with self.assertRaises(TagMismatch) as err:
4350 obj.decode(int_encoded)
4351 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4355 def seq_values_strategy(draw, seq_klass, do_expl=False):
4357 if draw(booleans()):
4360 k: v for k, v in draw(dictionaries(
4363 booleans().map(Boolean),
4364 integers().map(Integer),
4369 if draw(booleans()):
4370 schema = list(draw(dictionaries(
4373 booleans().map(Boolean),
4374 integers().map(Integer),
4380 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4382 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4384 if draw(booleans()):
4385 default = seq_klass()
4387 k: v for k, v in draw(dictionaries(
4390 booleans().map(Boolean),
4391 integers().map(Integer),
4395 optional = draw(one_of(none(), booleans()))
4397 draw(integers(min_value=0)),
4398 draw(integers(min_value=0)),
4399 draw(integers(min_value=0)),
4401 return (value, schema, impl, expl, default, optional, _decoded)
4405 def sequence_strategy(draw, seq_klass):
4406 inputs = draw(lists(
4408 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4409 tuples(just(Integer), integers(), one_of(none(), integers())),
4414 integers(min_value=1),
4415 min_size=len(inputs),
4416 max_size=len(inputs),
4419 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4420 for tag, expled in zip(tags, draw(lists(
4422 min_size=len(inputs),
4423 max_size=len(inputs),
4427 for i, optional in enumerate(draw(lists(
4428 sampled_from(("required", "optional", "empty")),
4429 min_size=len(inputs),
4430 max_size=len(inputs),
4432 if optional in ("optional", "empty"):
4433 inits[i]["optional"] = True
4434 if optional == "empty":
4436 empties = set(empties)
4437 names = list(draw(sets(
4439 min_size=len(inputs),
4440 max_size=len(inputs),
4443 for i, (klass, value, default) in enumerate(inputs):
4444 schema.append((names[i], klass(default=default, **inits[i])))
4445 seq_name = draw(text_letters())
4446 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4449 for i, (klass, value, default) in enumerate(inputs):
4456 "default_value": None if spec.default is None else default,
4460 expect["optional"] = True
4462 expect["presented"] = True
4463 expect["value"] = value
4465 expect["optional"] = True
4466 if default is not None and default == value:
4467 expect["presented"] = False
4468 seq[name] = klass(value)
4469 expects.append(expect)
4474 def sequences_strategy(draw, seq_klass):
4475 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4477 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4478 for tag, expled in zip(tags, draw(lists(
4485 i for i, is_default in enumerate(draw(lists(
4491 names = list(draw(sets(
4496 seq_expectses = draw(lists(
4497 sequence_strategy(seq_klass=seq_klass),
4501 seqs = [seq for seq, _ in seq_expectses]
4503 for i, (name, seq) in enumerate(zip(names, seqs)):
4506 seq(default=(seq if i in defaulted else None), **inits[i]),
4508 seq_name = draw(text_letters())
4509 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4512 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4515 "expects": expects_inner,
4518 seq_outer[name] = seq_inner
4519 if seq_outer.specs[name].default is None:
4520 expect["presented"] = True
4521 expect_outers.append(expect)
4522 return seq_outer, expect_outers
4525 class SeqMixing(object):
4526 def test_invalid_value_type(self):
4527 with self.assertRaises(InvalidValueType) as err:
4528 self.base_klass(123)
4531 def test_invalid_value_type_set(self):
4532 class Seq(self.base_klass):
4533 schema = (("whatever", Boolean()),)
4535 with self.assertRaises(InvalidValueType) as err:
4536 seq["whatever"] = Integer(123)
4540 def test_optional(self, optional):
4541 obj = self.base_klass(default=self.base_klass(), optional=optional)
4542 self.assertTrue(obj.optional)
4544 @given(data_strategy())
4545 def test_ready(self, d):
4547 str(i): v for i, v in enumerate(d.draw(lists(
4554 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4561 for name in d.draw(permutations(
4562 list(ready.keys()) + list(non_ready.keys()),
4564 schema_input.append((name, Boolean()))
4566 class Seq(self.base_klass):
4567 schema = tuple(schema_input)
4569 for name in ready.keys():
4571 seq[name] = Boolean()
4572 self.assertFalse(seq.ready)
4575 for name, value in ready.items():
4576 seq[name] = Boolean(value)
4577 self.assertFalse(seq.ready)
4580 with self.assertRaises(ObjNotReady) as err:
4583 for name, value in non_ready.items():
4584 seq[name] = Boolean(value)
4585 self.assertTrue(seq.ready)
4589 @given(data_strategy())
4590 def test_call(self, d):
4591 class SeqInherited(self.base_klass):
4593 for klass in (self.base_klass, SeqInherited):
4602 ) = d.draw(seq_values_strategy(seq_klass=klass))
4603 obj_initial = klass(
4609 optional_initial or False,
4620 ) = d.draw(seq_values_strategy(
4622 do_expl=impl_initial is None,
4624 obj = obj_initial(value, impl, expl, default, optional)
4625 value_expected = default if value is None else value
4627 default_initial if value_expected is None
4630 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4631 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4632 self.assertEqual(obj.expl_tag, expl or expl_initial)
4634 {} if obj.default is None else obj.default._value,
4635 getattr(default_initial if default is None else default, "_value", {}),
4637 if obj.default is None:
4638 optional = optional_initial if optional is None else optional
4639 optional = False if optional is None else optional
4642 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4643 self.assertEqual(obj.optional, optional)
4645 @given(data_strategy())
4646 def test_copy(self, d):
4647 class SeqInherited(self.base_klass):
4649 for klass in (self.base_klass, SeqInherited):
4650 values = d.draw(seq_values_strategy(seq_klass=klass))
4651 obj = klass(*values)
4652 obj_copied = obj.copy()
4653 self.assert_copied_basic_fields(obj, obj_copied)
4654 self.assertEqual(obj.specs, obj_copied.specs)
4655 self.assertEqual(obj._value, obj_copied._value)
4657 @given(data_strategy())
4658 def test_stripped(self, d):
4659 value = d.draw(integers())
4660 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4662 class Seq(self.base_klass):
4664 schema = (("whatever", Integer()),)
4666 seq["whatever"] = Integer(value)
4667 with self.assertRaises(NotEnoughData):
4668 seq.decode(seq.encode()[:-1])
4670 @given(data_strategy())
4671 def test_stripped_expl(self, d):
4672 value = d.draw(integers())
4673 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4675 class Seq(self.base_klass):
4677 schema = (("whatever", Integer()),)
4679 seq["whatever"] = Integer(value)
4680 with self.assertRaises(NotEnoughData):
4681 seq.decode(seq.encode()[:-1])
4683 @given(binary(min_size=2))
4684 def test_non_tag_mismatch_raised(self, junk):
4686 _, _, len_encoded = tag_strip(memoryview(junk))
4687 len_decode(len_encoded)
4693 class Seq(self.base_klass):
4695 ("whatever", Integer()),
4697 ("whenever", Integer()),
4700 seq["whatever"] = Integer(123)
4701 seq["junk"] = Any(junk)
4702 seq["whenever"] = Integer(123)
4703 with self.assertRaises(DecodeError):
4704 seq.decode(seq.encode())
4707 integers(min_value=31),
4708 integers(min_value=0),
4711 def test_bad_tag(self, tag, offset, decode_path):
4712 with self.assertRaises(DecodeError) as err:
4713 self.base_klass().decode(
4714 tag_encode(tag)[:-1],
4716 decode_path=decode_path,
4719 self.assertEqual(err.exception.offset, offset)
4720 self.assertEqual(err.exception.decode_path, decode_path)
4723 integers(min_value=128),
4724 integers(min_value=0),
4727 def test_bad_len(self, l, offset, decode_path):
4728 with self.assertRaises(DecodeError) as err:
4729 self.base_klass().decode(
4730 self.base_klass.tag_default + len_encode(l)[:-1],
4732 decode_path=decode_path,
4735 self.assertEqual(err.exception.offset, offset)
4736 self.assertEqual(err.exception.decode_path, decode_path)
4738 def _assert_expects(self, seq, expects):
4739 for expect in expects:
4741 seq.specs[expect["name"]].optional,
4744 if expect["default_value"] is not None:
4746 seq.specs[expect["name"]].default,
4747 expect["default_value"],
4749 if expect["presented"]:
4750 self.assertIn(expect["name"], seq)
4751 self.assertEqual(seq[expect["name"]], expect["value"])
4753 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4754 @given(data_strategy())
4755 def test_symmetric(self, d):
4756 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4757 tail_junk = d.draw(binary(max_size=5))
4758 self.assertTrue(seq.ready)
4759 self.assertFalse(seq.decoded)
4760 self._assert_expects(seq, expects)
4763 self.assertTrue(seq.ready)
4764 seq_encoded = seq.encode()
4765 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4766 self.assertFalse(seq_decoded.lenindef)
4767 self.assertFalse(seq_decoded.ber_encoded)
4768 self.assertFalse(seq_decoded.bered)
4770 t, _, lv = tag_strip(seq_encoded)
4771 _, _, v = len_decode(lv)
4772 seq_encoded_lenindef = t + LENINDEF + v + EOC
4773 seq_decoded_lenindef, tail_lenindef = seq.decode(
4774 seq_encoded_lenindef + tail_junk,
4775 ctx={"bered": True},
4777 self.assertTrue(seq_decoded_lenindef.lenindef)
4778 self.assertTrue(seq_decoded_lenindef.bered)
4779 with self.assertRaises(DecodeError):
4780 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4781 with self.assertRaises(DecodeError):
4782 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4783 repr(seq_decoded_lenindef)
4784 pprint(seq_decoded_lenindef)
4785 self.assertTrue(seq_decoded_lenindef.ready)
4787 for decoded, decoded_tail, encoded in (
4788 (seq_decoded, tail, seq_encoded),
4789 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4791 self.assertEqual(decoded_tail, tail_junk)
4792 self._assert_expects(decoded, expects)
4793 self.assertEqual(seq, decoded)
4794 self.assertEqual(decoded.encode(), seq_encoded)
4795 self.assertEqual(decoded.tlvlen, len(encoded))
4796 for expect in expects:
4797 if not expect["presented"]:
4798 self.assertNotIn(expect["name"], decoded)
4800 self.assertIn(expect["name"], decoded)
4801 obj = decoded[expect["name"]]
4802 self.assertTrue(obj.decoded)
4803 offset = obj.expl_offset if obj.expled else obj.offset
4804 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4805 self.assertSequenceEqual(
4806 seq_encoded[offset:offset + tlvlen],
4810 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4811 @given(data_strategy())
4812 def test_symmetric_with_seq(self, d):
4813 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4814 self.assertTrue(seq.ready)
4815 seq_encoded = seq.encode()
4816 seq_decoded, tail = seq.decode(seq_encoded)
4817 self.assertEqual(tail, b"")
4818 self.assertTrue(seq.ready)
4819 self.assertEqual(seq, seq_decoded)
4820 self.assertEqual(seq_decoded.encode(), seq_encoded)
4821 for expect_outer in expect_outers:
4822 if not expect_outer["presented"]:
4823 self.assertNotIn(expect_outer["name"], seq_decoded)
4825 self.assertIn(expect_outer["name"], seq_decoded)
4826 obj = seq_decoded[expect_outer["name"]]
4827 self.assertTrue(obj.decoded)
4828 offset = obj.expl_offset if obj.expled else obj.offset
4829 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4830 self.assertSequenceEqual(
4831 seq_encoded[offset:offset + tlvlen],
4834 self._assert_expects(obj, expect_outer["expects"])
4836 @given(data_strategy())
4837 def test_default_disappears(self, d):
4838 _schema = list(d.draw(dictionaries(
4840 sets(integers(), min_size=2, max_size=2),
4844 class Seq(self.base_klass):
4846 (n, Integer(default=d))
4847 for n, (_, d) in _schema
4850 for name, (value, _) in _schema:
4851 seq[name] = Integer(value)
4852 self.assertEqual(len(seq._value), len(_schema))
4853 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4854 self.assertGreater(len(seq.encode()), len(empty_seq))
4855 for name, (_, default) in _schema:
4856 seq[name] = Integer(default)
4857 self.assertEqual(len(seq._value), 0)
4858 self.assertSequenceEqual(seq.encode(), empty_seq)
4860 @given(data_strategy())
4861 def test_encoded_default_not_accepted(self, d):
4862 _schema = list(d.draw(dictionaries(
4867 tags = [tag_encode(tag) for tag in d.draw(sets(
4868 integers(min_value=0),
4869 min_size=len(_schema),
4870 max_size=len(_schema),
4873 class SeqWithoutDefault(self.base_klass):
4875 (n, Integer(impl=t))
4876 for (n, _), t in zip(_schema, tags)
4878 seq_without_default = SeqWithoutDefault()
4879 for name, value in _schema:
4880 seq_without_default[name] = Integer(value)
4881 seq_encoded = seq_without_default.encode()
4883 class SeqWithDefault(self.base_klass):
4885 (n, Integer(default=v, impl=t))
4886 for (n, v), t in zip(_schema, tags)
4888 seq_with_default = SeqWithDefault()
4889 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
4890 seq_with_default.decode(seq_encoded)
4891 for ctx in ({"bered": True}, {"allow_default_values": True}):
4892 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
4893 self.assertTrue(seq_decoded.ber_encoded)
4894 self.assertTrue(seq_decoded.bered)
4895 for name, value in _schema:
4896 self.assertEqual(seq_decoded[name], seq_with_default[name])
4897 self.assertEqual(seq_decoded[name], value)
4899 @given(data_strategy())
4900 def test_missing_from_spec(self, d):
4901 names = list(d.draw(sets(text_letters(), min_size=2)))
4902 tags = [tag_encode(tag) for tag in d.draw(sets(
4903 integers(min_value=0),
4904 min_size=len(names),
4905 max_size=len(names),
4907 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4909 class SeqFull(self.base_klass):
4910 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4911 seq_full = SeqFull()
4912 for i, name in enumerate(names):
4913 seq_full[name] = Integer(i)
4914 seq_encoded = seq_full.encode()
4915 altered = names_tags[:-2] + names_tags[-1:]
4917 class SeqMissing(self.base_klass):
4918 schema = [(n, Integer(impl=t)) for n, t in altered]
4919 seq_missing = SeqMissing()
4920 with self.assertRaises(TagMismatch):
4921 seq_missing.decode(seq_encoded)
4923 @given(data_strategy())
4924 def test_bered(self, d):
4925 class Seq(self.base_klass):
4926 schema = (("underlying", Boolean()),)
4927 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
4928 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
4929 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
4930 self.assertFalse(decoded.ber_encoded)
4931 self.assertFalse(decoded.lenindef)
4932 self.assertTrue(decoded.bered)
4934 class Seq(self.base_klass):
4935 schema = (("underlying", OctetString()),)
4937 tag_encode(form=TagFormConstructed, num=4) +
4939 OctetString(b"whatever").encode() +
4942 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
4943 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
4944 self.assertFalse(decoded.ber_encoded)
4945 self.assertFalse(decoded.lenindef)
4946 self.assertTrue(decoded.bered)
4949 class TestSequence(SeqMixing, CommonMixin, TestCase):
4950 base_klass = Sequence
4956 def test_remaining(self, value, junk):
4957 class Seq(Sequence):
4959 ("whatever", Integer()),
4961 int_encoded = Integer(value).encode()
4963 Sequence.tag_default,
4964 len_encode(len(int_encoded + junk)),
4967 with assertRaisesRegex(self, DecodeError, "remaining"):
4968 Seq().decode(junked)
4970 @given(sets(text_letters(), min_size=2))
4971 def test_obj_unknown(self, names):
4972 missing = names.pop()
4974 class Seq(Sequence):
4975 schema = [(n, Boolean()) for n in names]
4977 with self.assertRaises(ObjUnknown) as err:
4980 with self.assertRaises(ObjUnknown) as err:
4981 seq[missing] = Boolean()
4984 def test_x690_vector(self):
4985 class Seq(Sequence):
4987 ("name", IA5String()),
4990 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4991 self.assertEqual(seq["name"], "Smith")
4992 self.assertEqual(seq["ok"], True)
4995 class TestSet(SeqMixing, CommonMixin, TestCase):
4998 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4999 @given(data_strategy())
5000 def test_sorted(self, d):
5002 tag_encode(tag) for tag in
5003 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5007 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5009 for name, _ in Seq.schema:
5010 seq[name] = OctetString(b"")
5011 seq_encoded = seq.encode()
5012 seq_decoded, _ = seq.decode(seq_encoded)
5013 self.assertSequenceEqual(
5014 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5015 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5018 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5019 @given(data_strategy())
5020 def test_unsorted(self, d):
5022 tag_encode(tag) for tag in
5023 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5025 tags = d.draw(permutations(tags))
5026 assume(tags != sorted(tags))
5027 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5028 seq_encoded = b"".join((
5030 len_encode(len(encoded)),
5035 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5037 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5038 seq.decode(seq_encoded)
5039 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5040 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5041 self.assertTrue(seq_decoded.ber_encoded)
5042 self.assertTrue(seq_decoded.bered)
5043 self.assertSequenceEqual(
5044 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5050 def seqof_values_strategy(draw, schema=None, do_expl=False):
5052 schema = draw(sampled_from((Boolean(), Integer())))
5053 bound_min, bound_max = sorted(draw(sets(
5054 integers(min_value=0, max_value=10),
5058 if isinstance(schema, Boolean):
5059 values_generator = booleans().map(Boolean)
5060 elif isinstance(schema, Integer):
5061 values_generator = integers().map(Integer)
5062 values_generator = lists(
5067 values = draw(one_of(none(), values_generator))
5071 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5073 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5074 default = draw(one_of(none(), values_generator))
5075 optional = draw(one_of(none(), booleans()))
5077 draw(integers(min_value=0)),
5078 draw(integers(min_value=0)),
5079 draw(integers(min_value=0)),
5084 (bound_min, bound_max),
5093 class SeqOfMixing(object):
5094 def test_invalid_value_type(self):
5095 with self.assertRaises(InvalidValueType) as err:
5096 self.base_klass(123)
5099 def test_invalid_values_type(self):
5100 class SeqOf(self.base_klass):
5102 with self.assertRaises(InvalidValueType) as err:
5103 SeqOf([Integer(123), Boolean(False), Integer(234)])
5106 def test_schema_required(self):
5107 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5108 self.base_klass.__mro__[1]()
5110 @given(booleans(), booleans(), binary(), binary())
5111 def test_comparison(self, value1, value2, tag1, tag2):
5112 class SeqOf(self.base_klass):
5114 obj1 = SeqOf([Boolean(value1)])
5115 obj2 = SeqOf([Boolean(value2)])
5116 self.assertEqual(obj1 == obj2, value1 == value2)
5117 self.assertEqual(obj1 != obj2, value1 != value2)
5118 self.assertEqual(obj1 == list(obj2), value1 == value2)
5119 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5120 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5121 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5122 self.assertEqual(obj1 == obj2, tag1 == tag2)
5123 self.assertEqual(obj1 != obj2, tag1 != tag2)
5125 @given(lists(booleans()))
5126 def test_iter(self, values):
5127 class SeqOf(self.base_klass):
5129 obj = SeqOf([Boolean(value) for value in values])
5130 self.assertEqual(len(obj), len(values))
5131 for i, value in enumerate(obj):
5132 self.assertEqual(value, values[i])
5134 @given(data_strategy())
5135 def test_ready(self, d):
5136 ready = [Integer(v) for v in d.draw(lists(
5143 range(d.draw(integers(min_value=1, max_value=5)))
5146 class SeqOf(self.base_klass):
5148 values = d.draw(permutations(ready + non_ready))
5150 for value in values:
5152 self.assertFalse(seqof.ready)
5155 with self.assertRaises(ObjNotReady) as err:
5158 for i, value in enumerate(values):
5159 self.assertEqual(seqof[i], value)
5160 if not seqof[i].ready:
5161 seqof[i] = Integer(i)
5162 self.assertTrue(seqof.ready)
5166 def test_spec_mismatch(self):
5167 class SeqOf(self.base_klass):
5170 seqof.append(Integer(123))
5171 with self.assertRaises(ValueError):
5172 seqof.append(Boolean(False))
5173 with self.assertRaises(ValueError):
5174 seqof[0] = Boolean(False)
5176 @given(data_strategy())
5177 def test_bounds_satisfied(self, d):
5178 class SeqOf(self.base_klass):
5180 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5181 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5182 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5183 SeqOf(value=value, bounds=(bound_min, bound_max))
5185 @given(data_strategy())
5186 def test_bounds_unsatisfied(self, d):
5187 class SeqOf(self.base_klass):
5189 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5190 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5191 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5192 with self.assertRaises(BoundsError) as err:
5193 SeqOf(value=value, bounds=(bound_min, bound_max))
5195 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5196 SeqOf(bounds=(bound_min, bound_max)).decode(
5197 SeqOf(value).encode()
5200 value = [Boolean(True)] * d.draw(integers(
5201 min_value=bound_max + 1,
5202 max_value=bound_max + 10,
5204 with self.assertRaises(BoundsError) as err:
5205 SeqOf(value=value, bounds=(bound_min, bound_max))
5207 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5208 SeqOf(bounds=(bound_min, bound_max)).decode(
5209 SeqOf(value).encode()
5213 @given(integers(min_value=1, max_value=10))
5214 def test_out_of_bounds(self, bound_max):
5215 class SeqOf(self.base_klass):
5217 bounds = (0, bound_max)
5219 for _ in range(bound_max):
5220 seqof.append(Integer(123))
5221 with self.assertRaises(BoundsError):
5222 seqof.append(Integer(123))
5224 @given(data_strategy())
5225 def test_call(self, d):
5235 ) = d.draw(seqof_values_strategy())
5237 class SeqOf(self.base_klass):
5238 schema = schema_initial
5239 obj_initial = SeqOf(
5240 value=value_initial,
5241 bounds=bounds_initial,
5244 default=default_initial,
5245 optional=optional_initial or False,
5246 _decoded=_decoded_initial,
5257 ) = d.draw(seqof_values_strategy(
5258 schema=schema_initial,
5259 do_expl=impl_initial is None,
5261 if (default is None) and (obj_initial.default is not None):
5264 (bounds is None) and
5265 (value is not None) and
5266 (bounds_initial is not None) and
5267 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5271 (bounds is None) and
5272 (default is not None) and
5273 (bounds_initial is not None) and
5274 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5286 value_expected = default if value is None else value
5288 default_initial if value_expected is None
5291 value_expected = () if value_expected is None else value_expected
5292 self.assertEqual(obj, value_expected)
5293 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5294 self.assertEqual(obj.expl_tag, expl or expl_initial)
5297 default_initial if default is None else default,
5299 if obj.default is None:
5300 optional = optional_initial if optional is None else optional
5301 optional = False if optional is None else optional
5304 self.assertEqual(obj.optional, optional)
5306 (obj._bound_min, obj._bound_max),
5307 bounds or bounds_initial or (0, float("+inf")),
5310 @given(seqof_values_strategy())
5311 def test_copy(self, values):
5312 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5314 class SeqOf(self.base_klass):
5322 optional=optional or False,
5325 obj_copied = obj.copy()
5326 self.assert_copied_basic_fields(obj, obj_copied)
5327 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5328 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5329 self.assertEqual(obj._value, obj_copied._value)
5333 integers(min_value=1).map(tag_encode),
5335 def test_stripped(self, values, tag_impl):
5336 class SeqOf(self.base_klass):
5337 schema = OctetString()
5338 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5339 with self.assertRaises(NotEnoughData):
5340 obj.decode(obj.encode()[:-1])
5344 integers(min_value=1).map(tag_ctxc),
5346 def test_stripped_expl(self, values, tag_expl):
5347 class SeqOf(self.base_klass):
5348 schema = OctetString()
5349 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5350 with self.assertRaises(NotEnoughData):
5351 obj.decode(obj.encode()[:-1])
5354 integers(min_value=31),
5355 integers(min_value=0),
5358 def test_bad_tag(self, tag, offset, decode_path):
5359 with self.assertRaises(DecodeError) as err:
5360 self.base_klass().decode(
5361 tag_encode(tag)[:-1],
5363 decode_path=decode_path,
5366 self.assertEqual(err.exception.offset, offset)
5367 self.assertEqual(err.exception.decode_path, decode_path)
5370 integers(min_value=128),
5371 integers(min_value=0),
5374 def test_bad_len(self, l, offset, decode_path):
5375 with self.assertRaises(DecodeError) as err:
5376 self.base_klass().decode(
5377 self.base_klass.tag_default + len_encode(l)[:-1],
5379 decode_path=decode_path,
5382 self.assertEqual(err.exception.offset, offset)
5383 self.assertEqual(err.exception.decode_path, decode_path)
5385 @given(binary(min_size=1))
5386 def test_tag_mismatch(self, impl):
5387 assume(impl != self.base_klass.tag_default)
5388 with self.assertRaises(TagMismatch):
5389 self.base_klass(impl=impl).decode(self.base_klass().encode())
5391 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5393 seqof_values_strategy(schema=Integer()),
5394 lists(integers().map(Integer)),
5395 integers(min_value=1).map(tag_ctxc),
5396 integers(min_value=0),
5399 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5400 _, _, _, _, _, default, optional, _decoded = values
5402 class SeqOf(self.base_klass):
5412 self.assertFalse(obj.expled)
5413 obj_encoded = obj.encode()
5414 obj_expled = obj(value, expl=tag_expl)
5415 self.assertTrue(obj_expled.expled)
5418 obj_expled_encoded = obj_expled.encode()
5419 obj_decoded, tail = obj_expled.decode(
5420 obj_expled_encoded + tail_junk,
5425 self.assertEqual(tail, tail_junk)
5426 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5427 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5428 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5429 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5431 obj_decoded.expl_llen,
5432 len(len_encode(len(obj_encoded))),
5434 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5435 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5438 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5440 self.assertEqual(obj_decoded.expl_offset, offset)
5441 for obj_inner in obj_decoded:
5442 self.assertIn(obj_inner, obj_decoded)
5443 self.assertSequenceEqual(
5446 obj_inner.offset - offset:
5447 obj_inner.offset + obj_inner.tlvlen - offset
5451 t, _, lv = tag_strip(obj_encoded)
5452 _, _, v = len_decode(lv)
5453 obj_encoded_lenindef = t + LENINDEF + v + EOC
5454 obj_decoded_lenindef, tail_lenindef = obj.decode(
5455 obj_encoded_lenindef + tail_junk,
5456 ctx={"bered": True},
5458 self.assertTrue(obj_decoded_lenindef.lenindef)
5459 self.assertTrue(obj_decoded_lenindef.bered)
5460 repr(obj_decoded_lenindef)
5461 pprint(obj_decoded_lenindef)
5462 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5463 with self.assertRaises(DecodeError):
5464 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5465 with self.assertRaises(DecodeError):
5466 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5468 @given(data_strategy())
5469 def test_bered(self, d):
5470 class SeqOf(self.base_klass):
5472 encoded = Boolean(False).encode()
5473 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5474 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5475 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5476 self.assertFalse(decoded.ber_encoded)
5477 self.assertFalse(decoded.lenindef)
5478 self.assertTrue(decoded.bered)
5480 class SeqOf(self.base_klass):
5481 schema = OctetString()
5482 encoded = OctetString(b"whatever").encode()
5484 tag_encode(form=TagFormConstructed, num=4) +
5486 OctetString(b"whatever").encode() +
5489 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5490 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5491 self.assertFalse(decoded.ber_encoded)
5492 self.assertFalse(decoded.lenindef)
5493 self.assertTrue(decoded.bered)
5496 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5497 class SeqOf(SequenceOf):
5501 def _test_symmetric_compare_objs(self, obj1, obj2):
5502 self.assertEqual(obj1, obj2)
5503 self.assertSequenceEqual(list(obj1), list(obj2))
5506 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5511 def _test_symmetric_compare_objs(self, obj1, obj2):
5512 self.assertSetEqual(
5513 set(int(v) for v in obj1),
5514 set(int(v) for v in obj2),
5517 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5518 @given(data_strategy())
5519 def test_sorted(self, d):
5520 values = [OctetString(v) for v in d.draw(lists(binary()))]
5523 schema = OctetString()
5525 seq_encoded = seq.encode()
5526 seq_decoded, _ = seq.decode(seq_encoded)
5527 self.assertSequenceEqual(
5528 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5529 b"".join(sorted([v.encode() for v in values])),
5532 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5533 @given(data_strategy())
5534 def test_unsorted(self, d):
5535 values = [OctetString(v).encode() for v in d.draw(sets(
5536 binary(min_size=1, max_size=5),
5540 values = d.draw(permutations(values))
5541 assume(values != sorted(values))
5542 encoded = b"".join(values)
5543 seq_encoded = b"".join((
5545 len_encode(len(encoded)),
5550 schema = OctetString()
5552 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5553 seq.decode(seq_encoded)
5555 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5556 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5557 self.assertTrue(seq_decoded.ber_encoded)
5558 self.assertTrue(seq_decoded.bered)
5559 self.assertSequenceEqual(
5560 [obj.encode() for obj in seq_decoded],
5565 class TestGoMarshalVectors(TestCase):
5567 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5568 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5569 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5570 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5571 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5573 class Seq(Sequence):
5575 ("erste", Integer()),
5576 ("zweite", Integer(optional=True))
5579 seq["erste"] = Integer(64)
5580 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5581 seq["erste"] = Integer(0x123456)
5582 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5583 seq["erste"] = Integer(64)
5584 seq["zweite"] = Integer(65)
5585 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5587 class NestedSeq(Sequence):
5591 seq["erste"] = Integer(127)
5592 seq["zweite"] = None
5593 nested = NestedSeq()
5594 nested["nest"] = seq
5595 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5597 self.assertSequenceEqual(
5598 OctetString(b"\x01\x02\x03").encode(),
5599 hexdec("0403010203"),
5602 class Seq(Sequence):
5604 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5607 seq["erste"] = Integer(64)
5608 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5610 class Seq(Sequence):
5612 ("erste", Integer(expl=tag_ctxc(5))),
5615 seq["erste"] = Integer(64)
5616 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5618 class Seq(Sequence):
5621 impl=tag_encode(0, klass=TagClassContext),
5626 seq["erste"] = Null()
5627 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5629 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5631 self.assertSequenceEqual(
5632 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5633 hexdec("170d3730303130313030303030305a"),
5635 self.assertSequenceEqual(
5636 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5637 hexdec("170d3039313131353232353631365a"),
5639 self.assertSequenceEqual(
5640 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5641 hexdec("180f32313030303430353132303130315a"),
5644 class Seq(Sequence):
5646 ("erste", GeneralizedTime()),
5649 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5650 self.assertSequenceEqual(
5652 hexdec("3011180f32303039313131353232353631365a"),
5655 self.assertSequenceEqual(
5656 BitString((1, b"\x80")).encode(),
5659 self.assertSequenceEqual(
5660 BitString((12, b"\x81\xF0")).encode(),
5661 hexdec("03030481f0"),
5664 self.assertSequenceEqual(
5665 ObjectIdentifier("1.2.3.4").encode(),
5666 hexdec("06032a0304"),
5668 self.assertSequenceEqual(
5669 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5670 hexdec("06092a864888932d010105"),
5672 self.assertSequenceEqual(
5673 ObjectIdentifier("2.100.3").encode(),
5674 hexdec("0603813403"),
5677 self.assertSequenceEqual(
5678 PrintableString("test").encode(),
5679 hexdec("130474657374"),
5681 self.assertSequenceEqual(
5682 PrintableString("x" * 127).encode(),
5683 hexdec("137F" + "78" * 127),
5685 self.assertSequenceEqual(
5686 PrintableString("x" * 128).encode(),
5687 hexdec("138180" + "78" * 128),
5689 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5691 class Seq(Sequence):
5693 ("erste", IA5String()),
5696 seq["erste"] = IA5String("test")
5697 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5699 class Seq(Sequence):
5701 ("erste", PrintableString()),
5704 seq["erste"] = PrintableString("test")
5705 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5706 seq["erste"] = PrintableString("test*")
5707 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5709 class Seq(Sequence):
5711 ("erste", Any(optional=True)),
5712 ("zweite", Integer()),
5715 seq["zweite"] = Integer(64)
5716 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5721 seq.append(Integer(10))
5722 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5724 class _SeqOf(SequenceOf):
5725 schema = PrintableString()
5727 class SeqOf(SequenceOf):
5730 _seqof.append(PrintableString("1"))
5732 seqof.append(_seqof)
5733 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5735 class Seq(Sequence):
5737 ("erste", Integer(default=1)),
5740 seq["erste"] = Integer(0)
5741 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5742 seq["erste"] = Integer(1)
5743 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5744 seq["erste"] = Integer(2)
5745 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5748 class TestPP(TestCase):
5749 @given(data_strategy())
5750 def test_oid_printing(self, d):
5752 str(ObjectIdentifier(k)): v * 2
5753 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5755 chosen = d.draw(sampled_from(sorted(oids)))
5756 chosen_id = oids[chosen]
5757 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5758 self.assertNotIn(chosen_id, pp_console_row(pp))
5759 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5762 class TestAutoAddSlots(TestCase):
5764 class Inher(Integer):
5767 with self.assertRaises(AttributeError):
5769 inher.unexistent = "whatever"
5772 class TestOIDDefines(TestCase):
5773 @given(data_strategy())
5774 def runTest(self, d):
5775 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5776 value_name_chosen = d.draw(sampled_from(value_names))
5778 ObjectIdentifier(oid)
5779 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5781 oid_chosen = d.draw(sampled_from(oids))
5782 values = d.draw(lists(
5784 min_size=len(value_names),
5785 max_size=len(value_names),
5788 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5789 oid: Integer() for oid in oids[:-1]
5792 for i, value_name in enumerate(value_names):
5793 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5795 class Seq(Sequence):
5798 for value_name, value in zip(value_names, values):
5799 seq[value_name] = Any(Integer(value).encode())
5800 seq["type"] = oid_chosen
5801 seq, _ = Seq().decode(seq.encode())
5802 for value_name in value_names:
5803 if value_name == value_name_chosen:
5805 self.assertIsNone(seq[value_name].defined)
5806 if value_name_chosen in oids[:-1]:
5807 self.assertIsNotNone(seq[value_name_chosen].defined)
5808 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5809 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5812 class TestDefinesByPath(TestCase):
5813 def test_generated(self):
5814 class Seq(Sequence):
5816 ("type", ObjectIdentifier()),
5817 ("value", OctetString(expl=tag_ctxc(123))),
5820 class SeqInner(Sequence):
5822 ("typeInner", ObjectIdentifier()),
5823 ("valueInner", Any()),
5826 class PairValue(SetOf):
5829 class Pair(Sequence):
5831 ("type", ObjectIdentifier()),
5832 ("value", PairValue()),
5835 class Pairs(SequenceOf):
5842 type_octet_stringed,
5844 ObjectIdentifier(oid)
5845 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5847 seq_integered = Seq()
5848 seq_integered["type"] = type_integered
5849 seq_integered["value"] = OctetString(Integer(123).encode())
5850 seq_integered_raw = seq_integered.encode()
5854 (type_octet_stringed, OctetString(b"whatever")),
5855 (type_integered, Integer(123)),
5856 (type_octet_stringed, OctetString(b"whenever")),
5857 (type_integered, Integer(234)),
5859 for t, v in pairs_input:
5862 pair["value"] = PairValue((Any(v),))
5864 seq_inner = SeqInner()
5865 seq_inner["typeInner"] = type_innered
5866 seq_inner["valueInner"] = Any(pairs)
5867 seq_sequenced = Seq()
5868 seq_sequenced["type"] = type_sequenced
5869 seq_sequenced["value"] = OctetString(seq_inner.encode())
5870 seq_sequenced_raw = seq_sequenced.encode()
5872 defines_by_path = []
5873 seq_integered, _ = Seq().decode(seq_integered_raw)
5874 self.assertIsNone(seq_integered["value"].defined)
5875 defines_by_path.append(
5876 (("type",), ((("value",), {
5877 type_integered: Integer(),
5878 type_sequenced: SeqInner(),
5881 seq_integered, _ = Seq().decode(
5883 ctx={"defines_by_path": defines_by_path},
5885 self.assertIsNotNone(seq_integered["value"].defined)
5886 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5887 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5888 self.assertTrue(seq_integered_raw[
5889 seq_integered["value"].defined[1].offset:
5890 ].startswith(Integer(123).encode()))
5892 seq_sequenced, _ = Seq().decode(
5894 ctx={"defines_by_path": defines_by_path},
5896 self.assertIsNotNone(seq_sequenced["value"].defined)
5897 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5898 seq_inner = seq_sequenced["value"].defined[1]
5899 self.assertIsNone(seq_inner["valueInner"].defined)
5901 defines_by_path.append((
5902 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5903 ((("valueInner",), {type_innered: Pairs()}),),
5905 seq_sequenced, _ = Seq().decode(
5907 ctx={"defines_by_path": defines_by_path},
5909 self.assertIsNotNone(seq_sequenced["value"].defined)
5910 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5911 seq_inner = seq_sequenced["value"].defined[1]
5912 self.assertIsNotNone(seq_inner["valueInner"].defined)
5913 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5914 pairs = seq_inner["valueInner"].defined[1]
5916 self.assertIsNone(pair["value"][0].defined)
5918 defines_by_path.append((
5921 DecodePathDefBy(type_sequenced),
5923 DecodePathDefBy(type_innered),
5928 type_integered: Integer(),
5929 type_octet_stringed: OctetString(),
5932 seq_sequenced, _ = Seq().decode(
5934 ctx={"defines_by_path": defines_by_path},
5936 self.assertIsNotNone(seq_sequenced["value"].defined)
5937 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5938 seq_inner = seq_sequenced["value"].defined[1]
5939 self.assertIsNotNone(seq_inner["valueInner"].defined)
5940 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5941 pairs_got = seq_inner["valueInner"].defined[1]
5942 for pair_input, pair_got in zip(pairs_input, pairs_got):
5943 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5944 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5946 @given(oid_strategy(), integers())
5947 def test_simple(self, oid, tgt):
5948 class Inner(Sequence):
5950 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5951 ObjectIdentifier(oid): Integer(),
5955 class Outer(Sequence):
5958 ("tgt", OctetString()),
5962 inner["oid"] = ObjectIdentifier(oid)
5964 outer["inner"] = inner
5965 outer["tgt"] = OctetString(Integer(tgt).encode())
5966 decoded, _ = Outer().decode(outer.encode())
5967 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5970 class TestAbsDecodePath(TestCase):
5972 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5973 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5975 def test_concat(self, decode_path, rel_path):
5976 self.assertSequenceEqual(
5977 abs_decode_path(decode_path, rel_path),
5978 decode_path + rel_path,
5982 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5983 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5985 def test_abs(self, decode_path, rel_path):
5986 self.assertSequenceEqual(
5987 abs_decode_path(decode_path, ("/",) + rel_path),
5992 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5993 integers(min_value=1, max_value=3),
5994 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5996 def test_dots(self, decode_path, number_of_dots, rel_path):
5997 self.assertSequenceEqual(
5998 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5999 decode_path[:-number_of_dots] + rel_path,
6003 class TestStrictDefaultExistence(TestCase):
6004 @given(data_strategy())
6005 def runTest(self, d):
6006 count = d.draw(integers(min_value=1, max_value=10))
6007 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6009 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6010 for i in range(count)
6012 for klass in (Sequence, Set):
6016 for i in range(count):
6017 seq["int%d" % i] = Integer(123)
6019 chosen_choice = "int%d" % chosen
6020 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6021 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6023 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6024 self.assertTrue(decoded.ber_encoded)
6025 self.assertTrue(decoded.bered)
6026 decoded, _ = seq.decode(raw, ctx={"bered": True})
6027 self.assertTrue(decoded.ber_encoded)
6028 self.assertTrue(decoded.bered)
6031 class TestX690PrefixedType(TestCase):
6033 self.assertSequenceEqual(
6034 VisibleString("Jones").encode(),
6035 hexdec("1A054A6F6E6573"),
6037 self.assertSequenceEqual(
6040 impl=tag_encode(3, klass=TagClassApplication),
6042 hexdec("43054A6F6E6573"),
6044 self.assertSequenceEqual(
6048 impl=tag_encode(3, klass=TagClassApplication),
6052 hexdec("A20743054A6F6E6573"),
6054 self.assertSequenceEqual(
6058 impl=tag_encode(3, klass=TagClassApplication),
6060 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6062 hexdec("670743054A6F6E6573"),
6064 self.assertSequenceEqual(
6065 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6066 hexdec("82054A6F6E6573"),
6070 class TestExplOOB(TestCase):
6072 expl = tag_ctxc(123)
6073 raw = Integer(123).encode() + Integer(234).encode()
6074 raw = b"".join((expl, len_encode(len(raw)), raw))
6075 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6076 Integer(expl=expl).decode(raw)
6077 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})