2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2020 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, version 3 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this program. If not, see
16 # <http://www.gnu.org/licenses/>.
19 from copy import deepcopy
20 from datetime import datetime
21 from importlib import import_module
22 from string import ascii_letters
23 from string import digits
24 from string import printable
25 from string import whitespace
27 from unittest import TestCase
29 from hypothesis import assume
30 from hypothesis import given
31 from hypothesis import settings
32 from hypothesis.strategies import binary
33 from hypothesis.strategies import booleans
34 from hypothesis.strategies import composite
35 from hypothesis.strategies import data as data_strategy
36 from hypothesis.strategies import datetimes
37 from hypothesis.strategies import dictionaries
38 from hypothesis.strategies import integers
39 from hypothesis.strategies import just
40 from hypothesis.strategies import lists
41 from hypothesis.strategies import none
42 from hypothesis.strategies import one_of
43 from hypothesis.strategies import permutations
44 from hypothesis.strategies import sampled_from
45 from hypothesis.strategies import sets
46 from hypothesis.strategies import text
47 from hypothesis.strategies import tuples
48 from six import assertRaisesRegex
49 from six import binary_type
50 from six import byte2int
51 from six import indexbytes
52 from six import int2byte
53 from six import iterbytes
55 from six import text_type
56 from six import unichr as six_unichr
57 from six.moves.cPickle import dumps as pickle_dumps
58 from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto
59 from six.moves.cPickle import loads as pickle_loads
61 from pyderasn import _pp
62 from pyderasn import abs_decode_path
63 from pyderasn import Any
64 from pyderasn import BitString
65 from pyderasn import BMPString
66 from pyderasn import Boolean
67 from pyderasn import BoundsError
68 from pyderasn import Choice
69 from pyderasn import DecodeError
70 from pyderasn import DecodePathDefBy
71 from pyderasn import Enumerated
72 from pyderasn import EOC
73 from pyderasn import EOC_LEN
74 from pyderasn import ExceedingData
75 from pyderasn import GeneralizedTime
76 from pyderasn import GeneralString
77 from pyderasn import GraphicString
78 from pyderasn import hexdec
79 from pyderasn import hexenc
80 from pyderasn import IA5String
81 from pyderasn import Integer
82 from pyderasn import InvalidLength
83 from pyderasn import InvalidOID
84 from pyderasn import InvalidValueType
85 from pyderasn import len_decode
86 from pyderasn import len_encode
87 from pyderasn import LEN_YYMMDDHHMMSSZ
88 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
89 from pyderasn import LEN_YYYYMMDDHHMMSSZ
90 from pyderasn import LENINDEF
91 from pyderasn import LenIndefForm
92 from pyderasn import NotEnoughData
93 from pyderasn import Null
94 from pyderasn import NumericString
95 from pyderasn import ObjectIdentifier
96 from pyderasn import ObjNotReady
97 from pyderasn import ObjUnknown
98 from pyderasn import OctetString
99 from pyderasn import pp_console_row
100 from pyderasn import pprint
101 from pyderasn import PrintableString
102 from pyderasn import Sequence
103 from pyderasn import SequenceOf
104 from pyderasn import Set
105 from pyderasn import SetOf
106 from pyderasn import tag_ctxc
107 from pyderasn import tag_ctxp
108 from pyderasn import tag_decode
109 from pyderasn import tag_encode
110 from pyderasn import tag_strip
111 from pyderasn import TagClassApplication
112 from pyderasn import TagClassContext
113 from pyderasn import TagClassPrivate
114 from pyderasn import TagClassUniversal
115 from pyderasn import TagFormConstructed
116 from pyderasn import TagFormPrimitive
117 from pyderasn import TagMismatch
118 from pyderasn import TeletexString
119 from pyderasn import UniversalString
120 from pyderasn import UTCTime
121 from pyderasn import UTF8String
122 from pyderasn import VideotexString
123 from pyderasn import VisibleString
126 settings.register_profile("local", settings(
129 settings.load_profile("local")
130 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
132 tag_classes = sampled_from((
138 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
139 decode_path_strat = lists(integers(), max_size=3).map(
140 lambda decode_path: tuple(str(dp) for dp in decode_path)
142 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
145 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
147 self_module = import_module(__name__)
150 def register_class(klass):
151 klassname = klass.__name__ + str(time()).replace(".", "")
152 klass.__name__ = klassname
153 klass.__qualname__ = klassname
154 setattr(self_module, klassname, klass)
157 def assert_exceeding_data(self, call, junk):
159 with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)):
163 class TestHex(TestCase):
165 def test_symmetric(self, data):
166 self.assertEqual(hexdec(hexenc(data)), data)
169 class TestTagCoder(TestCase):
170 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
174 integers(min_value=0, max_value=30),
177 def test_short(self, klass, form, num, junk):
178 raw = tag_encode(klass=klass, form=form, num=num)
179 self.assertEqual(tag_decode(raw), (klass, form, num))
180 self.assertEqual(len(raw), 1)
182 byte2int(tag_encode(klass=klass, form=form, num=0)),
183 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
185 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
186 self.assertSequenceEqual(stripped.tobytes(), raw)
187 self.assertEqual(tlen, len(raw))
188 self.assertSequenceEqual(tail, junk)
190 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
194 integers(min_value=31),
197 def test_long(self, klass, form, num, junk):
198 raw = tag_encode(klass=klass, form=form, num=num)
199 self.assertEqual(tag_decode(raw), (klass, form, num))
200 self.assertGreater(len(raw), 1)
202 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
205 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
206 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
207 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
208 self.assertSequenceEqual(stripped.tobytes(), raw)
209 self.assertEqual(tlen, len(raw))
210 self.assertSequenceEqual(tail, junk)
212 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
213 @given(integers(min_value=31))
214 def test_unfinished_tag(self, num):
215 raw = bytearray(tag_encode(num=num))
216 for i in range(1, len(raw)):
218 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
219 tag_strip(bytes(raw))
221 def test_go_vectors_valid(self):
222 for data, (eklass, etag, elen, eform) in (
223 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
224 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
225 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
226 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
227 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
228 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
229 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
230 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
231 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
232 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
234 tag, _, len_encoded = tag_strip(memoryview(data))
235 klass, form, num = tag_decode(tag)
236 _len, _, tail = len_decode(len_encoded)
237 self.assertSequenceEqual(tail, b"")
238 self.assertEqual(klass, eklass)
239 self.assertEqual(num, etag)
240 self.assertEqual(_len, elen)
241 self.assertEqual(form, eform)
243 def test_go_vectors_invalid(self):
251 with self.assertRaises(DecodeError):
252 _, _, len_encoded = tag_strip(memoryview(data))
253 len_decode(len_encoded)
256 integers(min_value=0, max_value=127),
257 integers(min_value=0, max_value=2),
259 def test_long_instead_of_short(self, l, dummy_num):
260 octets = (b"\x00" * dummy_num) + int2byte(l)
261 octets = int2byte((dummy_num + 1) | 0x80) + octets
262 with self.assertRaises(DecodeError):
266 class TestLenCoder(TestCase):
267 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
269 integers(min_value=0, max_value=127),
272 def test_short(self, l, junk):
273 raw = len_encode(l) + junk
274 decoded, llen, tail = len_decode(memoryview(raw))
275 self.assertEqual(decoded, l)
276 self.assertEqual(llen, 1)
277 self.assertEqual(len(raw), 1 + len(junk))
278 self.assertEqual(tail.tobytes(), junk)
280 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
282 integers(min_value=128),
285 def test_long(self, l, junk):
286 raw = len_encode(l) + junk
287 decoded, llen, tail = len_decode(memoryview(raw))
288 self.assertEqual(decoded, l)
289 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
290 self.assertEqual(llen, len(raw) - len(junk))
291 self.assertNotEqual(indexbytes(raw, 1), 0)
292 self.assertSequenceEqual(tail.tobytes(), junk)
294 def test_empty(self):
295 with self.assertRaises(NotEnoughData):
298 @given(integers(min_value=128))
299 def test_stripped(self, _len):
300 with self.assertRaises(NotEnoughData):
301 len_decode(len_encode(_len)[:-1])
304 text_printable = text(alphabet=printable, min_size=1)
308 def text_letters(draw):
309 result = draw(text(alphabet=ascii_letters, min_size=1))
311 result = result.encode("ascii")
315 class CommonMixin(object):
316 def test_tag_default(self):
317 obj = self.base_klass()
318 self.assertEqual(obj.tag, obj.tag_default)
320 def test_simultaneous_impl_expl(self):
321 with self.assertRaises(ValueError):
322 self.base_klass(impl=b"whatever", expl=b"whenever")
324 @given(binary(min_size=1), integers(), integers(), integers())
325 def test_decoded(self, impl, offset, llen, vlen):
326 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
327 self.assertEqual(obj.offset, offset)
328 self.assertEqual(obj.llen, llen)
329 self.assertEqual(obj.vlen, vlen)
330 self.assertEqual(obj.tlen, len(impl))
331 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
333 @given(binary(min_size=1))
334 def test_impl_inherited(self, impl_tag):
335 class Inherited(self.base_klass):
338 self.assertSequenceEqual(obj.impl, impl_tag)
339 self.assertFalse(obj.expled)
342 def test_expl_inherited(self, expl_tag):
343 class Inherited(self.base_klass):
346 self.assertSequenceEqual(obj.expl, expl_tag)
347 self.assertTrue(obj.expled)
349 def assert_copied_basic_fields(self, obj, obj_copied):
350 self.assertEqual(obj, obj_copied)
351 self.assertSequenceEqual(obj.tag, obj_copied.tag)
352 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
353 self.assertEqual(obj.default, obj_copied.default)
354 self.assertEqual(obj.optional, obj_copied.optional)
355 self.assertEqual(obj.offset, obj_copied.offset)
356 self.assertEqual(obj.llen, obj_copied.llen)
357 self.assertEqual(obj.vlen, obj_copied.vlen)
361 def boolean_values_strategy(draw, do_expl=False):
362 value = draw(one_of(none(), booleans()))
366 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
368 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
369 default = draw(one_of(none(), booleans()))
370 optional = draw(one_of(none(), booleans()))
372 draw(integers(min_value=0)),
373 draw(integers(min_value=0)),
374 draw(integers(min_value=0)),
376 return (value, impl, expl, default, optional, _decoded)
379 class BooleanInherited(Boolean):
383 class TestBoolean(CommonMixin, TestCase):
386 def test_invalid_value_type(self):
387 with self.assertRaises(InvalidValueType) as err:
392 def test_optional(self, optional):
393 obj = Boolean(default=Boolean(False), optional=optional)
394 self.assertTrue(obj.optional)
397 def test_ready(self, value):
399 self.assertFalse(obj.ready)
402 pprint(obj, big_blobs=True, with_decode_path=True)
403 with self.assertRaises(ObjNotReady) as err:
407 self.assertTrue(obj.ready)
410 pprint(obj, big_blobs=True, with_decode_path=True)
412 @given(booleans(), booleans(), binary(), binary())
413 def test_comparison(self, value1, value2, tag1, tag2):
414 for klass in (Boolean, BooleanInherited):
417 self.assertEqual(obj1 == obj2, value1 == value2)
418 self.assertEqual(obj1 != obj2, value1 != value2)
419 self.assertEqual(obj1 == bool(obj2), value1 == value2)
420 obj1 = klass(value1, impl=tag1)
421 obj2 = klass(value1, impl=tag2)
422 self.assertEqual(obj1 == obj2, tag1 == tag2)
423 self.assertEqual(obj1 != obj2, tag1 != tag2)
425 @given(data_strategy())
426 def test_call(self, d):
427 for klass in (Boolean, BooleanInherited):
435 ) = d.draw(boolean_values_strategy())
441 optional_initial or False,
451 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
452 obj = obj_initial(value, impl, expl, default, optional)
454 value_expected = default if value is None else value
456 default_initial if value_expected is None
459 self.assertEqual(obj, value_expected)
460 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
461 self.assertEqual(obj.expl_tag, expl or expl_initial)
464 default_initial if default is None else default,
466 if obj.default is None:
467 optional = optional_initial if optional is None else optional
468 optional = False if optional is None else optional
471 self.assertEqual(obj.optional, optional)
473 @given(boolean_values_strategy())
474 def test_copy(self, values):
475 for klass in (Boolean, BooleanInherited):
477 for copy_func in copy_funcs:
478 obj_copied = copy_func(obj)
479 self.assert_copied_basic_fields(obj, obj_copied)
483 integers(min_value=1).map(tag_encode),
485 def test_stripped(self, value, tag_impl):
486 obj = Boolean(value, impl=tag_impl)
487 with self.assertRaises(NotEnoughData):
488 obj.decode(obj.encode()[:-1])
492 integers(min_value=1).map(tag_ctxc),
494 def test_stripped_expl(self, value, tag_expl):
495 obj = Boolean(value, expl=tag_expl)
496 with self.assertRaises(NotEnoughData):
497 obj.decode(obj.encode()[:-1])
500 integers(min_value=31),
501 integers(min_value=0),
504 def test_bad_tag(self, tag, offset, decode_path):
505 with self.assertRaises(DecodeError) as err:
507 tag_encode(tag)[:-1],
509 decode_path=decode_path,
512 self.assertEqual(err.exception.offset, offset)
513 self.assertEqual(err.exception.decode_path, decode_path)
516 integers(min_value=31),
517 integers(min_value=0),
520 def test_bad_expl_tag(self, tag, offset, decode_path):
521 with self.assertRaises(DecodeError) as err:
522 Boolean(expl=Boolean.tag_default).decode(
523 tag_encode(tag)[:-1],
525 decode_path=decode_path,
528 self.assertEqual(err.exception.offset, offset)
529 self.assertEqual(err.exception.decode_path, decode_path)
532 integers(min_value=128),
533 integers(min_value=0),
536 def test_bad_len(self, l, offset, decode_path):
537 with self.assertRaises(DecodeError) as err:
539 Boolean.tag_default + len_encode(l)[:-1],
541 decode_path=decode_path,
544 self.assertEqual(err.exception.offset, offset)
545 self.assertEqual(err.exception.decode_path, decode_path)
548 integers(min_value=128),
549 integers(min_value=0),
552 def test_bad_expl_len(self, l, offset, decode_path):
553 with self.assertRaises(DecodeError) as err:
554 Boolean(expl=Boolean.tag_default).decode(
555 Boolean.tag_default + len_encode(l)[:-1],
557 decode_path=decode_path,
560 self.assertEqual(err.exception.offset, offset)
561 self.assertEqual(err.exception.decode_path, decode_path)
563 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
565 boolean_values_strategy(),
567 integers(min_value=1).map(tag_ctxc),
568 integers(min_value=0),
571 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
572 for klass in (Boolean, BooleanInherited):
573 _, _, _, default, optional, _decoded = values
582 pprint(obj, big_blobs=True, with_decode_path=True)
583 self.assertFalse(obj.expled)
584 obj_encoded = obj.encode()
585 obj_expled = obj(value, expl=tag_expl)
586 self.assertTrue(obj_expled.expled)
588 list(obj_expled.pps())
589 pprint(obj_expled, big_blobs=True, with_decode_path=True)
590 obj_expled_hex_encoded = obj_expled.hexencode()
591 ctx_copied = deepcopy(ctx_dummy)
592 obj_decoded, tail = obj_expled.hexdecode(
593 obj_expled_hex_encoded + hexenc(tail_junk),
597 self.assertDictEqual(ctx_copied, ctx_dummy)
599 list(obj_decoded.pps())
600 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
601 self.assertEqual(tail, tail_junk)
602 self.assertEqual(obj_decoded, obj_expled)
603 self.assertNotEqual(obj_decoded, obj)
604 self.assertEqual(bool(obj_decoded), bool(obj_expled))
605 self.assertEqual(bool(obj_decoded), bool(obj))
606 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
607 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
608 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
610 obj_decoded.expl_llen,
611 len(len_encode(len(obj_encoded))),
613 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
614 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
617 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
619 self.assertEqual(obj_decoded.expl_offset, offset)
620 assert_exceeding_data(
622 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
626 @given(integers(min_value=2))
627 def test_invalid_len(self, l):
628 with self.assertRaises(InvalidLength):
629 Boolean().decode(b"".join((
635 @given(integers(min_value=0 + 1, max_value=255 - 1))
636 def test_ber_value(self, value):
637 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
638 Boolean().decode(b"".join((
643 obj, _ = Boolean().decode(
651 self.assertTrue(bool(obj))
652 self.assertTrue(obj.ber_encoded)
653 self.assertFalse(obj.lenindef)
654 self.assertTrue(obj.bered)
656 self.assertTrue(obj.ber_encoded)
657 self.assertFalse(obj.lenindef)
658 self.assertTrue(obj.bered)
661 integers(min_value=1).map(tag_ctxc),
662 binary().filter(lambda x: not x.startswith(EOC)),
664 def test_ber_expl_no_eoc(self, expl, junk):
665 encoded = expl + LENINDEF + Boolean(False).encode()
666 with self.assertRaises(LenIndefForm):
667 Boolean(expl=expl).decode(encoded + junk)
668 with assertRaisesRegex(self, DecodeError, "no EOC"):
669 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
670 obj, tail = Boolean(expl=expl).decode(
671 encoded + EOC + junk,
674 self.assertTrue(obj.expl_lenindef)
675 self.assertFalse(obj.lenindef)
676 self.assertFalse(obj.ber_encoded)
677 self.assertTrue(obj.bered)
679 self.assertTrue(obj.expl_lenindef)
680 self.assertFalse(obj.lenindef)
681 self.assertFalse(obj.ber_encoded)
682 self.assertTrue(obj.bered)
683 self.assertSequenceEqual(tail, junk)
686 pprint(obj, big_blobs=True, with_decode_path=True)
689 integers(min_value=1).map(tag_ctxc),
696 def test_ber_expl(self, expl, values):
702 Boolean(value).encode() +
705 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
707 class SeqOf(SequenceOf):
708 schema = Boolean(expl=expl)
709 with self.assertRaises(LenIndefForm):
710 SeqOf().decode(encoded)
711 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
712 self.assertSequenceEqual(tail, b"")
713 self.assertSequenceEqual([bool(v) for v in seqof], values)
729 len(expl) + 1 + 3 + EOC_LEN,
740 pprint(seqof, big_blobs=True, with_decode_path=True)
744 def integer_values_strategy(draw, do_expl=False):
745 bound_min, value, default, bound_max = sorted(draw(sets(
754 _specs = draw(sets(text_letters()))
757 min_size=len(_specs),
758 max_size=len(_specs),
760 _specs = list(zip(_specs, values))
763 bounds = (bound_min, bound_max)
767 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
769 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
772 optional = draw(one_of(none(), booleans()))
774 draw(integers(min_value=0)),
775 draw(integers(min_value=0)),
776 draw(integers(min_value=0)),
778 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
781 class IntegerInherited(Integer):
785 class TestInteger(CommonMixin, TestCase):
788 def test_invalid_value_type(self):
789 with self.assertRaises(InvalidValueType) as err:
793 @given(sets(text_letters(), min_size=2))
794 def test_unknown_name(self, names_input):
795 missing = names_input.pop()
798 schema = [(n, 123) for n in names_input]
799 with self.assertRaises(ObjUnknown) as err:
803 @given(sets(text_letters(), min_size=2))
804 def test_known_name(self, names_input):
806 schema = [(n, 123) for n in names_input]
807 Int(names_input.pop())
810 def test_optional(self, optional):
811 obj = Integer(default=Integer(0), optional=optional)
812 self.assertTrue(obj.optional)
815 def test_ready(self, value):
817 self.assertFalse(obj.ready)
820 pprint(obj, big_blobs=True, with_decode_path=True)
821 with self.assertRaises(ObjNotReady) as err:
825 self.assertTrue(obj.ready)
828 pprint(obj, big_blobs=True, with_decode_path=True)
831 @given(integers(), integers(), binary(), binary())
832 def test_comparison(self, value1, value2, tag1, tag2):
833 for klass in (Integer, IntegerInherited):
836 self.assertEqual(obj1 == obj2, value1 == value2)
837 self.assertEqual(obj1 != obj2, value1 != value2)
838 self.assertEqual(obj1 == int(obj2), value1 == value2)
839 obj1 = klass(value1, impl=tag1)
840 obj2 = klass(value1, impl=tag2)
841 self.assertEqual(obj1 == obj2, tag1 == tag2)
842 self.assertEqual(obj1 != obj2, tag1 != tag2)
844 @given(lists(integers()))
845 def test_sorted_works(self, values):
846 self.assertSequenceEqual(
847 [int(v) for v in sorted(Integer(v) for v in values)],
851 @given(data_strategy())
852 def test_named(self, d):
853 names_input = list(d.draw(sets(text_letters(), min_size=1)))
854 values_input = list(d.draw(sets(
856 min_size=len(names_input),
857 max_size=len(names_input),
859 chosen_name = d.draw(sampled_from(names_input))
860 names_input = dict(zip(names_input, values_input))
864 _int = Int(chosen_name)
865 self.assertEqual(_int.named, chosen_name)
866 self.assertEqual(int(_int), names_input[chosen_name])
868 @given(integers(), integers(min_value=0), integers(min_value=0))
869 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
870 value = bound_min + value_delta
871 bound_max = value + bound_delta
872 Integer(value=value, bounds=(bound_min, bound_max))
874 @given(sets(integers(), min_size=3, max_size=3))
875 def test_bounds_unsatisfied(self, values):
876 values = sorted(values)
877 with self.assertRaises(BoundsError) as err:
878 Integer(value=values[0], bounds=(values[1], values[2]))
880 with assertRaisesRegex(self, DecodeError, "bounds") as err:
881 Integer(bounds=(values[1], values[2])).decode(
882 Integer(values[0]).encode()
885 with self.assertRaises(BoundsError) as err:
886 Integer(value=values[2], bounds=(values[0], values[1]))
888 with assertRaisesRegex(self, DecodeError, "bounds") as err:
889 Integer(bounds=(values[0], values[1])).decode(
890 Integer(values[2]).encode()
894 @given(data_strategy())
895 def test_call(self, d):
896 for klass in (Integer, IntegerInherited):
906 ) = d.draw(integer_values_strategy())
913 optional_initial or False,
926 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
927 if (default is None) and (obj_initial.default is not None):
931 (value is not None) and
932 (bounds_initial is not None) and
933 not (bounds_initial[0] <= value <= bounds_initial[1])
938 (default is not None) and
939 (bounds_initial is not None) and
940 not (bounds_initial[0] <= default <= bounds_initial[1])
943 obj = obj_initial(value, bounds, impl, expl, default, optional)
945 value_expected = default if value is None else value
947 default_initial if value_expected is None
950 self.assertEqual(obj, value_expected)
951 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
952 self.assertEqual(obj.expl_tag, expl or expl_initial)
955 default_initial if default is None else default,
957 if obj.default is None:
958 optional = optional_initial if optional is None else optional
959 optional = False if optional is None else optional
962 self.assertEqual(obj.optional, optional)
964 (obj._bound_min, obj._bound_max),
965 bounds or bounds_initial or (float("-inf"), float("+inf")),
969 {} if _specs_initial is None else dict(_specs_initial),
972 @given(integer_values_strategy())
973 def test_copy(self, values):
974 for klass in (Integer, IntegerInherited):
976 for copy_func in copy_funcs:
977 obj_copied = copy_func(obj)
978 self.assert_copied_basic_fields(obj, obj_copied)
979 self.assertEqual(obj.specs, obj_copied.specs)
980 self.assertEqual(obj._bound_min, obj_copied._bound_min)
981 self.assertEqual(obj._bound_max, obj_copied._bound_max)
982 self.assertEqual(obj._value, obj_copied._value)
986 integers(min_value=1).map(tag_encode),
988 def test_stripped(self, value, tag_impl):
989 obj = Integer(value, impl=tag_impl)
990 with self.assertRaises(NotEnoughData):
991 obj.decode(obj.encode()[:-1])
995 integers(min_value=1).map(tag_ctxc),
997 def test_stripped_expl(self, value, tag_expl):
998 obj = Integer(value, expl=tag_expl)
999 with self.assertRaises(NotEnoughData):
1000 obj.decode(obj.encode()[:-1])
1002 def test_zero_len(self):
1003 with self.assertRaises(NotEnoughData):
1004 Integer().decode(b"".join((
1005 Integer.tag_default,
1010 integers(min_value=31),
1011 integers(min_value=0),
1014 def test_bad_tag(self, tag, offset, decode_path):
1015 with self.assertRaises(DecodeError) as err:
1017 tag_encode(tag)[:-1],
1019 decode_path=decode_path,
1022 self.assertEqual(err.exception.offset, offset)
1023 self.assertEqual(err.exception.decode_path, decode_path)
1026 integers(min_value=128),
1027 integers(min_value=0),
1030 def test_bad_len(self, l, offset, decode_path):
1031 with self.assertRaises(DecodeError) as err:
1033 Integer.tag_default + len_encode(l)[:-1],
1035 decode_path=decode_path,
1038 self.assertEqual(err.exception.offset, offset)
1039 self.assertEqual(err.exception.decode_path, decode_path)
1042 sets(integers(), min_size=2, max_size=2),
1043 integers(min_value=0),
1046 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1047 value, bound_min = list(sorted(ints))
1050 bounds = (bound_min, bound_min)
1051 with self.assertRaises(DecodeError) as err:
1053 Integer(value).encode(),
1055 decode_path=decode_path,
1058 self.assertEqual(err.exception.offset, offset)
1059 self.assertEqual(err.exception.decode_path, decode_path)
1061 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1063 integer_values_strategy(),
1065 integers(min_value=1).map(tag_ctxc),
1066 integers(min_value=0),
1069 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1070 for klass in (Integer, IntegerInherited):
1071 _, _, _, _, default, optional, _, _decoded = values
1080 pprint(obj, big_blobs=True, with_decode_path=True)
1081 self.assertFalse(obj.expled)
1082 obj_encoded = obj.encode()
1083 obj_expled = obj(value, expl=tag_expl)
1084 self.assertTrue(obj_expled.expled)
1086 list(obj_expled.pps())
1087 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1088 obj_expled_encoded = obj_expled.encode()
1089 ctx_copied = deepcopy(ctx_dummy)
1090 obj_decoded, tail = obj_expled.decode(
1091 obj_expled_encoded + tail_junk,
1095 self.assertDictEqual(ctx_copied, ctx_dummy)
1097 list(obj_decoded.pps())
1098 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1099 self.assertEqual(tail, tail_junk)
1100 self.assertEqual(obj_decoded, obj_expled)
1101 self.assertNotEqual(obj_decoded, obj)
1102 self.assertEqual(int(obj_decoded), int(obj_expled))
1103 self.assertEqual(int(obj_decoded), int(obj))
1104 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1105 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1106 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1108 obj_decoded.expl_llen,
1109 len(len_encode(len(obj_encoded))),
1111 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1112 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1115 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1117 self.assertEqual(obj_decoded.expl_offset, offset)
1118 assert_exceeding_data(
1120 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1124 def test_go_vectors_valid(self):
1125 for data, expect in ((
1129 (b"\xff\x7f", -129),
1133 (b"\xff\x00", -256),
1137 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1138 (b"\x80\x00\x00\x00", -2147483648),
1141 Integer().decode(b"".join((
1142 Integer.tag_default,
1143 len_encode(len(data)),
1149 def test_go_vectors_invalid(self):
1154 with self.assertRaises(DecodeError):
1155 Integer().decode(b"".join((
1156 Integer.tag_default,
1157 len_encode(len(data)),
1163 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1166 if draw(booleans()):
1167 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1169 integers(min_value=0, max_value=255),
1170 min_size=len(schema),
1171 max_size=len(schema),
1173 schema = list(zip(schema, bits))
1175 def _value(value_required):
1176 if not value_required and draw(booleans()):
1178 generation_choice = 0
1180 generation_choice = draw(sampled_from((1, 2, 3)))
1181 if generation_choice == 1 or draw(booleans()):
1182 return "'%s'B" % "".join(draw(lists(
1183 sampled_from(("0", "1")),
1184 max_size=len(schema),
1186 if generation_choice == 2 or draw(booleans()):
1187 return draw(binary(max_size=len(schema) // 8))
1188 if generation_choice == 3 or draw(booleans()):
1189 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1191 value = _value(value_required)
1192 default = _value(value_required=False)
1196 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1198 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1199 optional = draw(one_of(none(), booleans()))
1201 draw(integers(min_value=0)),
1202 draw(integers(min_value=0)),
1203 draw(integers(min_value=0)),
1205 return (schema, value, impl, expl, default, optional, _decoded)
1208 class BitStringInherited(BitString):
1212 class TestBitString(CommonMixin, TestCase):
1213 base_klass = BitString
1215 @given(lists(booleans()))
1216 def test_b_encoding(self, bits):
1217 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1218 self.assertEqual(obj.bit_len, len(bits))
1219 self.assertSequenceEqual(list(obj), bits)
1220 for i, bit in enumerate(bits):
1221 self.assertEqual(obj[i], bit)
1223 @given(lists(booleans()))
1224 def test_out_of_bounds_bits(self, bits):
1225 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1226 for i in range(len(bits), len(bits) * 2):
1227 self.assertFalse(obj[i])
1229 def test_bad_b_encoding(self):
1230 with self.assertRaises(ValueError):
1231 BitString("'010120101'B")
1234 integers(min_value=1, max_value=255),
1235 integers(min_value=1, max_value=255),
1237 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1238 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1239 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1240 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1242 class BS(BitString):
1243 schema = (("whatever", 0),)
1244 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1245 self.assertEqual(obj.bit_len, leading_zeros + 1)
1246 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1248 def test_zero_len(self):
1249 with self.assertRaises(NotEnoughData):
1250 BitString().decode(b"".join((
1251 BitString.tag_default,
1255 def test_invalid_value_type(self):
1256 with self.assertRaises(InvalidValueType) as err:
1259 with self.assertRaises(InvalidValueType) as err:
1263 def test_obj_unknown(self):
1264 with self.assertRaises(ObjUnknown) as err:
1265 BitString(b"whatever")["whenever"]
1268 def test_get_invalid_type(self):
1269 with self.assertRaises(InvalidValueType) as err:
1270 BitString(b"whatever")[(1, 2, 3)]
1273 @given(data_strategy())
1274 def test_unknown_name(self, d):
1275 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1276 missing = _schema.pop()
1278 class BS(BitString):
1279 schema = [(n, i) for i, n in enumerate(_schema)]
1280 with self.assertRaises(ObjUnknown) as err:
1285 def test_optional(self, optional):
1286 obj = BitString(default=BitString(b""), optional=optional)
1287 self.assertTrue(obj.optional)
1290 def test_ready(self, value):
1292 self.assertFalse(obj.ready)
1295 pprint(obj, big_blobs=True, with_decode_path=True)
1296 with self.assertRaises(ObjNotReady) as err:
1299 obj = BitString(value)
1300 self.assertTrue(obj.ready)
1303 pprint(obj, big_blobs=True, with_decode_path=True)
1306 tuples(integers(min_value=0), binary()),
1307 tuples(integers(min_value=0), binary()),
1311 def test_comparison(self, value1, value2, tag1, tag2):
1312 for klass in (BitString, BitStringInherited):
1313 obj1 = klass(value1)
1314 obj2 = klass(value2)
1315 self.assertEqual(obj1 == obj2, value1 == value2)
1316 self.assertEqual(obj1 != obj2, value1 != value2)
1317 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1318 obj1 = klass(value1, impl=tag1)
1319 obj2 = klass(value1, impl=tag2)
1320 self.assertEqual(obj1 == obj2, tag1 == tag2)
1321 self.assertEqual(obj1 != obj2, tag1 != tag2)
1323 @given(data_strategy())
1324 def test_call(self, d):
1325 for klass in (BitString, BitStringInherited):
1334 ) = d.draw(bit_string_values_strategy())
1337 schema = schema_initial
1339 value=value_initial,
1342 default=default_initial,
1343 optional=optional_initial or False,
1344 _decoded=_decoded_initial,
1354 ) = d.draw(bit_string_values_strategy(
1355 schema=schema_initial,
1356 do_expl=impl_initial is None,
1365 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1366 self.assertEqual(obj.expl_tag, expl or expl_initial)
1367 if obj.default is None:
1368 optional = optional_initial if optional is None else optional
1369 optional = False if optional is None else optional
1372 self.assertEqual(obj.optional, optional)
1373 self.assertEqual(obj.specs, obj_initial.specs)
1375 @given(bit_string_values_strategy())
1376 def test_copy(self, values):
1377 for klass in (BitString, BitStringInherited):
1378 _schema, value, impl, expl, default, optional, _decoded = values
1388 optional=optional or False,
1391 for copy_func in copy_funcs:
1392 obj_copied = copy_func(obj)
1393 self.assert_copied_basic_fields(obj, obj_copied)
1394 self.assertEqual(obj.specs, obj_copied.specs)
1395 self.assertEqual(obj._value, obj_copied._value)
1399 integers(min_value=1).map(tag_encode),
1401 def test_stripped(self, value, tag_impl):
1402 obj = BitString(value, impl=tag_impl)
1403 with self.assertRaises(NotEnoughData):
1404 obj.decode(obj.encode()[:-1])
1408 integers(min_value=1).map(tag_ctxc),
1410 def test_stripped_expl(self, value, tag_expl):
1411 obj = BitString(value, expl=tag_expl)
1412 with self.assertRaises(NotEnoughData):
1413 obj.decode(obj.encode()[:-1])
1416 integers(min_value=31),
1417 integers(min_value=0),
1420 def test_bad_tag(self, tag, offset, decode_path):
1421 with self.assertRaises(DecodeError) as err:
1423 tag_encode(tag)[:-1],
1425 decode_path=decode_path,
1428 self.assertEqual(err.exception.offset, offset)
1429 self.assertEqual(err.exception.decode_path, decode_path)
1432 integers(min_value=128),
1433 integers(min_value=0),
1436 def test_bad_len(self, l, offset, decode_path):
1437 with self.assertRaises(DecodeError) as err:
1439 BitString.tag_default + len_encode(l)[:-1],
1441 decode_path=decode_path,
1444 self.assertEqual(err.exception.offset, offset)
1445 self.assertEqual(err.exception.decode_path, decode_path)
1447 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1448 @given(data_strategy())
1449 def test_symmetric(self, d):
1458 ) = d.draw(bit_string_values_strategy(value_required=True))
1459 tail_junk = d.draw(binary(max_size=5))
1460 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1461 offset = d.draw(integers(min_value=0))
1462 for klass in (BitString, BitStringInherited):
1473 pprint(obj, big_blobs=True, with_decode_path=True)
1474 self.assertFalse(obj.expled)
1475 obj_encoded = obj.encode()
1476 obj_expled = obj(value, expl=tag_expl)
1477 self.assertTrue(obj_expled.expled)
1479 list(obj_expled.pps())
1480 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1481 obj_expled_encoded = obj_expled.encode()
1482 ctx_copied = deepcopy(ctx_dummy)
1483 obj_decoded, tail = obj_expled.decode(
1484 obj_expled_encoded + tail_junk,
1488 self.assertDictEqual(ctx_copied, ctx_dummy)
1490 list(obj_decoded.pps())
1491 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1492 self.assertEqual(tail, tail_junk)
1493 self.assertEqual(obj_decoded, obj_expled)
1494 self.assertNotEqual(obj_decoded, obj)
1495 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1496 self.assertEqual(bytes(obj_decoded), bytes(obj))
1497 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1498 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1499 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1501 obj_decoded.expl_llen,
1502 len(len_encode(len(obj_encoded))),
1504 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1505 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1508 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1510 self.assertEqual(obj_decoded.expl_offset, offset)
1511 if isinstance(value, tuple):
1512 self.assertSetEqual(set(value), set(obj_decoded.named))
1515 assert_exceeding_data(
1517 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1521 @given(integers(min_value=1, max_value=255))
1522 def test_bad_zero_value(self, pad_size):
1523 with self.assertRaises(DecodeError):
1524 BitString().decode(b"".join((
1525 BitString.tag_default,
1530 def test_go_vectors_invalid(self):
1536 with self.assertRaises(DecodeError):
1537 BitString().decode(b"".join((
1538 BitString.tag_default,
1543 def test_go_vectors_valid(self):
1544 obj, _ = BitString().decode(b"".join((
1545 BitString.tag_default,
1549 self.assertEqual(bytes(obj), b"")
1550 self.assertEqual(obj.bit_len, 0)
1552 obj, _ = BitString().decode(b"".join((
1553 BitString.tag_default,
1557 self.assertEqual(bytes(obj), b"\x00")
1558 self.assertEqual(obj.bit_len, 1)
1560 obj = BitString((16, b"\x82\x40"))
1561 self.assertTrue(obj[0])
1562 self.assertFalse(obj[1])
1563 self.assertTrue(obj[6])
1564 self.assertTrue(obj[9])
1565 self.assertFalse(obj[17])
1568 integers(min_value=1, max_value=30),
1571 binary(min_size=1, max_size=5),
1573 binary(min_size=1, max_size=5),
1581 lists(booleans(), min_size=1),
1584 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1585 def chunk_constructed(contents):
1587 tag_encode(form=TagFormConstructed, num=3) +
1589 b"".join(BitString(content).encode() for content in contents) +
1593 payload_expected = b""
1594 bit_len_expected = 0
1595 for chunk_input in chunk_inputs:
1596 if isinstance(chunk_input, binary_type):
1597 chunks.append(BitString(chunk_input).encode())
1598 payload_expected += chunk_input
1599 bit_len_expected += len(chunk_input) * 8
1601 chunks.append(chunk_constructed(chunk_input))
1602 payload = b"".join(chunk_input)
1603 payload_expected += payload
1604 bit_len_expected += len(payload) * 8
1605 chunk_last = BitString("'%s'B" % "".join(
1606 "1" if bit else "0" for bit in chunk_last_bits
1608 payload_expected += bytes(chunk_last)
1609 bit_len_expected += chunk_last.bit_len
1610 encoded_indefinite = (
1611 tag_encode(form=TagFormConstructed, num=impl) +
1614 chunk_last.encode() +
1617 encoded_definite = (
1618 tag_encode(form=TagFormConstructed, num=impl) +
1619 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1623 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1624 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1625 for lenindef_expected, encoded in (
1626 (True, encoded_indefinite),
1627 (False, encoded_definite),
1629 obj, tail = BitString(impl=tag_encode(impl)).decode(
1631 ctx={"bered": True},
1633 self.assertSequenceEqual(tail, junk)
1634 self.assertEqual(obj.bit_len, bit_len_expected)
1635 self.assertSequenceEqual(bytes(obj), payload_expected)
1636 self.assertTrue(obj.ber_encoded)
1637 self.assertEqual(obj.lenindef, lenindef_expected)
1638 self.assertTrue(obj.bered)
1640 self.assertTrue(obj.ber_encoded)
1641 self.assertEqual(obj.lenindef, lenindef_expected)
1642 self.assertTrue(obj.bered)
1643 self.assertEqual(len(encoded), obj.tlvlen)
1646 integers(min_value=0),
1649 def test_ber_definite_too_short(self, offset, decode_path):
1650 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1652 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1654 decode_path=decode_path,
1655 ctx={"bered": True},
1657 self.assertEqual(err.exception.decode_path, decode_path)
1658 self.assertEqual(err.exception.offset, offset)
1661 integers(min_value=0),
1664 def test_ber_definite_no_data(self, offset, decode_path):
1665 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1667 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1669 decode_path=decode_path,
1670 ctx={"bered": True},
1672 self.assertEqual(err.exception.decode_path, decode_path)
1673 self.assertEqual(err.exception.offset, offset)
1676 integers(min_value=0),
1678 integers(min_value=1, max_value=3),
1680 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1681 bs = BitString(b"data").encode()
1682 with self.assertRaises(NotEnoughData) as err:
1684 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1686 decode_path=decode_path,
1687 ctx={"bered": True},
1689 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1690 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1693 integers(min_value=0),
1695 integers(min_value=1, max_value=3),
1697 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1698 bs = BitString(b"data").encode()
1699 bs_longer = BitString(b"data-longer").encode()
1700 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1703 tag_encode(3, form=TagFormConstructed) +
1704 len_encode((chunks + 1) * len(bs)) +
1709 decode_path=decode_path,
1710 ctx={"bered": True},
1712 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1713 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1716 integers(min_value=0),
1719 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1720 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1722 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1724 decode_path=decode_path,
1725 ctx={"bered": True},
1727 self.assertEqual(err.exception.decode_path, decode_path)
1728 self.assertEqual(err.exception.offset, offset)
1730 @given(data_strategy())
1731 def test_ber_indefinite_not_multiple(self, d):
1732 bs_short = BitString("'A'H").encode()
1733 bs_full = BitString("'AA'H").encode()
1734 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1735 chunks.append(bs_short)
1736 d.draw(permutations(chunks))
1737 chunks.append(bs_short)
1738 offset = d.draw(integers(min_value=0))
1739 decode_path = d.draw(decode_path_strat)
1740 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1743 tag_encode(3, form=TagFormConstructed) +
1749 decode_path=decode_path,
1750 ctx={"bered": True},
1753 err.exception.decode_path,
1754 decode_path + (str(chunks.index(bs_short)),),
1757 err.exception.offset,
1758 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1761 def test_x690_vector(self):
1762 vector = BitString("'0A3B5F291CD'H")
1763 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1764 self.assertSequenceEqual(tail, b"")
1765 self.assertEqual(obj, vector)
1766 obj, tail = BitString().decode(
1767 hexdec("23800303000A3B0305045F291CD00000"),
1768 ctx={"bered": True},
1770 self.assertSequenceEqual(tail, b"")
1771 self.assertEqual(obj, vector)
1772 self.assertTrue(obj.ber_encoded)
1773 self.assertTrue(obj.lenindef)
1774 self.assertTrue(obj.bered)
1776 self.assertTrue(obj.ber_encoded)
1777 self.assertTrue(obj.lenindef)
1778 self.assertTrue(obj.bered)
1782 def octet_string_values_strategy(draw, do_expl=False):
1783 bound_min, bound_max = sorted(draw(sets(
1784 integers(min_value=0, max_value=1 << 7),
1788 value = draw(one_of(
1790 binary(min_size=bound_min, max_size=bound_max),
1792 default = draw(one_of(
1794 binary(min_size=bound_min, max_size=bound_max),
1797 if draw(booleans()):
1798 bounds = (bound_min, bound_max)
1802 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1804 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1805 optional = draw(one_of(none(), booleans()))
1807 draw(integers(min_value=0)),
1808 draw(integers(min_value=0)),
1809 draw(integers(min_value=0)),
1811 return (value, bounds, impl, expl, default, optional, _decoded)
1814 class OctetStringInherited(OctetString):
1818 class TestOctetString(CommonMixin, TestCase):
1819 base_klass = OctetString
1821 def test_invalid_value_type(self):
1822 with self.assertRaises(InvalidValueType) as err:
1823 OctetString(text_type(123))
1827 def test_optional(self, optional):
1828 obj = OctetString(default=OctetString(b""), optional=optional)
1829 self.assertTrue(obj.optional)
1832 def test_ready(self, value):
1834 self.assertFalse(obj.ready)
1837 pprint(obj, big_blobs=True, with_decode_path=True)
1838 with self.assertRaises(ObjNotReady) as err:
1841 obj = OctetString(value)
1842 self.assertTrue(obj.ready)
1845 pprint(obj, big_blobs=True, with_decode_path=True)
1847 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1848 def test_comparison(self, value1, value2, tag1, tag2):
1849 for klass in (OctetString, OctetStringInherited):
1850 obj1 = klass(value1)
1851 obj2 = klass(value2)
1852 self.assertEqual(obj1 == obj2, value1 == value2)
1853 self.assertEqual(obj1 != obj2, value1 != value2)
1854 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1855 obj1 = klass(value1, impl=tag1)
1856 obj2 = klass(value1, impl=tag2)
1857 self.assertEqual(obj1 == obj2, tag1 == tag2)
1858 self.assertEqual(obj1 != obj2, tag1 != tag2)
1860 @given(lists(binary()))
1861 def test_sorted_works(self, values):
1862 self.assertSequenceEqual(
1863 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1867 @given(data_strategy())
1868 def test_bounds_satisfied(self, d):
1869 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1870 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1871 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1872 OctetString(value=value, bounds=(bound_min, bound_max))
1874 @given(data_strategy())
1875 def test_bounds_unsatisfied(self, d):
1876 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1877 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1878 value = d.draw(binary(max_size=bound_min - 1))
1879 with self.assertRaises(BoundsError) as err:
1880 OctetString(value=value, bounds=(bound_min, bound_max))
1882 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1883 OctetString(bounds=(bound_min, bound_max)).decode(
1884 OctetString(value).encode()
1887 value = d.draw(binary(min_size=bound_max + 1))
1888 with self.assertRaises(BoundsError) as err:
1889 OctetString(value=value, bounds=(bound_min, bound_max))
1891 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1892 OctetString(bounds=(bound_min, bound_max)).decode(
1893 OctetString(value).encode()
1897 @given(data_strategy())
1898 def test_call(self, d):
1899 for klass in (OctetString, OctetStringInherited):
1908 ) = d.draw(octet_string_values_strategy())
1909 obj_initial = klass(
1915 optional_initial or False,
1926 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1927 if (default is None) and (obj_initial.default is not None):
1930 (bounds is None) and
1931 (value is not None) and
1932 (bounds_initial is not None) and
1933 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1937 (bounds is None) and
1938 (default is not None) and
1939 (bounds_initial is not None) and
1940 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1943 obj = obj_initial(value, bounds, impl, expl, default, optional)
1945 value_expected = default if value is None else value
1947 default_initial if value_expected is None
1950 self.assertEqual(obj, value_expected)
1951 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1952 self.assertEqual(obj.expl_tag, expl or expl_initial)
1955 default_initial if default is None else default,
1957 if obj.default is None:
1958 optional = optional_initial if optional is None else optional
1959 optional = False if optional is None else optional
1962 self.assertEqual(obj.optional, optional)
1964 (obj._bound_min, obj._bound_max),
1965 bounds or bounds_initial or (0, float("+inf")),
1968 @given(octet_string_values_strategy())
1969 def test_copy(self, values):
1970 for klass in (OctetString, OctetStringInherited):
1971 obj = klass(*values)
1972 for copy_func in copy_funcs:
1973 obj_copied = copy_func(obj)
1974 self.assert_copied_basic_fields(obj, obj_copied)
1975 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1976 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1977 self.assertEqual(obj._value, obj_copied._value)
1981 integers(min_value=1).map(tag_encode),
1983 def test_stripped(self, value, tag_impl):
1984 obj = OctetString(value, impl=tag_impl)
1985 with self.assertRaises(NotEnoughData):
1986 obj.decode(obj.encode()[:-1])
1990 integers(min_value=1).map(tag_ctxc),
1992 def test_stripped_expl(self, value, tag_expl):
1993 obj = OctetString(value, expl=tag_expl)
1994 with self.assertRaises(NotEnoughData):
1995 obj.decode(obj.encode()[:-1])
1998 integers(min_value=31),
1999 integers(min_value=0),
2002 def test_bad_tag(self, tag, offset, decode_path):
2003 with self.assertRaises(DecodeError) as err:
2004 OctetString().decode(
2005 tag_encode(tag)[:-1],
2007 decode_path=decode_path,
2010 self.assertEqual(err.exception.offset, offset)
2011 self.assertEqual(err.exception.decode_path, decode_path)
2014 integers(min_value=128),
2015 integers(min_value=0),
2018 def test_bad_len(self, l, offset, decode_path):
2019 with self.assertRaises(DecodeError) as err:
2020 OctetString().decode(
2021 OctetString.tag_default + len_encode(l)[:-1],
2023 decode_path=decode_path,
2026 self.assertEqual(err.exception.offset, offset)
2027 self.assertEqual(err.exception.decode_path, decode_path)
2030 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2031 integers(min_value=0),
2034 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2035 value, bound_min = list(sorted(ints))
2037 class String(OctetString):
2038 bounds = (bound_min, bound_min)
2039 with self.assertRaises(DecodeError) as err:
2041 OctetString(b"\x00" * value).encode(),
2043 decode_path=decode_path,
2046 self.assertEqual(err.exception.offset, offset)
2047 self.assertEqual(err.exception.decode_path, decode_path)
2049 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2051 octet_string_values_strategy(),
2053 integers(min_value=1).map(tag_ctxc),
2054 integers(min_value=0),
2057 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2058 for klass in (OctetString, OctetStringInherited):
2059 _, _, _, _, default, optional, _decoded = values
2068 pprint(obj, big_blobs=True, with_decode_path=True)
2069 self.assertFalse(obj.expled)
2070 obj_encoded = obj.encode()
2071 obj_expled = obj(value, expl=tag_expl)
2072 self.assertTrue(obj_expled.expled)
2074 list(obj_expled.pps())
2075 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2076 obj_expled_encoded = obj_expled.encode()
2077 ctx_copied = deepcopy(ctx_dummy)
2078 obj_decoded, tail = obj_expled.decode(
2079 obj_expled_encoded + tail_junk,
2083 self.assertDictEqual(ctx_copied, ctx_dummy)
2085 list(obj_decoded.pps())
2086 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2087 self.assertEqual(tail, tail_junk)
2088 self.assertEqual(obj_decoded, obj_expled)
2089 self.assertNotEqual(obj_decoded, obj)
2090 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2091 self.assertEqual(bytes(obj_decoded), bytes(obj))
2092 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2093 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2094 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2096 obj_decoded.expl_llen,
2097 len(len_encode(len(obj_encoded))),
2099 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2100 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2103 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2105 self.assertEqual(obj_decoded.expl_offset, offset)
2106 assert_exceeding_data(
2108 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2113 integers(min_value=1, max_value=30),
2116 binary(min_size=1, max_size=5),
2118 binary(min_size=1, max_size=5),
2128 def test_constructed(self, impl, chunk_inputs, junk):
2129 def chunk_constructed(contents):
2131 tag_encode(form=TagFormConstructed, num=4) +
2133 b"".join(OctetString(content).encode() for content in contents) +
2137 payload_expected = b""
2138 for chunk_input in chunk_inputs:
2139 if isinstance(chunk_input, binary_type):
2140 chunks.append(OctetString(chunk_input).encode())
2141 payload_expected += chunk_input
2143 chunks.append(chunk_constructed(chunk_input))
2144 payload = b"".join(chunk_input)
2145 payload_expected += payload
2146 encoded_indefinite = (
2147 tag_encode(form=TagFormConstructed, num=impl) +
2152 encoded_definite = (
2153 tag_encode(form=TagFormConstructed, num=impl) +
2154 len_encode(len(b"".join(chunks))) +
2157 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2158 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2159 for lenindef_expected, encoded in (
2160 (True, encoded_indefinite),
2161 (False, encoded_definite),
2163 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2165 ctx={"bered": True},
2167 self.assertSequenceEqual(tail, junk)
2168 self.assertSequenceEqual(bytes(obj), payload_expected)
2169 self.assertTrue(obj.ber_encoded)
2170 self.assertEqual(obj.lenindef, lenindef_expected)
2171 self.assertTrue(obj.bered)
2173 self.assertTrue(obj.ber_encoded)
2174 self.assertEqual(obj.lenindef, lenindef_expected)
2175 self.assertTrue(obj.bered)
2176 self.assertEqual(len(encoded), obj.tlvlen)
2179 integers(min_value=0),
2182 def test_ber_definite_too_short(self, offset, decode_path):
2183 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2184 OctetString().decode(
2185 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2187 decode_path=decode_path,
2188 ctx={"bered": True},
2190 self.assertEqual(err.exception.decode_path, decode_path)
2191 self.assertEqual(err.exception.offset, offset)
2194 integers(min_value=0),
2196 integers(min_value=1, max_value=3),
2198 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2199 bs = OctetString(b"data").encode()
2200 with self.assertRaises(NotEnoughData) as err:
2201 OctetString().decode(
2202 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2204 decode_path=decode_path,
2205 ctx={"bered": True},
2207 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2208 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2211 integers(min_value=0),
2213 integers(min_value=1, max_value=3),
2215 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2216 bs = OctetString(b"data").encode()
2217 bs_longer = OctetString(b"data-longer").encode()
2218 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2219 OctetString().decode(
2221 tag_encode(4, form=TagFormConstructed) +
2222 len_encode((chunks + 1) * len(bs)) +
2227 decode_path=decode_path,
2228 ctx={"bered": True},
2230 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2231 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2235 def null_values_strategy(draw, do_expl=False):
2239 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2241 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2242 optional = draw(one_of(none(), booleans()))
2244 draw(integers(min_value=0)),
2245 draw(integers(min_value=0)),
2246 draw(integers(min_value=0)),
2248 return (impl, expl, optional, _decoded)
2251 class NullInherited(Null):
2255 class TestNull(CommonMixin, TestCase):
2258 def test_ready(self):
2260 self.assertTrue(obj.ready)
2263 pprint(obj, big_blobs=True, with_decode_path=True)
2265 @given(binary(), binary())
2266 def test_comparison(self, tag1, tag2):
2267 for klass in (Null, NullInherited):
2268 obj1 = klass(impl=tag1)
2269 obj2 = klass(impl=tag2)
2270 self.assertEqual(obj1 == obj2, tag1 == tag2)
2271 self.assertEqual(obj1 != obj2, tag1 != tag2)
2272 self.assertNotEqual(obj1, tag2)
2274 @given(data_strategy())
2275 def test_call(self, d):
2276 for klass in (Null, NullInherited):
2282 ) = d.draw(null_values_strategy())
2283 obj_initial = klass(
2286 optional=optional_initial or False,
2287 _decoded=_decoded_initial,
2294 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2295 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2296 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2297 self.assertEqual(obj.expl_tag, expl or expl_initial)
2298 optional = optional_initial if optional is None else optional
2299 optional = False if optional is None else optional
2300 self.assertEqual(obj.optional, optional)
2302 @given(null_values_strategy())
2303 def test_copy(self, values):
2304 for klass in (Null, NullInherited):
2305 impl, expl, optional, _decoded = values
2309 optional=optional or False,
2312 for copy_func in copy_funcs:
2313 obj_copied = copy_func(obj)
2314 self.assert_copied_basic_fields(obj, obj_copied)
2316 @given(integers(min_value=1).map(tag_encode))
2317 def test_stripped(self, tag_impl):
2318 obj = Null(impl=tag_impl)
2319 with self.assertRaises(NotEnoughData):
2320 obj.decode(obj.encode()[:-1])
2322 @given(integers(min_value=1).map(tag_ctxc))
2323 def test_stripped_expl(self, tag_expl):
2324 obj = Null(expl=tag_expl)
2325 with self.assertRaises(NotEnoughData):
2326 obj.decode(obj.encode()[:-1])
2329 integers(min_value=31),
2330 integers(min_value=0),
2333 def test_bad_tag(self, tag, offset, decode_path):
2334 with self.assertRaises(DecodeError) as err:
2336 tag_encode(tag)[:-1],
2338 decode_path=decode_path,
2341 self.assertEqual(err.exception.offset, offset)
2342 self.assertEqual(err.exception.decode_path, decode_path)
2345 integers(min_value=128),
2346 integers(min_value=0),
2349 def test_bad_len(self, l, offset, decode_path):
2350 with self.assertRaises(DecodeError) as err:
2352 Null.tag_default + len_encode(l)[:-1],
2354 decode_path=decode_path,
2357 self.assertEqual(err.exception.offset, offset)
2358 self.assertEqual(err.exception.decode_path, decode_path)
2360 @given(binary(min_size=1))
2361 def test_tag_mismatch(self, impl):
2362 assume(impl != Null.tag_default)
2363 with self.assertRaises(TagMismatch):
2364 Null(impl=impl).decode(Null().encode())
2367 null_values_strategy(),
2368 integers(min_value=1).map(tag_ctxc),
2369 integers(min_value=0),
2372 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2373 for klass in (Null, NullInherited):
2374 _, _, optional, _decoded = values
2375 obj = klass(optional=optional, _decoded=_decoded)
2378 pprint(obj, big_blobs=True, with_decode_path=True)
2379 self.assertFalse(obj.expled)
2380 obj_encoded = obj.encode()
2381 obj_expled = obj(expl=tag_expl)
2382 self.assertTrue(obj_expled.expled)
2384 list(obj_expled.pps())
2385 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2386 obj_expled_encoded = obj_expled.encode()
2387 ctx_copied = deepcopy(ctx_dummy)
2388 obj_decoded, tail = obj_expled.decode(
2389 obj_expled_encoded + tail_junk,
2393 self.assertDictEqual(ctx_copied, ctx_dummy)
2395 list(obj_decoded.pps())
2396 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2397 self.assertEqual(tail, tail_junk)
2398 self.assertEqual(obj_decoded, obj_expled)
2399 self.assertNotEqual(obj_decoded, obj)
2400 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2401 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2402 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2404 obj_decoded.expl_llen,
2405 len(len_encode(len(obj_encoded))),
2407 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2408 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2411 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2413 self.assertEqual(obj_decoded.expl_offset, offset)
2414 assert_exceeding_data(
2416 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2420 @given(integers(min_value=1))
2421 def test_invalid_len(self, l):
2422 with self.assertRaises(InvalidLength):
2423 Null().decode(b"".join((
2430 def oid_strategy(draw):
2431 first_arc = draw(integers(min_value=0, max_value=2))
2433 if first_arc in (0, 1):
2434 second_arc = draw(integers(min_value=0, max_value=39))
2436 second_arc = draw(integers(min_value=0))
2437 other_arcs = draw(lists(integers(min_value=0)))
2438 return tuple([first_arc, second_arc] + other_arcs)
2442 def oid_values_strategy(draw, do_expl=False):
2443 value = draw(one_of(none(), oid_strategy()))
2447 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2449 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2450 default = draw(one_of(none(), oid_strategy()))
2451 optional = draw(one_of(none(), booleans()))
2453 draw(integers(min_value=0)),
2454 draw(integers(min_value=0)),
2455 draw(integers(min_value=0)),
2457 return (value, impl, expl, default, optional, _decoded)
2460 class ObjectIdentifierInherited(ObjectIdentifier):
2464 class TestObjectIdentifier(CommonMixin, TestCase):
2465 base_klass = ObjectIdentifier
2467 def test_invalid_value_type(self):
2468 with self.assertRaises(InvalidValueType) as err:
2469 ObjectIdentifier(123)
2473 def test_optional(self, optional):
2474 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2475 self.assertTrue(obj.optional)
2477 @given(oid_strategy())
2478 def test_ready(self, value):
2479 obj = ObjectIdentifier()
2480 self.assertFalse(obj.ready)
2483 pprint(obj, big_blobs=True, with_decode_path=True)
2484 with self.assertRaises(ObjNotReady) as err:
2487 obj = ObjectIdentifier(value)
2488 self.assertTrue(obj.ready)
2489 self.assertFalse(obj.ber_encoded)
2492 pprint(obj, big_blobs=True, with_decode_path=True)
2495 @given(oid_strategy(), oid_strategy(), binary(), binary())
2496 def test_comparison(self, value1, value2, tag1, tag2):
2497 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2498 obj1 = klass(value1)
2499 obj2 = klass(value2)
2500 self.assertEqual(obj1 == obj2, value1 == value2)
2501 self.assertEqual(obj1 != obj2, value1 != value2)
2502 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2503 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2504 obj1 = klass(value1, impl=tag1)
2505 obj2 = klass(value1, impl=tag2)
2506 self.assertEqual(obj1 == obj2, tag1 == tag2)
2507 self.assertEqual(obj1 != obj2, tag1 != tag2)
2509 @given(lists(oid_strategy()))
2510 def test_sorted_works(self, values):
2511 self.assertSequenceEqual(
2512 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2516 @given(data_strategy())
2517 def test_call(self, d):
2518 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2526 ) = d.draw(oid_values_strategy())
2527 obj_initial = klass(
2528 value=value_initial,
2531 default=default_initial,
2532 optional=optional_initial or False,
2533 _decoded=_decoded_initial,
2542 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2551 value_expected = default if value is None else value
2553 default_initial if value_expected is None
2556 self.assertEqual(obj, value_expected)
2557 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2558 self.assertEqual(obj.expl_tag, expl or expl_initial)
2561 default_initial if default is None else default,
2563 if obj.default is None:
2564 optional = optional_initial if optional is None else optional
2565 optional = False if optional is None else optional
2568 self.assertEqual(obj.optional, optional)
2570 @given(oid_values_strategy())
2571 def test_copy(self, values):
2572 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2589 for copy_func in copy_funcs:
2590 obj_copied = copy_func(obj)
2591 self.assert_copied_basic_fields(obj, obj_copied)
2592 self.assertEqual(obj._value, obj_copied._value)
2594 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2597 integers(min_value=1).map(tag_encode),
2599 def test_stripped(self, value, tag_impl):
2600 obj = ObjectIdentifier(value, impl=tag_impl)
2601 with self.assertRaises(NotEnoughData):
2602 obj.decode(obj.encode()[:-1])
2606 integers(min_value=1).map(tag_ctxc),
2608 def test_stripped_expl(self, value, tag_expl):
2609 obj = ObjectIdentifier(value, expl=tag_expl)
2610 with self.assertRaises(NotEnoughData):
2611 obj.decode(obj.encode()[:-1])
2614 integers(min_value=31),
2615 integers(min_value=0),
2618 def test_bad_tag(self, tag, offset, decode_path):
2619 with self.assertRaises(DecodeError) as err:
2620 ObjectIdentifier().decode(
2621 tag_encode(tag)[:-1],
2623 decode_path=decode_path,
2626 self.assertEqual(err.exception.offset, offset)
2627 self.assertEqual(err.exception.decode_path, decode_path)
2630 integers(min_value=128),
2631 integers(min_value=0),
2634 def test_bad_len(self, l, offset, decode_path):
2635 with self.assertRaises(DecodeError) as err:
2636 ObjectIdentifier().decode(
2637 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2639 decode_path=decode_path,
2642 self.assertEqual(err.exception.offset, offset)
2643 self.assertEqual(err.exception.decode_path, decode_path)
2645 def test_zero_oid(self):
2646 with self.assertRaises(NotEnoughData):
2647 ObjectIdentifier().decode(
2648 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2651 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2652 @given(oid_strategy())
2653 def test_unfinished_oid(self, value):
2654 assume(list(value)[-1] > 255)
2655 obj_encoded = ObjectIdentifier(value).encode()
2656 obj, _ = ObjectIdentifier().decode(obj_encoded)
2657 data = obj_encoded[obj.tlen + obj.llen:-1]
2659 ObjectIdentifier.tag_default,
2660 len_encode(len(data)),
2663 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2666 @given(integers(min_value=0))
2667 def test_invalid_short(self, value):
2668 with self.assertRaises(InvalidOID):
2669 ObjectIdentifier((value,))
2670 with self.assertRaises(InvalidOID):
2671 ObjectIdentifier("%d" % value)
2673 @given(integers(min_value=3), integers(min_value=0))
2674 def test_invalid_first_arc(self, first_arc, second_arc):
2675 with self.assertRaises(InvalidOID):
2676 ObjectIdentifier((first_arc, second_arc))
2677 with self.assertRaises(InvalidOID):
2678 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2680 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2681 def test_invalid_second_arc(self, first_arc, second_arc):
2682 with self.assertRaises(InvalidOID):
2683 ObjectIdentifier((first_arc, second_arc))
2684 with self.assertRaises(InvalidOID):
2685 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2687 @given(text(alphabet=ascii_letters + ".", min_size=1))
2688 def test_junk(self, oid):
2689 with self.assertRaises(InvalidOID):
2690 ObjectIdentifier(oid)
2692 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2693 @given(oid_strategy())
2694 def test_validness(self, oid):
2695 obj = ObjectIdentifier(oid)
2696 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2699 pprint(obj, big_blobs=True, with_decode_path=True)
2701 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2703 oid_values_strategy(),
2705 integers(min_value=1).map(tag_ctxc),
2706 integers(min_value=0),
2709 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2710 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2711 _, _, _, default, optional, _decoded = values
2720 pprint(obj, big_blobs=True, with_decode_path=True)
2721 self.assertFalse(obj.expled)
2722 obj_encoded = obj.encode()
2723 obj_expled = obj(value, expl=tag_expl)
2724 self.assertTrue(obj_expled.expled)
2726 list(obj_expled.pps())
2727 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2728 obj_expled_encoded = obj_expled.encode()
2729 ctx_copied = deepcopy(ctx_dummy)
2730 obj_decoded, tail = obj_expled.decode(
2731 obj_expled_encoded + tail_junk,
2735 self.assertDictEqual(ctx_copied, ctx_dummy)
2737 list(obj_decoded.pps())
2738 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2739 self.assertEqual(tail, tail_junk)
2740 self.assertEqual(obj_decoded, obj_expled)
2741 self.assertNotEqual(obj_decoded, obj)
2742 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2743 self.assertEqual(tuple(obj_decoded), tuple(obj))
2744 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2745 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2746 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2748 obj_decoded.expl_llen,
2749 len(len_encode(len(obj_encoded))),
2751 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2752 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2755 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2757 self.assertEqual(obj_decoded.expl_offset, offset)
2758 assert_exceeding_data(
2760 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2765 oid_strategy().map(ObjectIdentifier),
2766 oid_strategy().map(ObjectIdentifier),
2768 def test_add(self, oid1, oid2):
2769 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2770 for oid_to_add in (oid2, tuple(oid2)):
2771 self.assertEqual(oid1 + oid_to_add, oid_expect)
2772 with self.assertRaises(InvalidValueType):
2775 def test_go_vectors_valid(self):
2776 for data, expect in (
2778 (b"\x55\x02", (2, 5, 2)),
2779 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2780 (b"\x81\x34\x03", (2, 100, 3)),
2783 ObjectIdentifier().decode(b"".join((
2784 ObjectIdentifier.tag_default,
2785 len_encode(len(data)),
2791 def test_go_vectors_invalid(self):
2792 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2793 with self.assertRaises(DecodeError):
2794 ObjectIdentifier().decode(b"".join((
2795 Integer.tag_default,
2796 len_encode(len(data)),
2800 def test_x690_vector(self):
2802 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2803 ObjectIdentifier((2, 999, 3)),
2806 def test_nonnormalized_first_arc(self):
2808 ObjectIdentifier.tag_default +
2811 ObjectIdentifier((1, 0)).encode()[-1:]
2813 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2814 self.assertTrue(obj.ber_encoded)
2815 self.assertTrue(obj.bered)
2817 self.assertTrue(obj.ber_encoded)
2818 self.assertTrue(obj.bered)
2819 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2820 ObjectIdentifier().decode(tampered)
2822 @given(data_strategy())
2823 def test_nonnormalized_arcs(self, d):
2824 arcs = d.draw(lists(
2825 integers(min_value=0, max_value=100),
2829 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2830 _, _, lv = tag_strip(dered)
2831 _, _, v = len_decode(lv)
2832 v_no_first_arc = v[1:]
2833 idx_for_tamper = d.draw(integers(
2835 max_value=len(v_no_first_arc) - 1,
2837 tampered = list(bytearray(v_no_first_arc))
2838 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2839 tampered.insert(idx_for_tamper, 0x80)
2840 tampered = bytes(bytearray(tampered))
2842 ObjectIdentifier.tag_default +
2843 len_encode(len(tampered)) +
2846 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2847 self.assertTrue(obj.ber_encoded)
2848 self.assertTrue(obj.bered)
2850 self.assertTrue(obj.ber_encoded)
2851 self.assertTrue(obj.bered)
2852 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2853 ObjectIdentifier().decode(tampered)
2857 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2859 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2860 values = list(draw(sets(
2862 min_size=len(schema),
2863 max_size=len(schema),
2865 schema = list(zip(schema, values))
2866 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2870 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2872 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2873 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2874 optional = draw(one_of(none(), booleans()))
2876 draw(integers(min_value=0)),
2877 draw(integers(min_value=0)),
2878 draw(integers(min_value=0)),
2880 return (schema, value, impl, expl, default, optional, _decoded)
2883 class TestEnumerated(CommonMixin, TestCase):
2884 class EWhatever(Enumerated):
2885 schema = (("whatever", 0),)
2887 base_klass = EWhatever
2889 def test_schema_required(self):
2890 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2893 def test_invalid_value_type(self):
2894 with self.assertRaises(InvalidValueType) as err:
2895 self.base_klass((1, 2))
2898 @given(sets(text_letters(), min_size=2))
2899 def test_unknown_name(self, schema_input):
2900 missing = schema_input.pop()
2902 class E(Enumerated):
2903 schema = [(n, 123) for n in schema_input]
2904 with self.assertRaises(ObjUnknown) as err:
2909 sets(text_letters(), min_size=2),
2910 sets(integers(), min_size=2),
2912 def test_unknown_value(self, schema_input, values_input):
2914 missing_value = values_input.pop()
2915 _input = list(zip(schema_input, values_input))
2917 class E(Enumerated):
2919 with self.assertRaises(DecodeError) as err:
2924 def test_optional(self, optional):
2925 obj = self.base_klass(default="whatever", optional=optional)
2926 self.assertTrue(obj.optional)
2928 def test_ready(self):
2929 obj = self.base_klass()
2930 self.assertFalse(obj.ready)
2933 pprint(obj, big_blobs=True, with_decode_path=True)
2934 with self.assertRaises(ObjNotReady) as err:
2937 obj = self.base_klass("whatever")
2938 self.assertTrue(obj.ready)
2941 pprint(obj, big_blobs=True, with_decode_path=True)
2943 @given(integers(), integers(), binary(), binary())
2944 def test_comparison(self, value1, value2, tag1, tag2):
2945 class E(Enumerated):
2947 ("whatever0", value1),
2948 ("whatever1", value2),
2951 class EInherited(E):
2953 for klass in (E, EInherited):
2954 obj1 = klass(value1)
2955 obj2 = klass(value2)
2956 self.assertEqual(obj1 == obj2, value1 == value2)
2957 self.assertEqual(obj1 != obj2, value1 != value2)
2958 self.assertEqual(obj1 == int(obj2), value1 == value2)
2959 obj1 = klass(value1, impl=tag1)
2960 obj2 = klass(value1, impl=tag2)
2961 self.assertEqual(obj1 == obj2, tag1 == tag2)
2962 self.assertEqual(obj1 != obj2, tag1 != tag2)
2964 @given(data_strategy())
2965 def test_call(self, d):
2974 ) = d.draw(enumerated_values_strategy())
2976 class E(Enumerated):
2977 schema = schema_initial
2979 value=value_initial,
2982 default=default_initial,
2983 optional=optional_initial or False,
2984 _decoded=_decoded_initial,
2994 ) = d.draw(enumerated_values_strategy(
2995 schema=schema_initial,
2996 do_expl=impl_initial is None,
3006 value_expected = default if value is None else value
3008 default_initial if value_expected is None
3013 dict(schema_initial).get(value_expected, value_expected),
3015 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3016 self.assertEqual(obj.expl_tag, expl or expl_initial)
3019 default_initial if default is None else default,
3021 if obj.default is None:
3022 optional = optional_initial if optional is None else optional
3023 optional = False if optional is None else optional
3026 self.assertEqual(obj.optional, optional)
3027 self.assertEqual(obj.specs, dict(schema_initial))
3029 @given(enumerated_values_strategy())
3030 def test_copy(self, values):
3031 schema_input, value, impl, expl, default, optional, _decoded = values
3033 class E(Enumerated):
3034 schema = schema_input
3044 for copy_func in copy_funcs:
3045 obj_copied = copy_func(obj)
3046 self.assert_copied_basic_fields(obj, obj_copied)
3047 self.assertEqual(obj.specs, obj_copied.specs)
3049 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3050 @given(data_strategy())
3051 def test_symmetric(self, d):
3052 schema_input, _, _, _, default, optional, _decoded = d.draw(
3053 enumerated_values_strategy(),
3055 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3056 offset = d.draw(integers(min_value=0))
3057 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3058 tail_junk = d.draw(binary(max_size=5))
3060 class E(Enumerated):
3061 schema = schema_input
3070 pprint(obj, big_blobs=True, with_decode_path=True)
3071 self.assertFalse(obj.expled)
3072 obj_encoded = obj.encode()
3073 obj_expled = obj(value, expl=tag_expl)
3074 self.assertTrue(obj_expled.expled)
3076 list(obj_expled.pps())
3077 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3078 obj_expled_encoded = obj_expled.encode()
3079 ctx_copied = deepcopy(ctx_dummy)
3080 obj_decoded, tail = obj_expled.decode(
3081 obj_expled_encoded + tail_junk,
3085 self.assertDictEqual(ctx_copied, ctx_dummy)
3087 list(obj_decoded.pps())
3088 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3089 self.assertEqual(tail, tail_junk)
3090 self.assertEqual(obj_decoded, obj_expled)
3091 self.assertNotEqual(obj_decoded, obj)
3092 self.assertEqual(int(obj_decoded), int(obj_expled))
3093 self.assertEqual(int(obj_decoded), int(obj))
3094 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3095 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3096 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3098 obj_decoded.expl_llen,
3099 len(len_encode(len(obj_encoded))),
3101 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3102 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3105 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3107 self.assertEqual(obj_decoded.expl_offset, offset)
3108 assert_exceeding_data(
3110 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3116 def string_values_strategy(draw, alphabet, do_expl=False):
3117 bound_min, bound_max = sorted(draw(sets(
3118 integers(min_value=0, max_value=1 << 7),
3122 value = draw(one_of(
3124 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3126 default = draw(one_of(
3128 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3131 if draw(booleans()):
3132 bounds = (bound_min, bound_max)
3136 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3138 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3139 optional = draw(one_of(none(), booleans()))
3141 draw(integers(min_value=0)),
3142 draw(integers(min_value=0)),
3143 draw(integers(min_value=0)),
3145 return (value, bounds, impl, expl, default, optional, _decoded)
3148 class StringMixin(object):
3149 def test_invalid_value_type(self):
3150 with self.assertRaises(InvalidValueType) as err:
3151 self.base_klass((1, 2))
3154 def text_alphabet(self):
3155 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3156 return printable + whitespace
3160 def test_optional(self, optional):
3161 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3162 self.assertTrue(obj.optional)
3164 @given(data_strategy())
3165 def test_ready(self, d):
3166 obj = self.base_klass()
3167 self.assertFalse(obj.ready)
3170 pprint(obj, big_blobs=True, with_decode_path=True)
3172 with self.assertRaises(ObjNotReady) as err:
3175 value = d.draw(text(alphabet=self.text_alphabet()))
3176 obj = self.base_klass(value)
3177 self.assertTrue(obj.ready)
3180 pprint(obj, big_blobs=True, with_decode_path=True)
3183 @given(data_strategy())
3184 def test_comparison(self, d):
3185 value1 = d.draw(text(alphabet=self.text_alphabet()))
3186 value2 = d.draw(text(alphabet=self.text_alphabet()))
3187 tag1 = d.draw(binary(min_size=1))
3188 tag2 = d.draw(binary(min_size=1))
3189 obj1 = self.base_klass(value1)
3190 obj2 = self.base_klass(value2)
3191 self.assertEqual(obj1 == obj2, value1 == value2)
3192 self.assertEqual(obj1 != obj2, value1 != value2)
3193 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3194 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3195 obj1 = self.base_klass(value1, impl=tag1)
3196 obj2 = self.base_klass(value1, impl=tag2)
3197 self.assertEqual(obj1 == obj2, tag1 == tag2)
3198 self.assertEqual(obj1 != obj2, tag1 != tag2)
3200 @given(data_strategy())
3201 def test_bounds_satisfied(self, d):
3202 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3203 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3204 value = d.draw(text(
3205 alphabet=self.text_alphabet(),
3209 self.base_klass(value=value, bounds=(bound_min, bound_max))
3211 @given(data_strategy())
3212 def test_bounds_unsatisfied(self, d):
3213 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3214 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3215 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3216 with self.assertRaises(BoundsError) as err:
3217 self.base_klass(value=value, bounds=(bound_min, bound_max))
3219 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3220 self.base_klass(bounds=(bound_min, bound_max)).decode(
3221 self.base_klass(value).encode()
3224 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3225 with self.assertRaises(BoundsError) as err:
3226 self.base_klass(value=value, bounds=(bound_min, bound_max))
3228 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3229 self.base_klass(bounds=(bound_min, bound_max)).decode(
3230 self.base_klass(value).encode()
3234 @given(data_strategy())
3235 def test_call(self, d):
3244 ) = d.draw(string_values_strategy(self.text_alphabet()))
3245 obj_initial = self.base_klass(
3251 optional_initial or False,
3262 ) = d.draw(string_values_strategy(
3263 self.text_alphabet(),
3264 do_expl=impl_initial is None,
3266 if (default is None) and (obj_initial.default is not None):
3269 (bounds is None) and
3270 (value is not None) and
3271 (bounds_initial is not None) and
3272 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3276 (bounds is None) and
3277 (default is not None) and
3278 (bounds_initial is not None) and
3279 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3282 obj = obj_initial(value, bounds, impl, expl, default, optional)
3284 value_expected = default if value is None else value
3286 default_initial if value_expected is None
3289 self.assertEqual(obj, value_expected)
3290 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3291 self.assertEqual(obj.expl_tag, expl or expl_initial)
3294 default_initial if default is None else default,
3296 if obj.default is None:
3297 optional = optional_initial if optional is None else optional
3298 optional = False if optional is None else optional
3301 self.assertEqual(obj.optional, optional)
3303 (obj._bound_min, obj._bound_max),
3304 bounds or bounds_initial or (0, float("+inf")),
3307 @given(data_strategy())
3308 def test_copy(self, d):
3309 values = d.draw(string_values_strategy(self.text_alphabet()))
3310 obj = self.base_klass(*values)
3311 for copy_func in copy_funcs:
3312 obj_copied = copy_func(obj)
3313 self.assert_copied_basic_fields(obj, obj_copied)
3314 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3315 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3316 self.assertEqual(obj._value, obj_copied._value)
3318 @given(data_strategy())
3319 def test_stripped(self, d):
3320 value = d.draw(text(alphabet=self.text_alphabet()))
3321 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3322 obj = self.base_klass(value, impl=tag_impl)
3323 with self.assertRaises(NotEnoughData):
3324 obj.decode(obj.encode()[:-1])
3326 @given(data_strategy())
3327 def test_stripped_expl(self, d):
3328 value = d.draw(text(alphabet=self.text_alphabet()))
3329 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3330 obj = self.base_klass(value, expl=tag_expl)
3331 with self.assertRaises(NotEnoughData):
3332 obj.decode(obj.encode()[:-1])
3335 integers(min_value=31),
3336 integers(min_value=0),
3339 def test_bad_tag(self, tag, offset, decode_path):
3340 with self.assertRaises(DecodeError) as err:
3341 self.base_klass().decode(
3342 tag_encode(tag)[:-1],
3344 decode_path=decode_path,
3347 self.assertEqual(err.exception.offset, offset)
3348 self.assertEqual(err.exception.decode_path, decode_path)
3351 integers(min_value=128),
3352 integers(min_value=0),
3355 def test_bad_len(self, l, offset, decode_path):
3356 with self.assertRaises(DecodeError) as err:
3357 self.base_klass().decode(
3358 self.base_klass.tag_default + len_encode(l)[:-1],
3360 decode_path=decode_path,
3363 self.assertEqual(err.exception.offset, offset)
3364 self.assertEqual(err.exception.decode_path, decode_path)
3367 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3368 integers(min_value=0),
3371 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3372 value, bound_min = list(sorted(ints))
3374 class String(self.base_klass):
3375 # Multiply this value by four, to satisfy UTF-32 bounds
3376 # (4 bytes per character) validation
3377 bounds = (bound_min * 4, bound_min * 4)
3378 with self.assertRaises(DecodeError) as err:
3380 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3382 decode_path=decode_path,
3385 self.assertEqual(err.exception.offset, offset)
3386 self.assertEqual(err.exception.decode_path, decode_path)
3388 @given(data_strategy())
3389 def test_symmetric(self, d):
3390 values = d.draw(string_values_strategy(self.text_alphabet()))
3391 value = d.draw(text(alphabet=self.text_alphabet()))
3392 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3393 offset = d.draw(integers(min_value=0))
3394 tail_junk = d.draw(binary(max_size=5))
3395 _, _, _, _, default, optional, _decoded = values
3396 obj = self.base_klass(
3404 pprint(obj, big_blobs=True, with_decode_path=True)
3405 self.assertFalse(obj.expled)
3406 obj_encoded = obj.encode()
3407 obj_expled = obj(value, expl=tag_expl)
3408 self.assertTrue(obj_expled.expled)
3410 list(obj_expled.pps())
3411 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3412 obj_expled_encoded = obj_expled.encode()
3413 ctx_copied = deepcopy(ctx_dummy)
3414 obj_decoded, tail = obj_expled.decode(
3415 obj_expled_encoded + tail_junk,
3419 self.assertDictEqual(ctx_copied, ctx_dummy)
3421 list(obj_decoded.pps())
3422 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3423 self.assertEqual(tail, tail_junk)
3424 self.assertEqual(obj_decoded, obj_expled)
3425 self.assertNotEqual(obj_decoded, obj)
3426 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3427 self.assertEqual(bytes(obj_decoded), bytes(obj))
3428 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3429 self.assertEqual(text_type(obj_decoded), text_type(obj))
3430 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3431 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3432 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3434 obj_decoded.expl_llen,
3435 len(len_encode(len(obj_encoded))),
3437 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3438 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3441 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3443 self.assertEqual(obj_decoded.expl_offset, offset)
3444 assert_exceeding_data(
3446 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3451 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3452 base_klass = UTF8String
3455 cyrillic_letters = text(
3456 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3462 class UnicodeDecodeErrorMixin(object):
3463 @given(cyrillic_letters)
3464 def test_unicode_decode_error(self, cyrillic_text):
3465 with self.assertRaises(DecodeError):
3466 self.base_klass(cyrillic_text)
3469 class TestNumericString(StringMixin, CommonMixin, TestCase):
3470 base_klass = NumericString
3472 def text_alphabet(self):
3475 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3476 def test_non_numeric(self, non_numeric_text):
3477 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3478 self.base_klass(non_numeric_text)
3481 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3482 integers(min_value=0),
3485 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3486 value, bound_min = list(sorted(ints))
3488 class String(self.base_klass):
3489 bounds = (bound_min, bound_min)
3490 with self.assertRaises(DecodeError) as err:
3492 self.base_klass(b"1" * value).encode(),
3494 decode_path=decode_path,
3497 self.assertEqual(err.exception.offset, offset)
3498 self.assertEqual(err.exception.decode_path, decode_path)
3501 class TestPrintableString(
3502 UnicodeDecodeErrorMixin,
3507 base_klass = PrintableString
3509 def text_alphabet(self):
3510 return ascii_letters + digits + " '()+,-./:=?"
3512 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3513 def test_non_printable(self, non_printable_text):
3514 with assertRaisesRegex(self, DecodeError, "non-printable"):
3515 self.base_klass(non_printable_text)
3518 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3519 integers(min_value=0),
3522 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3523 value, bound_min = list(sorted(ints))
3525 class String(self.base_klass):
3526 bounds = (bound_min, bound_min)
3527 with self.assertRaises(DecodeError) as err:
3529 self.base_klass(b"1" * value).encode(),
3531 decode_path=decode_path,
3534 self.assertEqual(err.exception.offset, offset)
3535 self.assertEqual(err.exception.decode_path, decode_path)
3537 def test_allowable_invalid_chars(self):
3539 ("*", {"allow_asterisk": True}),
3540 ("&", {"allow_ampersand": True}),
3541 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3544 obj = self.base_klass(s)
3545 for prop in kwargs.keys():
3546 self.assertFalse(getattr(obj, prop))
3548 with assertRaisesRegex(self, DecodeError, "non-printable"):
3550 self.base_klass(s, **kwargs)
3551 klass = self.base_klass(**kwargs)
3553 for prop in kwargs.keys():
3554 self.assertTrue(getattr(obj, prop))
3557 for prop in kwargs.keys():
3558 self.assertTrue(getattr(obj, prop))
3561 class TestTeletexString(
3562 UnicodeDecodeErrorMixin,
3567 base_klass = TeletexString
3570 class TestVideotexString(
3571 UnicodeDecodeErrorMixin,
3576 base_klass = VideotexString
3579 class TestIA5String(
3580 UnicodeDecodeErrorMixin,
3585 base_klass = IA5String
3588 class TestGraphicString(
3589 UnicodeDecodeErrorMixin,
3594 base_klass = GraphicString
3597 class TestVisibleString(
3598 UnicodeDecodeErrorMixin,
3603 base_klass = VisibleString
3605 def test_x690_vector(self):
3606 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3607 self.assertSequenceEqual(tail, b"")
3608 self.assertEqual(str(obj), "Jones")
3609 self.assertFalse(obj.ber_encoded)
3610 self.assertFalse(obj.lenindef)
3611 self.assertFalse(obj.bered)
3613 obj, tail = VisibleString().decode(
3614 hexdec("3A0904034A6F6E04026573"),
3615 ctx={"bered": True},
3617 self.assertSequenceEqual(tail, b"")
3618 self.assertEqual(str(obj), "Jones")
3619 self.assertTrue(obj.ber_encoded)
3620 self.assertFalse(obj.lenindef)
3621 self.assertTrue(obj.bered)
3623 self.assertTrue(obj.ber_encoded)
3624 self.assertFalse(obj.lenindef)
3625 self.assertTrue(obj.bered)
3627 obj, tail = VisibleString().decode(
3628 hexdec("3A8004034A6F6E040265730000"),
3629 ctx={"bered": True},
3631 self.assertSequenceEqual(tail, b"")
3632 self.assertEqual(str(obj), "Jones")
3633 self.assertTrue(obj.ber_encoded)
3634 self.assertTrue(obj.lenindef)
3635 self.assertTrue(obj.bered)
3637 self.assertTrue(obj.ber_encoded)
3638 self.assertTrue(obj.lenindef)
3639 self.assertTrue(obj.bered)
3642 class TestGeneralString(
3643 UnicodeDecodeErrorMixin,
3648 base_klass = GeneralString
3651 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3652 base_klass = UniversalString
3655 class TestBMPString(StringMixin, CommonMixin, TestCase):
3656 base_klass = BMPString
3660 def generalized_time_values_strategy(
3668 if draw(booleans()):
3669 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3671 value = value.replace(microsecond=0)
3673 if draw(booleans()):
3674 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3676 default = default.replace(microsecond=0)
3680 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3682 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3683 optional = draw(one_of(none(), booleans()))
3685 draw(integers(min_value=0)),
3686 draw(integers(min_value=0)),
3687 draw(integers(min_value=0)),
3689 return (value, impl, expl, default, optional, _decoded)
3692 class TimeMixin(object):
3693 def test_invalid_value_type(self):
3694 with self.assertRaises(InvalidValueType) as err:
3695 self.base_klass(datetime.now().timetuple())
3698 @given(data_strategy())
3699 def test_optional(self, d):
3700 default = d.draw(datetimes(
3701 min_value=self.min_datetime,
3702 max_value=self.max_datetime,
3704 optional = d.draw(booleans())
3705 obj = self.base_klass(default=default, optional=optional)
3706 self.assertTrue(obj.optional)
3708 @given(data_strategy())
3709 def test_ready(self, d):
3710 obj = self.base_klass()
3711 self.assertFalse(obj.ready)
3714 pprint(obj, big_blobs=True, with_decode_path=True)
3715 with self.assertRaises(ObjNotReady) as err:
3718 value = d.draw(datetimes(min_value=self.min_datetime))
3719 obj = self.base_klass(value)
3720 self.assertTrue(obj.ready)
3723 pprint(obj, big_blobs=True, with_decode_path=True)
3725 @given(data_strategy())
3726 def test_comparison(self, d):
3727 value1 = d.draw(datetimes(
3728 min_value=self.min_datetime,
3729 max_value=self.max_datetime,
3731 value2 = d.draw(datetimes(
3732 min_value=self.min_datetime,
3733 max_value=self.max_datetime,
3735 tag1 = d.draw(binary(min_size=1))
3736 tag2 = d.draw(binary(min_size=1))
3738 value1 = value1.replace(microsecond=0)
3739 value2 = value2.replace(microsecond=0)
3740 obj1 = self.base_klass(value1)
3741 obj2 = self.base_klass(value2)
3742 self.assertEqual(obj1 == obj2, value1 == value2)
3743 self.assertEqual(obj1 != obj2, value1 != value2)
3744 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3745 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3746 obj1 = self.base_klass(value1, impl=tag1)
3747 obj2 = self.base_klass(value1, impl=tag2)
3748 self.assertEqual(obj1 == obj2, tag1 == tag2)
3749 self.assertEqual(obj1 != obj2, tag1 != tag2)
3751 @given(data_strategy())
3752 def test_call(self, d):
3760 ) = d.draw(generalized_time_values_strategy(
3761 min_datetime=self.min_datetime,
3762 max_datetime=self.max_datetime,
3763 omit_ms=self.omit_ms,
3765 obj_initial = self.base_klass(
3766 value=value_initial,
3769 default=default_initial,
3770 optional=optional_initial or False,
3771 _decoded=_decoded_initial,
3780 ) = d.draw(generalized_time_values_strategy(
3781 min_datetime=self.min_datetime,
3782 max_datetime=self.max_datetime,
3783 omit_ms=self.omit_ms,
3784 do_expl=impl_initial is None,
3794 value_expected = default if value is None else value
3796 default_initial if value_expected is None
3799 self.assertEqual(obj, value_expected)
3800 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3801 self.assertEqual(obj.expl_tag, expl or expl_initial)
3804 default_initial if default is None else default,
3806 if obj.default is None:
3807 optional = optional_initial if optional is None else optional
3808 optional = False if optional is None else optional
3811 self.assertEqual(obj.optional, optional)
3813 @given(data_strategy())
3814 def test_copy(self, d):
3815 values = d.draw(generalized_time_values_strategy(
3816 min_datetime=self.min_datetime,
3817 max_datetime=self.max_datetime,
3819 obj = self.base_klass(*values)
3820 for copy_func in copy_funcs:
3821 obj_copied = copy_func(obj)
3822 self.assert_copied_basic_fields(obj, obj_copied)
3823 self.assertEqual(obj._value, obj_copied._value)
3825 @given(data_strategy())
3826 def test_stripped(self, d):
3827 value = d.draw(datetimes(
3828 min_value=self.min_datetime,
3829 max_value=self.max_datetime,
3831 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3832 obj = self.base_klass(value, impl=tag_impl)
3833 with self.assertRaises(NotEnoughData):
3834 obj.decode(obj.encode()[:-1])
3836 @given(data_strategy())
3837 def test_stripped_expl(self, d):
3838 value = d.draw(datetimes(
3839 min_value=self.min_datetime,
3840 max_value=self.max_datetime,
3842 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3843 obj = self.base_klass(value, expl=tag_expl)
3844 with self.assertRaises(NotEnoughData):
3845 obj.decode(obj.encode()[:-1])
3847 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3848 @given(data_strategy())
3849 def test_symmetric(self, d):
3850 values = d.draw(generalized_time_values_strategy(
3851 min_datetime=self.min_datetime,
3852 max_datetime=self.max_datetime,
3854 value = d.draw(datetimes(
3855 min_value=self.min_datetime,
3856 max_value=self.max_datetime,
3858 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3859 offset = d.draw(integers(min_value=0))
3860 tail_junk = d.draw(binary(max_size=5))
3861 _, _, _, default, optional, _decoded = values
3862 obj = self.base_klass(
3870 pprint(obj, big_blobs=True, with_decode_path=True)
3871 self.assertFalse(obj.expled)
3872 obj_encoded = obj.encode()
3873 self.additional_symmetric_check(value, obj_encoded)
3874 obj_expled = obj(value, expl=tag_expl)
3875 self.assertTrue(obj_expled.expled)
3877 list(obj_expled.pps())
3878 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3879 obj_expled_encoded = obj_expled.encode()
3880 ctx_copied = deepcopy(ctx_dummy)
3881 obj_decoded, tail = obj_expled.decode(
3882 obj_expled_encoded + tail_junk,
3886 self.assertDictEqual(ctx_copied, ctx_dummy)
3888 list(obj_decoded.pps())
3889 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3890 self.assertEqual(tail, tail_junk)
3891 self.assertEqual(obj_decoded, obj_expled)
3892 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3893 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3894 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3895 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3896 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3898 obj_decoded.expl_llen,
3899 len(len_encode(len(obj_encoded))),
3901 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3902 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3905 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3907 self.assertEqual(obj_decoded.expl_offset, offset)
3908 assert_exceeding_data(
3910 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3915 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3916 base_klass = GeneralizedTime
3918 min_datetime = datetime(1900, 1, 1)
3919 max_datetime = datetime(9999, 12, 31)
3921 def additional_symmetric_check(self, value, obj_encoded):
3922 if value.microsecond > 0:
3923 self.assertFalse(obj_encoded.endswith(b"0Z"))
3925 def test_x690_vector_valid(self):
3929 b"19920722132100.3Z",
3931 GeneralizedTime(data)
3933 def test_x690_vector_invalid(self):
3936 b"19920622123421.0Z",
3937 b"19920722132100.30Z",
3939 with self.assertRaises(DecodeError) as err:
3940 GeneralizedTime(data)
3943 def test_go_vectors_invalid(self):
3955 b"-20100102030410Z",
3956 b"2010-0102030410Z",
3957 b"2010-0002030410Z",
3958 b"201001-02030410Z",
3959 b"20100102-030410Z",
3960 b"2010010203-0410Z",
3961 b"201001020304-10Z",
3962 # These ones are INVALID in *DER*, but accepted
3963 # by Go's encoding/asn1
3964 b"20100102030405+0607",
3965 b"20100102030405-0607",
3967 with self.assertRaises(DecodeError) as err:
3968 GeneralizedTime(data)
3971 def test_go_vectors_valid(self):
3973 GeneralizedTime(b"20100102030405Z").todatetime(),
3974 datetime(2010, 1, 2, 3, 4, 5, 0),
3979 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3980 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3982 binary(min_size=1, max_size=1),
3984 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3985 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3988 def test_junk(self, part0, part1, part2):
3989 junk = part0 + part1 + part2
3990 assume(not (set(junk) <= set(digits.encode("ascii"))))
3991 with self.assertRaises(DecodeError):
3992 GeneralizedTime().decode(
3993 GeneralizedTime.tag_default +
3994 len_encode(len(junk)) +
4000 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4001 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4003 binary(min_size=1, max_size=1),
4005 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4006 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4009 def test_junk_dm(self, part0, part1, part2):
4010 junk = part0 + part1 + part2
4011 assume(not (set(junk) <= set(digits.encode("ascii"))))
4012 with self.assertRaises(DecodeError):
4013 GeneralizedTime().decode(
4014 GeneralizedTime.tag_default +
4015 len_encode(len(junk)) +
4019 def test_ns_fractions(self):
4020 GeneralizedTime(b"20010101000000.000001Z")
4021 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
4022 GeneralizedTime(b"20010101000000.0000001Z")
4025 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4026 base_klass = UTCTime
4028 min_datetime = datetime(2000, 1, 1)
4029 max_datetime = datetime(2049, 12, 31)
4031 def additional_symmetric_check(self, value, obj_encoded):
4034 def test_x690_vector_valid(self):
4042 def test_x690_vector_invalid(self):
4047 with self.assertRaises(DecodeError) as err:
4051 def test_go_vectors_invalid(self):
4077 # These ones are INVALID in *DER*, but accepted
4078 # by Go's encoding/asn1
4079 b"910506164540-0700",
4080 b"910506164540+0730",
4084 with self.assertRaises(DecodeError) as err:
4088 def test_go_vectors_valid(self):
4090 UTCTime(b"910506234540Z").todatetime(),
4091 datetime(1991, 5, 6, 23, 45, 40, 0),
4094 @given(integers(min_value=0, max_value=49))
4095 def test_pre50(self, year):
4097 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4101 @given(integers(min_value=50, max_value=99))
4102 def test_post50(self, year):
4104 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4110 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4111 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4113 binary(min_size=1, max_size=1),
4115 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4116 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4119 def test_junk(self, part0, part1, part2):
4120 junk = part0 + part1 + part2
4121 assume(not (set(junk) <= set(digits.encode("ascii"))))
4122 with self.assertRaises(DecodeError):
4124 UTCTime.tag_default +
4125 len_encode(len(junk)) +
4131 def any_values_strategy(draw, do_expl=False):
4132 value = draw(one_of(none(), binary()))
4135 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4136 optional = draw(one_of(none(), booleans()))
4138 draw(integers(min_value=0)),
4139 draw(integers(min_value=0)),
4140 draw(integers(min_value=0)),
4142 return (value, expl, optional, _decoded)
4145 class AnyInherited(Any):
4149 class TestAny(CommonMixin, TestCase):
4152 def test_invalid_value_type(self):
4153 with self.assertRaises(InvalidValueType) as err:
4158 def test_optional(self, optional):
4159 obj = Any(optional=optional)
4160 self.assertEqual(obj.optional, optional)
4163 def test_ready(self, value):
4165 self.assertFalse(obj.ready)
4168 pprint(obj, big_blobs=True, with_decode_path=True)
4169 with self.assertRaises(ObjNotReady) as err:
4173 self.assertTrue(obj.ready)
4176 pprint(obj, big_blobs=True, with_decode_path=True)
4179 def test_basic(self, value):
4180 integer_encoded = Integer(value).encode()
4182 Any(integer_encoded),
4183 Any(Integer(value)),
4184 Any(Any(Integer(value))),
4186 self.assertSequenceEqual(bytes(obj), integer_encoded)
4188 obj.decode(obj.encode())[0].vlen,
4189 len(integer_encoded),
4193 pprint(obj, big_blobs=True, with_decode_path=True)
4194 self.assertSequenceEqual(obj.encode(), integer_encoded)
4196 @given(binary(), binary())
4197 def test_comparison(self, value1, value2):
4198 for klass in (Any, AnyInherited):
4199 obj1 = klass(value1)
4200 obj2 = klass(value2)
4201 self.assertEqual(obj1 == obj2, value1 == value2)
4202 self.assertEqual(obj1 != obj2, value1 != value2)
4203 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4205 @given(data_strategy())
4206 def test_call(self, d):
4207 for klass in (Any, AnyInherited):
4213 ) = d.draw(any_values_strategy())
4214 obj_initial = klass(
4217 optional_initial or False,
4225 ) = d.draw(any_values_strategy(do_expl=True))
4226 obj = obj_initial(value, expl, optional)
4228 value_expected = None if value is None else value
4229 self.assertEqual(obj, value_expected)
4230 self.assertEqual(obj.expl_tag, expl or expl_initial)
4231 if obj.default is None:
4232 optional = optional_initial if optional is None else optional
4233 optional = False if optional is None else optional
4234 self.assertEqual(obj.optional, optional)
4236 def test_simultaneous_impl_expl(self):
4237 # override it, as Any does not have implicit tag
4240 def test_decoded(self):
4241 # override it, as Any does not have implicit tag
4244 @given(any_values_strategy())
4245 def test_copy(self, values):
4246 for klass in (Any, AnyInherited):
4247 obj = klass(*values)
4248 for copy_func in copy_funcs:
4249 obj_copied = copy_func(obj)
4250 self.assert_copied_basic_fields(obj, obj_copied)
4251 self.assertEqual(obj._value, obj_copied._value)
4253 @given(binary().map(OctetString))
4254 def test_stripped(self, value):
4256 with self.assertRaises(NotEnoughData):
4257 obj.decode(obj.encode()[:-1])
4261 integers(min_value=1).map(tag_ctxc),
4263 def test_stripped_expl(self, value, tag_expl):
4264 obj = Any(value, expl=tag_expl)
4265 with self.assertRaises(NotEnoughData):
4266 obj.decode(obj.encode()[:-1])
4269 integers(min_value=31),
4270 integers(min_value=0),
4273 def test_bad_tag(self, tag, offset, decode_path):
4274 with self.assertRaises(DecodeError) as err:
4276 tag_encode(tag)[:-1],
4278 decode_path=decode_path,
4281 self.assertEqual(err.exception.offset, offset)
4282 self.assertEqual(err.exception.decode_path, decode_path)
4285 integers(min_value=128),
4286 integers(min_value=0),
4289 def test_bad_len(self, l, offset, decode_path):
4290 with self.assertRaises(DecodeError) as err:
4292 Any.tag_default + len_encode(l)[:-1],
4294 decode_path=decode_path,
4297 self.assertEqual(err.exception.offset, offset)
4298 self.assertEqual(err.exception.decode_path, decode_path)
4300 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4302 any_values_strategy(),
4303 integers().map(lambda x: Integer(x).encode()),
4304 integers(min_value=1).map(tag_ctxc),
4305 integers(min_value=0),
4308 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4309 for klass in (Any, AnyInherited):
4310 _, _, optional, _decoded = values
4311 obj = klass(value=value, optional=optional, _decoded=_decoded)
4314 pprint(obj, big_blobs=True, with_decode_path=True)
4315 self.assertFalse(obj.expled)
4316 obj_encoded = obj.encode()
4317 obj_expled = obj(value, expl=tag_expl)
4318 self.assertTrue(obj_expled.expled)
4320 list(obj_expled.pps())
4321 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4322 obj_expled_encoded = obj_expled.encode()
4323 ctx_copied = deepcopy(ctx_dummy)
4324 obj_decoded, tail = obj_expled.decode(
4325 obj_expled_encoded + tail_junk,
4329 self.assertDictEqual(ctx_copied, ctx_dummy)
4331 list(obj_decoded.pps())
4332 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4333 self.assertEqual(tail, tail_junk)
4334 self.assertEqual(obj_decoded, obj_expled)
4335 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4336 self.assertEqual(bytes(obj_decoded), bytes(obj))
4337 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4338 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4339 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4341 obj_decoded.expl_llen,
4342 len(len_encode(len(obj_encoded))),
4344 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4345 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4348 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4350 self.assertEqual(obj_decoded.expl_offset, offset)
4351 self.assertEqual(obj_decoded.tlen, 0)
4352 self.assertEqual(obj_decoded.llen, 0)
4353 self.assertEqual(obj_decoded.vlen, len(value))
4354 assert_exceeding_data(
4356 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4361 integers(min_value=1).map(tag_ctxc),
4362 integers(min_value=0, max_value=3),
4363 integers(min_value=0),
4367 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4368 chunk = Boolean(False, expl=expl).encode()
4370 OctetString.tag_default +
4372 b"".join([chunk] * chunks) +
4375 with self.assertRaises(LenIndefForm):
4379 decode_path=decode_path,
4381 obj, tail = Any().decode(
4384 decode_path=decode_path,
4385 ctx={"bered": True},
4387 self.assertSequenceEqual(tail, junk)
4388 self.assertEqual(obj.offset, offset)
4389 self.assertEqual(obj.tlvlen, len(encoded))
4390 self.assertTrue(obj.lenindef)
4391 self.assertFalse(obj.ber_encoded)
4392 self.assertTrue(obj.bered)
4394 self.assertTrue(obj.lenindef)
4395 self.assertFalse(obj.ber_encoded)
4396 self.assertTrue(obj.bered)
4399 pprint(obj, big_blobs=True, with_decode_path=True)
4400 with self.assertRaises(NotEnoughData) as err:
4404 decode_path=decode_path,
4405 ctx={"bered": True},
4407 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4408 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4410 class SeqOf(SequenceOf):
4411 schema = Boolean(expl=expl)
4413 class Seq(Sequence):
4415 ("type", ObjectIdentifier(defines=((("value",), {
4416 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4421 ("type", ObjectIdentifier("1.2.3")),
4422 ("value", Any(encoded)),
4424 seq_encoded = seq.encode()
4425 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4426 self.assertIsNotNone(seq_decoded["value"].defined)
4428 list(seq_decoded.pps())
4429 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4430 self.assertTrue(seq_decoded.bered)
4431 self.assertFalse(seq_decoded["type"].bered)
4432 self.assertTrue(seq_decoded["value"].bered)
4434 chunk = chunk[:-1] + b"\x01"
4435 chunks = b"".join([chunk] * (chunks + 1))
4436 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4438 ("type", ObjectIdentifier("1.2.3")),
4439 ("value", Any(encoded)),
4441 seq_encoded = seq.encode()
4442 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4443 self.assertIsNotNone(seq_decoded["value"].defined)
4445 list(seq_decoded.pps())
4446 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4447 self.assertTrue(seq_decoded.bered)
4448 self.assertFalse(seq_decoded["type"].bered)
4449 self.assertTrue(seq_decoded["value"].bered)
4453 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4455 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4456 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4458 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4459 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4461 min_size=len(names),
4462 max_size=len(names),
4465 (name, Integer(**tag_kwargs))
4466 for name, tag_kwargs in zip(names, tags)
4469 if value_required or draw(booleans()):
4470 value = draw(tuples(
4471 sampled_from([name for name, _ in schema]),
4472 integers().map(Integer),
4476 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4477 default = draw(one_of(
4479 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4481 optional = draw(one_of(none(), booleans()))
4483 draw(integers(min_value=0)),
4484 draw(integers(min_value=0)),
4485 draw(integers(min_value=0)),
4487 return (schema, value, expl, default, optional, _decoded)
4490 class ChoiceInherited(Choice):
4494 class TestChoice(CommonMixin, TestCase):
4496 schema = (("whatever", Boolean()),)
4499 def test_schema_required(self):
4500 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4503 def test_impl_forbidden(self):
4504 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4505 Choice(impl=b"whatever")
4507 def test_invalid_value_type(self):
4508 with self.assertRaises(InvalidValueType) as err:
4509 self.base_klass(123)
4511 with self.assertRaises(ObjUnknown) as err:
4512 self.base_klass(("whenever", Boolean(False)))
4514 with self.assertRaises(InvalidValueType) as err:
4515 self.base_klass(("whatever", Integer(123)))
4519 def test_optional(self, optional):
4520 obj = self.base_klass(
4521 default=self.base_klass(("whatever", Boolean(False))),
4524 self.assertTrue(obj.optional)
4527 def test_ready(self, value):
4528 obj = self.base_klass()
4529 self.assertFalse(obj.ready)
4532 pprint(obj, big_blobs=True, with_decode_path=True)
4533 self.assertIsNone(obj["whatever"])
4534 with self.assertRaises(ObjNotReady) as err:
4537 obj["whatever"] = Boolean()
4538 self.assertFalse(obj.ready)
4541 pprint(obj, big_blobs=True, with_decode_path=True)
4542 obj["whatever"] = Boolean(value)
4543 self.assertTrue(obj.ready)
4546 pprint(obj, big_blobs=True, with_decode_path=True)
4548 @given(booleans(), booleans())
4549 def test_comparison(self, value1, value2):
4550 class WahlInherited(self.base_klass):
4552 for klass in (self.base_klass, WahlInherited):
4553 obj1 = klass(("whatever", Boolean(value1)))
4554 obj2 = klass(("whatever", Boolean(value2)))
4555 self.assertEqual(obj1 == obj2, value1 == value2)
4556 self.assertEqual(obj1 != obj2, value1 != value2)
4557 self.assertEqual(obj1 == obj2._value, value1 == value2)
4558 self.assertFalse(obj1 == obj2._value[1])
4560 @given(data_strategy())
4561 def test_call(self, d):
4562 for klass in (Choice, ChoiceInherited):
4570 ) = d.draw(choice_values_strategy())
4573 schema = schema_initial
4575 value=value_initial,
4577 default=default_initial,
4578 optional=optional_initial or False,
4579 _decoded=_decoded_initial,
4588 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4589 obj = obj_initial(value, expl, default, optional)
4591 value_expected = default if value is None else value
4593 default_initial if value_expected is None
4596 self.assertEqual(obj.choice, value_expected[0])
4597 self.assertEqual(obj.value, int(value_expected[1]))
4598 self.assertEqual(obj.expl_tag, expl or expl_initial)
4599 default_expect = default_initial if default is None else default
4600 if default_expect is not None:
4601 self.assertEqual(obj.default.choice, default_expect[0])
4602 self.assertEqual(obj.default.value, int(default_expect[1]))
4603 if obj.default is None:
4604 optional = optional_initial if optional is None else optional
4605 optional = False if optional is None else optional
4608 self.assertEqual(obj.optional, optional)
4609 self.assertEqual(obj.specs, obj_initial.specs)
4611 def test_simultaneous_impl_expl(self):
4612 # override it, as Any does not have implicit tag
4615 def test_decoded(self):
4616 # override it, as Any does not have implicit tag
4619 @given(choice_values_strategy())
4620 def test_copy(self, values):
4621 _schema, value, expl, default, optional, _decoded = values
4623 class Wahl(self.base_klass):
4625 register_class(Wahl)
4630 optional=optional or False,
4633 for copy_func in copy_funcs:
4634 obj_copied = copy_func(obj)
4635 self.assertIsNone(obj.tag)
4636 self.assertIsNone(obj_copied.tag)
4637 # hack for assert_copied_basic_fields
4638 obj.tag = "whatever"
4639 obj_copied.tag = "whatever"
4640 self.assert_copied_basic_fields(obj, obj_copied)
4642 self.assertEqual(obj._value, obj_copied._value)
4643 self.assertEqual(obj.specs, obj_copied.specs)
4646 def test_stripped(self, value):
4647 obj = self.base_klass(("whatever", Boolean(value)))
4648 with self.assertRaises(NotEnoughData):
4649 obj.decode(obj.encode()[:-1])
4653 integers(min_value=1).map(tag_ctxc),
4655 def test_stripped_expl(self, value, tag_expl):
4656 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4657 with self.assertRaises(NotEnoughData):
4658 obj.decode(obj.encode()[:-1])
4660 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4661 @given(data_strategy())
4662 def test_symmetric(self, d):
4663 _schema, value, _, default, optional, _decoded = d.draw(
4664 choice_values_strategy(value_required=True)
4666 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4667 offset = d.draw(integers(min_value=0))
4668 tail_junk = d.draw(binary(max_size=5))
4670 class Wahl(self.base_klass):
4680 pprint(obj, big_blobs=True, with_decode_path=True)
4681 self.assertFalse(obj.expled)
4682 obj_encoded = obj.encode()
4683 obj_expled = obj(value, expl=tag_expl)
4684 self.assertTrue(obj_expled.expled)
4686 list(obj_expled.pps())
4687 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4688 obj_expled_encoded = obj_expled.encode()
4689 ctx_copied = deepcopy(ctx_dummy)
4690 obj_decoded, tail = obj_expled.decode(
4691 obj_expled_encoded + tail_junk,
4695 self.assertDictEqual(ctx_copied, ctx_dummy)
4697 list(obj_decoded.pps())
4698 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4699 self.assertEqual(tail, tail_junk)
4700 self.assertEqual(obj_decoded, obj_expled)
4701 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4702 self.assertEqual(obj_decoded.value, obj_expled.value)
4703 self.assertEqual(obj_decoded.choice, obj.choice)
4704 self.assertEqual(obj_decoded.value, obj.value)
4705 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4706 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4707 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4709 obj_decoded.expl_llen,
4710 len(len_encode(len(obj_encoded))),
4712 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4713 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4716 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4718 self.assertEqual(obj_decoded.expl_offset, offset)
4719 self.assertSequenceEqual(
4721 obj_decoded.value.fulloffset - offset:
4722 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4726 assert_exceeding_data(
4728 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4733 def test_set_get(self, value):
4736 ("erste", Boolean()),
4737 ("zweite", Integer()),
4740 with self.assertRaises(ObjUnknown) as err:
4741 obj["whatever"] = "whenever"
4742 with self.assertRaises(InvalidValueType) as err:
4743 obj["zweite"] = Boolean(False)
4744 obj["zweite"] = Integer(value)
4746 with self.assertRaises(ObjUnknown) as err:
4749 self.assertIsNone(obj["erste"])
4750 self.assertEqual(obj["zweite"], Integer(value))
4752 def test_tag_mismatch(self):
4755 ("erste", Boolean()),
4757 int_encoded = Integer(123).encode()
4758 bool_encoded = Boolean(False).encode()
4760 obj.decode(bool_encoded)
4761 with self.assertRaises(TagMismatch):
4762 obj.decode(int_encoded)
4764 def test_tag_mismatch_underlying(self):
4765 class SeqOfBoolean(SequenceOf):
4768 class SeqOfInteger(SequenceOf):
4773 ("erste", SeqOfBoolean()),
4776 int_encoded = SeqOfInteger((Integer(123),)).encode()
4777 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4779 obj.decode(bool_encoded)
4780 with self.assertRaises(TagMismatch) as err:
4781 obj.decode(int_encoded)
4782 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4786 def seq_values_strategy(draw, seq_klass, do_expl=False):
4788 if draw(booleans()):
4790 value._value = draw(dictionaries(
4793 booleans().map(Boolean),
4794 integers().map(Integer),
4798 if draw(booleans()):
4799 schema = list(draw(dictionaries(
4802 booleans().map(Boolean),
4803 integers().map(Integer),
4809 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4811 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4813 if draw(booleans()):
4814 default = seq_klass()
4815 default._value = draw(dictionaries(
4818 booleans().map(Boolean),
4819 integers().map(Integer),
4822 optional = draw(one_of(none(), booleans()))
4824 draw(integers(min_value=0)),
4825 draw(integers(min_value=0)),
4826 draw(integers(min_value=0)),
4828 return (value, schema, impl, expl, default, optional, _decoded)
4832 def sequence_strategy(draw, seq_klass):
4833 inputs = draw(lists(
4835 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4836 tuples(just(Integer), integers(), one_of(none(), integers())),
4841 integers(min_value=1),
4842 min_size=len(inputs),
4843 max_size=len(inputs),
4846 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4847 for tag, expled in zip(tags, draw(lists(
4849 min_size=len(inputs),
4850 max_size=len(inputs),
4854 for i, optional in enumerate(draw(lists(
4855 sampled_from(("required", "optional", "empty")),
4856 min_size=len(inputs),
4857 max_size=len(inputs),
4859 if optional in ("optional", "empty"):
4860 inits[i]["optional"] = True
4861 if optional == "empty":
4863 empties = set(empties)
4864 names = list(draw(sets(
4866 min_size=len(inputs),
4867 max_size=len(inputs),
4870 for i, (klass, value, default) in enumerate(inputs):
4871 schema.append((names[i], klass(default=default, **inits[i])))
4872 seq_name = draw(text_letters())
4873 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4876 for i, (klass, value, default) in enumerate(inputs):
4883 "default_value": None if spec.default is None else default,
4887 expect["optional"] = True
4889 expect["presented"] = True
4890 expect["value"] = value
4892 expect["optional"] = True
4893 if default is not None and default == value:
4894 expect["presented"] = False
4895 seq[name] = klass(value)
4896 expects.append(expect)
4901 def sequences_strategy(draw, seq_klass):
4902 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4904 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4905 for tag, expled in zip(tags, draw(lists(
4912 i for i, is_default in enumerate(draw(lists(
4918 names = list(draw(sets(
4923 seq_expectses = draw(lists(
4924 sequence_strategy(seq_klass=seq_klass),
4928 seqs = [seq for seq, _ in seq_expectses]
4930 for i, (name, seq) in enumerate(zip(names, seqs)):
4933 seq(default=(seq if i in defaulted else None), **inits[i]),
4935 seq_name = draw(text_letters())
4936 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4939 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4942 "expects": expects_inner,
4945 seq_outer[name] = seq_inner
4946 if seq_outer.specs[name].default is None:
4947 expect["presented"] = True
4948 expect_outers.append(expect)
4949 return seq_outer, expect_outers
4952 class SeqMixing(object):
4953 def test_invalid_value_type(self):
4954 with self.assertRaises(InvalidValueType) as err:
4955 self.base_klass(123)
4958 def test_invalid_value_type_set(self):
4959 class Seq(self.base_klass):
4960 schema = (("whatever", Boolean()),)
4962 with self.assertRaises(InvalidValueType) as err:
4963 seq["whatever"] = Integer(123)
4967 def test_optional(self, optional):
4968 obj = self.base_klass(default=self.base_klass(), optional=optional)
4969 self.assertTrue(obj.optional)
4971 @given(data_strategy())
4972 def test_ready(self, d):
4974 str(i): v for i, v in enumerate(d.draw(lists(
4981 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4988 for name in d.draw(permutations(
4989 list(ready.keys()) + list(non_ready.keys()),
4991 schema_input.append((name, Boolean()))
4993 class Seq(self.base_klass):
4994 schema = tuple(schema_input)
4996 for name in ready.keys():
4998 seq[name] = Boolean()
4999 self.assertFalse(seq.ready)
5002 pprint(seq, big_blobs=True, with_decode_path=True)
5003 for name, value in ready.items():
5004 seq[name] = Boolean(value)
5005 self.assertFalse(seq.ready)
5008 pprint(seq, big_blobs=True, with_decode_path=True)
5009 with self.assertRaises(ObjNotReady) as err:
5012 for name, value in non_ready.items():
5013 seq[name] = Boolean(value)
5014 self.assertTrue(seq.ready)
5017 pprint(seq, big_blobs=True, with_decode_path=True)
5019 @given(data_strategy())
5020 def test_call(self, d):
5021 class SeqInherited(self.base_klass):
5023 for klass in (self.base_klass, SeqInherited):
5032 ) = d.draw(seq_values_strategy(seq_klass=klass))
5033 obj_initial = klass(
5039 optional_initial or False,
5050 ) = d.draw(seq_values_strategy(
5052 do_expl=impl_initial is None,
5054 obj = obj_initial(value, impl, expl, default, optional)
5055 value_expected = default if value is None else value
5057 default_initial if value_expected is None
5060 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5061 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5062 self.assertEqual(obj.expl_tag, expl or expl_initial)
5064 {} if obj.default is None else obj.default._value,
5065 getattr(default_initial if default is None else default, "_value", {}),
5067 if obj.default is None:
5068 optional = optional_initial if optional is None else optional
5069 optional = False if optional is None else optional
5072 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5073 self.assertEqual(obj.optional, optional)
5075 @given(data_strategy())
5076 def test_copy(self, d):
5077 class SeqInherited(self.base_klass):
5079 register_class(SeqInherited)
5080 for klass in (self.base_klass, SeqInherited):
5081 values = d.draw(seq_values_strategy(seq_klass=klass))
5082 obj = klass(*values)
5083 for copy_func in copy_funcs:
5084 obj_copied = copy_func(obj)
5085 self.assert_copied_basic_fields(obj, obj_copied)
5086 self.assertEqual(obj.specs, obj_copied.specs)
5087 self.assertEqual(obj._value, obj_copied._value)
5089 @given(data_strategy())
5090 def test_stripped(self, d):
5091 value = d.draw(integers())
5092 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5094 class Seq(self.base_klass):
5096 schema = (("whatever", Integer()),)
5098 seq["whatever"] = Integer(value)
5099 with self.assertRaises(NotEnoughData):
5100 seq.decode(seq.encode()[:-1])
5102 @given(data_strategy())
5103 def test_stripped_expl(self, d):
5104 value = d.draw(integers())
5105 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5107 class Seq(self.base_klass):
5109 schema = (("whatever", Integer()),)
5111 seq["whatever"] = Integer(value)
5112 with self.assertRaises(NotEnoughData):
5113 seq.decode(seq.encode()[:-1])
5115 @given(binary(min_size=2))
5116 def test_non_tag_mismatch_raised(self, junk):
5118 _, _, len_encoded = tag_strip(memoryview(junk))
5119 len_decode(len_encoded)
5125 class Seq(self.base_klass):
5127 ("whatever", Integer()),
5129 ("whenever", Integer()),
5132 seq["whatever"] = Integer(123)
5133 seq["junk"] = Any(junk)
5134 seq["whenever"] = Integer(123)
5135 with self.assertRaises(DecodeError):
5136 seq.decode(seq.encode())
5139 integers(min_value=31),
5140 integers(min_value=0),
5143 def test_bad_tag(self, tag, offset, decode_path):
5144 with self.assertRaises(DecodeError) as err:
5145 self.base_klass().decode(
5146 tag_encode(tag)[:-1],
5148 decode_path=decode_path,
5151 self.assertEqual(err.exception.offset, offset)
5152 self.assertEqual(err.exception.decode_path, decode_path)
5155 integers(min_value=128),
5156 integers(min_value=0),
5159 def test_bad_len(self, l, offset, decode_path):
5160 with self.assertRaises(DecodeError) as err:
5161 self.base_klass().decode(
5162 self.base_klass.tag_default + len_encode(l)[:-1],
5164 decode_path=decode_path,
5167 self.assertEqual(err.exception.offset, offset)
5168 self.assertEqual(err.exception.decode_path, decode_path)
5170 def _assert_expects(self, seq, expects):
5171 for expect in expects:
5173 seq.specs[expect["name"]].optional,
5176 if expect["default_value"] is not None:
5178 seq.specs[expect["name"]].default,
5179 expect["default_value"],
5181 if expect["presented"]:
5182 self.assertIn(expect["name"], seq)
5183 self.assertEqual(seq[expect["name"]], expect["value"])
5185 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5186 @given(data_strategy())
5187 def test_symmetric(self, d):
5188 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5189 tail_junk = d.draw(binary(max_size=5))
5190 self.assertTrue(seq.ready)
5191 self.assertFalse(seq.decoded)
5192 self._assert_expects(seq, expects)
5195 pprint(seq, big_blobs=True, with_decode_path=True)
5196 self.assertTrue(seq.ready)
5197 seq_encoded = seq.encode()
5198 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5199 self.assertFalse(seq_decoded.lenindef)
5200 self.assertFalse(seq_decoded.ber_encoded)
5201 self.assertFalse(seq_decoded.bered)
5203 t, _, lv = tag_strip(seq_encoded)
5204 _, _, v = len_decode(lv)
5205 seq_encoded_lenindef = t + LENINDEF + v + EOC
5206 ctx_copied = deepcopy(ctx_dummy)
5207 ctx_copied["bered"] = True
5208 seq_decoded_lenindef, tail_lenindef = seq.decode(
5209 seq_encoded_lenindef + tail_junk,
5212 del ctx_copied["bered"]
5213 self.assertDictEqual(ctx_copied, ctx_dummy)
5214 self.assertTrue(seq_decoded_lenindef.lenindef)
5215 self.assertTrue(seq_decoded_lenindef.bered)
5216 seq_decoded_lenindef = copy(seq_decoded_lenindef)
5217 self.assertTrue(seq_decoded_lenindef.lenindef)
5218 self.assertTrue(seq_decoded_lenindef.bered)
5219 with self.assertRaises(DecodeError):
5220 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5221 with self.assertRaises(DecodeError):
5222 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5223 repr(seq_decoded_lenindef)
5224 list(seq_decoded_lenindef.pps())
5225 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5226 self.assertTrue(seq_decoded_lenindef.ready)
5228 for decoded, decoded_tail, encoded in (
5229 (seq_decoded, tail, seq_encoded),
5230 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5232 self.assertEqual(decoded_tail, tail_junk)
5233 self._assert_expects(decoded, expects)
5234 self.assertEqual(seq, decoded)
5235 self.assertEqual(decoded.encode(), seq_encoded)
5236 self.assertEqual(decoded.tlvlen, len(encoded))
5237 for expect in expects:
5238 if not expect["presented"]:
5239 self.assertNotIn(expect["name"], decoded)
5241 self.assertIn(expect["name"], decoded)
5242 obj = decoded[expect["name"]]
5243 self.assertTrue(obj.decoded)
5244 offset = obj.expl_offset if obj.expled else obj.offset
5245 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5246 self.assertSequenceEqual(
5247 seq_encoded[offset:offset + tlvlen],
5251 assert_exceeding_data(
5253 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
5257 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5258 @given(data_strategy())
5259 def test_symmetric_with_seq(self, d):
5260 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5261 self.assertTrue(seq.ready)
5262 seq_encoded = seq.encode()
5263 seq_decoded, tail = seq.decode(seq_encoded)
5264 self.assertEqual(tail, b"")
5265 self.assertTrue(seq.ready)
5266 self.assertEqual(seq, seq_decoded)
5267 self.assertEqual(seq_decoded.encode(), seq_encoded)
5268 for expect_outer in expect_outers:
5269 if not expect_outer["presented"]:
5270 self.assertNotIn(expect_outer["name"], seq_decoded)
5272 self.assertIn(expect_outer["name"], seq_decoded)
5273 obj = seq_decoded[expect_outer["name"]]
5274 self.assertTrue(obj.decoded)
5275 offset = obj.expl_offset if obj.expled else obj.offset
5276 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5277 self.assertSequenceEqual(
5278 seq_encoded[offset:offset + tlvlen],
5281 self._assert_expects(obj, expect_outer["expects"])
5283 @given(data_strategy())
5284 def test_default_disappears(self, d):
5285 _schema = list(d.draw(dictionaries(
5287 sets(integers(), min_size=2, max_size=2),
5291 class Seq(self.base_klass):
5293 (n, Integer(default=d))
5294 for n, (_, d) in _schema
5297 for name, (value, _) in _schema:
5298 seq[name] = Integer(value)
5299 self.assertEqual(len(seq._value), len(_schema))
5300 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5301 self.assertGreater(len(seq.encode()), len(empty_seq))
5302 for name, (_, default) in _schema:
5303 seq[name] = Integer(default)
5304 self.assertEqual(len(seq._value), 0)
5305 self.assertSequenceEqual(seq.encode(), empty_seq)
5307 @given(data_strategy())
5308 def test_encoded_default_not_accepted(self, d):
5309 _schema = list(d.draw(dictionaries(
5314 tags = [tag_encode(tag) for tag in d.draw(sets(
5315 integers(min_value=0),
5316 min_size=len(_schema),
5317 max_size=len(_schema),
5320 class SeqWithoutDefault(self.base_klass):
5322 (n, Integer(impl=t))
5323 for (n, _), t in zip(_schema, tags)
5325 seq_without_default = SeqWithoutDefault()
5326 for name, value in _schema:
5327 seq_without_default[name] = Integer(value)
5328 seq_encoded = seq_without_default.encode()
5330 class SeqWithDefault(self.base_klass):
5332 (n, Integer(default=v, impl=t))
5333 for (n, v), t in zip(_schema, tags)
5335 seq_with_default = SeqWithDefault()
5336 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5337 seq_with_default.decode(seq_encoded)
5338 for ctx in ({"bered": True}, {"allow_default_values": True}):
5339 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5340 self.assertTrue(seq_decoded.ber_encoded)
5341 self.assertTrue(seq_decoded.bered)
5342 seq_decoded = copy(seq_decoded)
5343 self.assertTrue(seq_decoded.ber_encoded)
5344 self.assertTrue(seq_decoded.bered)
5345 for name, value in _schema:
5346 self.assertEqual(seq_decoded[name], seq_with_default[name])
5347 self.assertEqual(seq_decoded[name], value)
5349 @given(data_strategy())
5350 def test_missing_from_spec(self, d):
5351 names = list(d.draw(sets(text_letters(), min_size=2)))
5352 tags = [tag_encode(tag) for tag in d.draw(sets(
5353 integers(min_value=0),
5354 min_size=len(names),
5355 max_size=len(names),
5357 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5359 class SeqFull(self.base_klass):
5360 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5361 seq_full = SeqFull()
5362 for i, name in enumerate(names):
5363 seq_full[name] = Integer(i)
5364 seq_encoded = seq_full.encode()
5365 altered = names_tags[:-2] + names_tags[-1:]
5367 class SeqMissing(self.base_klass):
5368 schema = [(n, Integer(impl=t)) for n, t in altered]
5369 seq_missing = SeqMissing()
5370 with self.assertRaises(TagMismatch):
5371 seq_missing.decode(seq_encoded)
5373 def test_bered(self):
5374 class Seq(self.base_klass):
5375 schema = (("underlying", Boolean()),)
5376 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5377 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5378 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5379 self.assertFalse(decoded.ber_encoded)
5380 self.assertFalse(decoded.lenindef)
5381 self.assertTrue(decoded.bered)
5382 decoded = copy(decoded)
5383 self.assertFalse(decoded.ber_encoded)
5384 self.assertFalse(decoded.lenindef)
5385 self.assertTrue(decoded.bered)
5387 class Seq(self.base_klass):
5388 schema = (("underlying", OctetString()),)
5390 tag_encode(form=TagFormConstructed, num=4) +
5392 OctetString(b"whatever").encode() +
5395 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5396 with self.assertRaises(DecodeError):
5397 Seq().decode(encoded)
5398 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5399 self.assertFalse(decoded.ber_encoded)
5400 self.assertFalse(decoded.lenindef)
5401 self.assertTrue(decoded.bered)
5402 decoded = copy(decoded)
5403 self.assertFalse(decoded.ber_encoded)
5404 self.assertFalse(decoded.lenindef)
5405 self.assertTrue(decoded.bered)
5408 class TestSequence(SeqMixing, CommonMixin, TestCase):
5409 base_klass = Sequence
5415 def test_remaining(self, value, junk):
5416 class Seq(Sequence):
5418 ("whatever", Integer()),
5420 int_encoded = Integer(value).encode()
5422 Sequence.tag_default,
5423 len_encode(len(int_encoded + junk)),
5426 with assertRaisesRegex(self, DecodeError, "remaining"):
5427 Seq().decode(junked)
5429 @given(sets(text_letters(), min_size=2))
5430 def test_obj_unknown(self, names):
5431 missing = names.pop()
5433 class Seq(Sequence):
5434 schema = [(n, Boolean()) for n in names]
5436 with self.assertRaises(ObjUnknown) as err:
5439 with self.assertRaises(ObjUnknown) as err:
5440 seq[missing] = Boolean()
5443 def test_x690_vector(self):
5444 class Seq(Sequence):
5446 ("name", IA5String()),
5449 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5450 self.assertEqual(seq["name"], "Smith")
5451 self.assertEqual(seq["ok"], True)
5454 class TestSet(SeqMixing, CommonMixin, TestCase):
5457 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5458 @given(data_strategy())
5459 def test_sorted(self, d):
5461 tag_encode(tag) for tag in
5462 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5466 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5468 for name, _ in Seq.schema:
5469 seq[name] = OctetString(b"")
5470 seq_encoded = seq.encode()
5471 seq_decoded, _ = seq.decode(seq_encoded)
5472 self.assertSequenceEqual(
5473 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5474 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5477 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5478 @given(data_strategy())
5479 def test_unsorted(self, d):
5481 tag_encode(tag) for tag in
5482 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5484 tags = d.draw(permutations(tags))
5485 assume(tags != sorted(tags))
5486 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5487 seq_encoded = b"".join((
5489 len_encode(len(encoded)),
5494 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5496 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5497 seq.decode(seq_encoded)
5498 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5499 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5500 self.assertTrue(seq_decoded.ber_encoded)
5501 self.assertTrue(seq_decoded.bered)
5502 seq_decoded = copy(seq_decoded)
5503 self.assertTrue(seq_decoded.ber_encoded)
5504 self.assertTrue(seq_decoded.bered)
5505 self.assertSequenceEqual(
5506 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5512 def seqof_values_strategy(draw, schema=None, do_expl=False):
5514 schema = draw(sampled_from((Boolean(), Integer())))
5515 bound_min, bound_max = sorted(draw(sets(
5516 integers(min_value=0, max_value=10),
5520 if isinstance(schema, Boolean):
5521 values_generator = booleans().map(Boolean)
5522 elif isinstance(schema, Integer):
5523 values_generator = integers().map(Integer)
5524 values_generator = lists(
5529 values = draw(one_of(none(), values_generator))
5533 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5535 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5536 default = draw(one_of(none(), values_generator))
5537 optional = draw(one_of(none(), booleans()))
5539 draw(integers(min_value=0)),
5540 draw(integers(min_value=0)),
5541 draw(integers(min_value=0)),
5546 (bound_min, bound_max),
5555 class SeqOfMixing(object):
5556 def test_invalid_value_type(self):
5557 with self.assertRaises(InvalidValueType) as err:
5558 self.base_klass(123)
5561 def test_invalid_values_type(self):
5562 class SeqOf(self.base_klass):
5564 with self.assertRaises(InvalidValueType) as err:
5565 SeqOf([Integer(123), Boolean(False), Integer(234)])
5568 def test_schema_required(self):
5569 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5570 self.base_klass.__mro__[1]()
5572 @given(booleans(), booleans(), binary(), binary())
5573 def test_comparison(self, value1, value2, tag1, tag2):
5574 class SeqOf(self.base_klass):
5576 obj1 = SeqOf([Boolean(value1)])
5577 obj2 = SeqOf([Boolean(value2)])
5578 self.assertEqual(obj1 == obj2, value1 == value2)
5579 self.assertEqual(obj1 != obj2, value1 != value2)
5580 self.assertEqual(obj1 == list(obj2), value1 == value2)
5581 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5582 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5583 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5584 self.assertEqual(obj1 == obj2, tag1 == tag2)
5585 self.assertEqual(obj1 != obj2, tag1 != tag2)
5587 @given(lists(booleans()))
5588 def test_iter(self, values):
5589 class SeqOf(self.base_klass):
5591 obj = SeqOf([Boolean(value) for value in values])
5592 self.assertEqual(len(obj), len(values))
5593 for i, value in enumerate(obj):
5594 self.assertEqual(value, values[i])
5596 @given(data_strategy())
5597 def test_ready(self, d):
5598 ready = [Integer(v) for v in d.draw(lists(
5605 range(d.draw(integers(min_value=1, max_value=5)))
5608 class SeqOf(self.base_klass):
5610 values = d.draw(permutations(ready + non_ready))
5612 for value in values:
5614 self.assertFalse(seqof.ready)
5617 pprint(seqof, big_blobs=True, with_decode_path=True)
5618 with self.assertRaises(ObjNotReady) as err:
5621 for i, value in enumerate(values):
5622 self.assertEqual(seqof[i], value)
5623 if not seqof[i].ready:
5624 seqof[i] = Integer(i)
5625 self.assertTrue(seqof.ready)
5628 pprint(seqof, big_blobs=True, with_decode_path=True)
5630 def test_spec_mismatch(self):
5631 class SeqOf(self.base_klass):
5634 seqof.append(Integer(123))
5635 with self.assertRaises(ValueError):
5636 seqof.append(Boolean(False))
5637 with self.assertRaises(ValueError):
5638 seqof[0] = Boolean(False)
5640 @given(data_strategy())
5641 def test_bounds_satisfied(self, d):
5642 class SeqOf(self.base_klass):
5644 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5645 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5646 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5647 SeqOf(value=value, bounds=(bound_min, bound_max))
5649 @given(data_strategy())
5650 def test_bounds_unsatisfied(self, d):
5651 class SeqOf(self.base_klass):
5653 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5654 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5655 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5656 with self.assertRaises(BoundsError) as err:
5657 SeqOf(value=value, bounds=(bound_min, bound_max))
5659 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5660 SeqOf(bounds=(bound_min, bound_max)).decode(
5661 SeqOf(value).encode()
5664 value = [Boolean(True)] * d.draw(integers(
5665 min_value=bound_max + 1,
5666 max_value=bound_max + 10,
5668 with self.assertRaises(BoundsError) as err:
5669 SeqOf(value=value, bounds=(bound_min, bound_max))
5671 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5672 SeqOf(bounds=(bound_min, bound_max)).decode(
5673 SeqOf(value).encode()
5677 @given(integers(min_value=1, max_value=10))
5678 def test_out_of_bounds(self, bound_max):
5679 class SeqOf(self.base_klass):
5681 bounds = (0, bound_max)
5683 for _ in range(bound_max):
5684 seqof.append(Integer(123))
5685 with self.assertRaises(BoundsError):
5686 seqof.append(Integer(123))
5688 @given(data_strategy())
5689 def test_call(self, d):
5699 ) = d.draw(seqof_values_strategy())
5701 class SeqOf(self.base_klass):
5702 schema = schema_initial
5703 obj_initial = SeqOf(
5704 value=value_initial,
5705 bounds=bounds_initial,
5708 default=default_initial,
5709 optional=optional_initial or False,
5710 _decoded=_decoded_initial,
5721 ) = d.draw(seqof_values_strategy(
5722 schema=schema_initial,
5723 do_expl=impl_initial is None,
5725 if (default is None) and (obj_initial.default is not None):
5728 (bounds is None) and
5729 (value is not None) and
5730 (bounds_initial is not None) and
5731 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5735 (bounds is None) and
5736 (default is not None) and
5737 (bounds_initial is not None) and
5738 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5750 value_expected = default if value is None else value
5752 default_initial if value_expected is None
5755 value_expected = () if value_expected is None else value_expected
5756 self.assertEqual(obj, value_expected)
5757 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5758 self.assertEqual(obj.expl_tag, expl or expl_initial)
5761 default_initial if default is None else default,
5763 if obj.default is None:
5764 optional = optional_initial if optional is None else optional
5765 optional = False if optional is None else optional
5768 self.assertEqual(obj.optional, optional)
5770 (obj._bound_min, obj._bound_max),
5771 bounds or bounds_initial or (0, float("+inf")),
5774 @given(seqof_values_strategy())
5775 def test_copy(self, values):
5776 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5778 class SeqOf(self.base_klass):
5780 register_class(SeqOf)
5787 optional=optional or False,
5790 for copy_func in copy_funcs:
5791 obj_copied = copy_func(obj)
5792 self.assert_copied_basic_fields(obj, obj_copied)
5793 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5794 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5795 self.assertEqual(obj._value, obj_copied._value)
5799 integers(min_value=1).map(tag_encode),
5801 def test_stripped(self, values, tag_impl):
5802 class SeqOf(self.base_klass):
5803 schema = OctetString()
5804 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5805 with self.assertRaises(NotEnoughData):
5806 obj.decode(obj.encode()[:-1])
5810 integers(min_value=1).map(tag_ctxc),
5812 def test_stripped_expl(self, values, tag_expl):
5813 class SeqOf(self.base_klass):
5814 schema = OctetString()
5815 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5816 with self.assertRaises(NotEnoughData):
5817 obj.decode(obj.encode()[:-1])
5820 integers(min_value=31),
5821 integers(min_value=0),
5824 def test_bad_tag(self, tag, offset, decode_path):
5825 with self.assertRaises(DecodeError) as err:
5826 self.base_klass().decode(
5827 tag_encode(tag)[:-1],
5829 decode_path=decode_path,
5832 self.assertEqual(err.exception.offset, offset)
5833 self.assertEqual(err.exception.decode_path, decode_path)
5836 integers(min_value=128),
5837 integers(min_value=0),
5840 def test_bad_len(self, l, offset, decode_path):
5841 with self.assertRaises(DecodeError) as err:
5842 self.base_klass().decode(
5843 self.base_klass.tag_default + len_encode(l)[:-1],
5845 decode_path=decode_path,
5848 self.assertEqual(err.exception.offset, offset)
5849 self.assertEqual(err.exception.decode_path, decode_path)
5851 @given(binary(min_size=1))
5852 def test_tag_mismatch(self, impl):
5853 assume(impl != self.base_klass.tag_default)
5854 with self.assertRaises(TagMismatch):
5855 self.base_klass(impl=impl).decode(self.base_klass().encode())
5857 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5859 seqof_values_strategy(schema=Integer()),
5860 lists(integers().map(Integer)),
5861 integers(min_value=1).map(tag_ctxc),
5862 integers(min_value=0),
5865 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5866 _, _, _, _, _, default, optional, _decoded = values
5868 class SeqOf(self.base_klass):
5878 pprint(obj, big_blobs=True, with_decode_path=True)
5879 self.assertFalse(obj.expled)
5880 obj_encoded = obj.encode()
5881 obj_expled = obj(value, expl=tag_expl)
5882 self.assertTrue(obj_expled.expled)
5884 list(obj_expled.pps())
5885 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5886 obj_expled_encoded = obj_expled.encode()
5887 ctx_copied = deepcopy(ctx_dummy)
5888 obj_decoded, tail = obj_expled.decode(
5889 obj_expled_encoded + tail_junk,
5893 self.assertDictEqual(ctx_copied, ctx_dummy)
5895 list(obj_decoded.pps())
5896 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5897 self.assertEqual(tail, tail_junk)
5898 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5899 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5900 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5901 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5903 obj_decoded.expl_llen,
5904 len(len_encode(len(obj_encoded))),
5906 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5907 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5910 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5912 self.assertEqual(obj_decoded.expl_offset, offset)
5913 for obj_inner in obj_decoded:
5914 self.assertIn(obj_inner, obj_decoded)
5915 self.assertSequenceEqual(
5918 obj_inner.offset - offset:
5919 obj_inner.offset + obj_inner.tlvlen - offset
5923 t, _, lv = tag_strip(obj_encoded)
5924 _, _, v = len_decode(lv)
5925 obj_encoded_lenindef = t + LENINDEF + v + EOC
5926 obj_decoded_lenindef, tail_lenindef = obj.decode(
5927 obj_encoded_lenindef + tail_junk,
5928 ctx={"bered": True},
5930 self.assertTrue(obj_decoded_lenindef.lenindef)
5931 self.assertTrue(obj_decoded_lenindef.bered)
5932 obj_decoded_lenindef = copy(obj_decoded_lenindef)
5933 self.assertTrue(obj_decoded_lenindef.lenindef)
5934 self.assertTrue(obj_decoded_lenindef.bered)
5935 repr(obj_decoded_lenindef)
5936 list(obj_decoded_lenindef.pps())
5937 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5938 self.assertEqual(tail_lenindef, tail_junk)
5939 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5940 with self.assertRaises(DecodeError):
5941 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5942 with self.assertRaises(DecodeError):
5943 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5945 assert_exceeding_data(
5947 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5951 def test_bered(self):
5952 class SeqOf(self.base_klass):
5954 encoded = Boolean(False).encode()
5955 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5956 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5957 with self.assertRaises(DecodeError):
5958 SeqOf().decode(encoded)
5959 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5960 self.assertFalse(decoded.ber_encoded)
5961 self.assertFalse(decoded.lenindef)
5962 self.assertTrue(decoded.bered)
5963 decoded = copy(decoded)
5964 self.assertFalse(decoded.ber_encoded)
5965 self.assertFalse(decoded.lenindef)
5966 self.assertTrue(decoded.bered)
5968 class SeqOf(self.base_klass):
5969 schema = OctetString()
5970 encoded = OctetString(b"whatever").encode()
5972 tag_encode(form=TagFormConstructed, num=4) +
5974 OctetString(b"whatever").encode() +
5977 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5978 with self.assertRaises(DecodeError):
5979 SeqOf().decode(encoded)
5980 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5981 self.assertFalse(decoded.ber_encoded)
5982 self.assertFalse(decoded.lenindef)
5983 self.assertTrue(decoded.bered)
5984 decoded = copy(decoded)
5985 self.assertFalse(decoded.ber_encoded)
5986 self.assertFalse(decoded.lenindef)
5987 self.assertTrue(decoded.bered)
5990 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5991 class SeqOf(SequenceOf):
5995 def _test_symmetric_compare_objs(self, obj1, obj2):
5996 self.assertEqual(obj1, obj2)
5997 self.assertSequenceEqual(list(obj1), list(obj2))
6000 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
6005 def _test_symmetric_compare_objs(self, obj1, obj2):
6006 self.assertSetEqual(
6007 set(int(v) for v in obj1),
6008 set(int(v) for v in obj2),
6011 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6012 @given(data_strategy())
6013 def test_sorted(self, d):
6014 values = [OctetString(v) for v in d.draw(lists(binary()))]
6017 schema = OctetString()
6019 seq_encoded = seq.encode()
6020 seq_decoded, _ = seq.decode(seq_encoded)
6021 self.assertSequenceEqual(
6022 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6023 b"".join(sorted([v.encode() for v in values])),
6026 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6027 @given(data_strategy())
6028 def test_unsorted(self, d):
6029 values = [OctetString(v).encode() for v in d.draw(sets(
6030 binary(min_size=1, max_size=5),
6034 values = d.draw(permutations(values))
6035 assume(values != sorted(values))
6036 encoded = b"".join(values)
6037 seq_encoded = b"".join((
6039 len_encode(len(encoded)),
6044 schema = OctetString()
6046 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6047 seq.decode(seq_encoded)
6049 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6050 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6051 self.assertTrue(seq_decoded.ber_encoded)
6052 self.assertTrue(seq_decoded.bered)
6053 seq_decoded = copy(seq_decoded)
6054 self.assertTrue(seq_decoded.ber_encoded)
6055 self.assertTrue(seq_decoded.bered)
6056 self.assertSequenceEqual(
6057 [obj.encode() for obj in seq_decoded],
6062 class TestGoMarshalVectors(TestCase):
6064 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6065 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6066 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6067 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6068 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6070 class Seq(Sequence):
6072 ("erste", Integer()),
6073 ("zweite", Integer(optional=True))
6076 seq["erste"] = Integer(64)
6077 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6078 seq["erste"] = Integer(0x123456)
6079 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6080 seq["erste"] = Integer(64)
6081 seq["zweite"] = Integer(65)
6082 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6084 class NestedSeq(Sequence):
6088 seq["erste"] = Integer(127)
6089 seq["zweite"] = None
6090 nested = NestedSeq()
6091 nested["nest"] = seq
6092 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6094 self.assertSequenceEqual(
6095 OctetString(b"\x01\x02\x03").encode(),
6096 hexdec("0403010203"),
6099 class Seq(Sequence):
6101 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6104 seq["erste"] = Integer(64)
6105 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6107 class Seq(Sequence):
6109 ("erste", Integer(expl=tag_ctxc(5))),
6112 seq["erste"] = Integer(64)
6113 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6115 class Seq(Sequence):
6118 impl=tag_encode(0, klass=TagClassContext),
6123 seq["erste"] = Null()
6124 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6126 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6128 self.assertSequenceEqual(
6129 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6130 hexdec("170d3730303130313030303030305a"),
6132 self.assertSequenceEqual(
6133 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6134 hexdec("170d3039313131353232353631365a"),
6136 self.assertSequenceEqual(
6137 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6138 hexdec("180f32313030303430353132303130315a"),
6141 class Seq(Sequence):
6143 ("erste", GeneralizedTime()),
6146 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6147 self.assertSequenceEqual(
6149 hexdec("3011180f32303039313131353232353631365a"),
6152 self.assertSequenceEqual(
6153 BitString((1, b"\x80")).encode(),
6156 self.assertSequenceEqual(
6157 BitString((12, b"\x81\xF0")).encode(),
6158 hexdec("03030481f0"),
6161 self.assertSequenceEqual(
6162 ObjectIdentifier("1.2.3.4").encode(),
6163 hexdec("06032a0304"),
6165 self.assertSequenceEqual(
6166 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6167 hexdec("06092a864888932d010105"),
6169 self.assertSequenceEqual(
6170 ObjectIdentifier("2.100.3").encode(),
6171 hexdec("0603813403"),
6174 self.assertSequenceEqual(
6175 PrintableString("test").encode(),
6176 hexdec("130474657374"),
6178 self.assertSequenceEqual(
6179 PrintableString("x" * 127).encode(),
6180 hexdec("137F" + "78" * 127),
6182 self.assertSequenceEqual(
6183 PrintableString("x" * 128).encode(),
6184 hexdec("138180" + "78" * 128),
6186 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6188 class Seq(Sequence):
6190 ("erste", IA5String()),
6193 seq["erste"] = IA5String("test")
6194 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6196 class Seq(Sequence):
6198 ("erste", PrintableString()),
6201 seq["erste"] = PrintableString("test")
6202 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6203 # Asterisk is actually not allowable
6204 PrintableString._allowable_chars |= set(b"*")
6205 seq["erste"] = PrintableString("test*")
6206 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6207 PrintableString._allowable_chars -= set(b"*")
6209 class Seq(Sequence):
6211 ("erste", Any(optional=True)),
6212 ("zweite", Integer()),
6215 seq["zweite"] = Integer(64)
6216 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6221 seq.append(Integer(10))
6222 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6224 class _SeqOf(SequenceOf):
6225 schema = PrintableString()
6227 class SeqOf(SequenceOf):
6230 _seqof.append(PrintableString("1"))
6232 seqof.append(_seqof)
6233 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6235 class Seq(Sequence):
6237 ("erste", Integer(default=1)),
6240 seq["erste"] = Integer(0)
6241 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6242 seq["erste"] = Integer(1)
6243 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6244 seq["erste"] = Integer(2)
6245 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6248 class TestPP(TestCase):
6249 @given(data_strategy())
6250 def test_oid_printing(self, d):
6252 str(ObjectIdentifier(k)): v * 2
6253 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6255 chosen = d.draw(sampled_from(sorted(oids)))
6256 chosen_id = oids[chosen]
6257 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6258 self.assertNotIn(chosen_id, pp_console_row(pp))
6261 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6265 class TestAutoAddSlots(TestCase):
6267 class Inher(Integer):
6270 with self.assertRaises(AttributeError):
6272 inher.unexistent = "whatever"
6275 class TestOIDDefines(TestCase):
6276 @given(data_strategy())
6277 def runTest(self, d):
6278 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6279 value_name_chosen = d.draw(sampled_from(value_names))
6281 ObjectIdentifier(oid)
6282 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6284 oid_chosen = d.draw(sampled_from(oids))
6285 values = d.draw(lists(
6287 min_size=len(value_names),
6288 max_size=len(value_names),
6291 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6292 oid: Integer() for oid in oids[:-1]
6295 for i, value_name in enumerate(value_names):
6296 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6298 class Seq(Sequence):
6301 for value_name, value in zip(value_names, values):
6302 seq[value_name] = Any(Integer(value).encode())
6303 seq["type"] = oid_chosen
6304 seq, _ = Seq().decode(seq.encode())
6305 for value_name in value_names:
6306 if value_name == value_name_chosen:
6308 self.assertIsNone(seq[value_name].defined)
6309 if value_name_chosen in oids[:-1]:
6310 self.assertIsNotNone(seq[value_name_chosen].defined)
6311 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6312 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6315 pprint(seq, big_blobs=True, with_decode_path=True)
6318 class TestDefinesByPath(TestCase):
6319 def test_generated(self):
6320 class Seq(Sequence):
6322 ("type", ObjectIdentifier()),
6323 ("value", OctetString(expl=tag_ctxc(123))),
6326 class SeqInner(Sequence):
6328 ("typeInner", ObjectIdentifier()),
6329 ("valueInner", Any()),
6332 class PairValue(SetOf):
6335 class Pair(Sequence):
6337 ("type", ObjectIdentifier()),
6338 ("value", PairValue()),
6341 class Pairs(SequenceOf):
6348 type_octet_stringed,
6350 ObjectIdentifier(oid)
6351 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6353 seq_integered = Seq()
6354 seq_integered["type"] = type_integered
6355 seq_integered["value"] = OctetString(Integer(123).encode())
6356 seq_integered_raw = seq_integered.encode()
6360 (type_octet_stringed, OctetString(b"whatever")),
6361 (type_integered, Integer(123)),
6362 (type_octet_stringed, OctetString(b"whenever")),
6363 (type_integered, Integer(234)),
6365 for t, v in pairs_input:
6368 pair["value"] = PairValue((Any(v),))
6370 seq_inner = SeqInner()
6371 seq_inner["typeInner"] = type_innered
6372 seq_inner["valueInner"] = Any(pairs)
6373 seq_sequenced = Seq()
6374 seq_sequenced["type"] = type_sequenced
6375 seq_sequenced["value"] = OctetString(seq_inner.encode())
6376 seq_sequenced_raw = seq_sequenced.encode()
6378 list(seq_sequenced.pps())
6379 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6381 defines_by_path = []
6382 ctx_copied = deepcopy(ctx_dummy)
6383 seq_integered, _ = Seq().decode(
6387 self.assertDictEqual(ctx_copied, ctx_dummy)
6388 self.assertIsNone(seq_integered["value"].defined)
6389 defines_by_path.append(
6390 (("type",), ((("value",), {
6391 type_integered: Integer(),
6392 type_sequenced: SeqInner(),
6395 ctx_copied["defines_by_path"] = defines_by_path
6396 seq_integered, _ = Seq().decode(
6400 del ctx_copied["defines_by_path"]
6401 self.assertDictEqual(ctx_copied, ctx_dummy)
6402 self.assertIsNotNone(seq_integered["value"].defined)
6403 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6404 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6405 self.assertTrue(seq_integered_raw[
6406 seq_integered["value"].defined[1].offset:
6407 ].startswith(Integer(123).encode()))
6409 list(seq_integered.pps())
6410 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6412 ctx_copied["defines_by_path"] = defines_by_path
6413 seq_sequenced, _ = Seq().decode(
6417 del ctx_copied["defines_by_path"]
6418 self.assertDictEqual(ctx_copied, ctx_dummy)
6419 self.assertIsNotNone(seq_sequenced["value"].defined)
6420 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6421 seq_inner = seq_sequenced["value"].defined[1]
6422 self.assertIsNone(seq_inner["valueInner"].defined)
6424 list(seq_sequenced.pps())
6425 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6427 defines_by_path.append((
6428 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6429 ((("valueInner",), {type_innered: Pairs()}),),
6431 ctx_copied["defines_by_path"] = defines_by_path
6432 seq_sequenced, _ = Seq().decode(
6436 del ctx_copied["defines_by_path"]
6437 self.assertDictEqual(ctx_copied, ctx_dummy)
6438 self.assertIsNotNone(seq_sequenced["value"].defined)
6439 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6440 seq_inner = seq_sequenced["value"].defined[1]
6441 self.assertIsNotNone(seq_inner["valueInner"].defined)
6442 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6443 pairs = seq_inner["valueInner"].defined[1]
6445 self.assertIsNone(pair["value"][0].defined)
6447 list(seq_sequenced.pps())
6448 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6450 defines_by_path.append((
6453 DecodePathDefBy(type_sequenced),
6455 DecodePathDefBy(type_innered),
6460 type_integered: Integer(),
6461 type_octet_stringed: OctetString(),
6464 ctx_copied["defines_by_path"] = defines_by_path
6465 seq_sequenced, _ = Seq().decode(
6469 del ctx_copied["defines_by_path"]
6470 self.assertDictEqual(ctx_copied, ctx_dummy)
6471 self.assertIsNotNone(seq_sequenced["value"].defined)
6472 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6473 seq_inner = seq_sequenced["value"].defined[1]
6474 self.assertIsNotNone(seq_inner["valueInner"].defined)
6475 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6476 pairs_got = seq_inner["valueInner"].defined[1]
6477 for pair_input, pair_got in zip(pairs_input, pairs_got):
6478 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6479 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6481 list(seq_sequenced.pps())
6482 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6484 @given(oid_strategy(), integers())
6485 def test_simple(self, oid, tgt):
6486 class Inner(Sequence):
6488 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6489 ObjectIdentifier(oid): Integer(),
6493 class Outer(Sequence):
6496 ("tgt", OctetString()),
6500 inner["oid"] = ObjectIdentifier(oid)
6502 outer["inner"] = inner
6503 outer["tgt"] = OctetString(Integer(tgt).encode())
6504 decoded, _ = Outer().decode(outer.encode())
6505 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6508 class TestAbsDecodePath(TestCase):
6510 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6511 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6513 def test_concat(self, decode_path, rel_path):
6514 self.assertSequenceEqual(
6515 abs_decode_path(decode_path, rel_path),
6516 decode_path + rel_path,
6520 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6521 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6523 def test_abs(self, decode_path, rel_path):
6524 self.assertSequenceEqual(
6525 abs_decode_path(decode_path, ("/",) + rel_path),
6530 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6531 integers(min_value=1, max_value=3),
6532 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6534 def test_dots(self, decode_path, number_of_dots, rel_path):
6535 self.assertSequenceEqual(
6536 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6537 decode_path[:-number_of_dots] + rel_path,
6541 class TestStrictDefaultExistence(TestCase):
6542 @given(data_strategy())
6543 def runTest(self, d):
6544 count = d.draw(integers(min_value=1, max_value=10))
6545 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6547 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6548 for i in range(count)
6550 for klass in (Sequence, Set):
6554 for i in range(count):
6555 seq["int%d" % i] = Integer(123)
6557 chosen_choice = "int%d" % chosen
6558 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6559 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6561 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6562 self.assertTrue(decoded.ber_encoded)
6563 self.assertTrue(decoded.bered)
6564 decoded = copy(decoded)
6565 self.assertTrue(decoded.ber_encoded)
6566 self.assertTrue(decoded.bered)
6567 decoded, _ = seq.decode(raw, ctx={"bered": True})
6568 self.assertTrue(decoded.ber_encoded)
6569 self.assertTrue(decoded.bered)
6570 decoded = copy(decoded)
6571 self.assertTrue(decoded.ber_encoded)
6572 self.assertTrue(decoded.bered)
6575 class TestX690PrefixedType(TestCase):
6577 self.assertSequenceEqual(
6578 VisibleString("Jones").encode(),
6579 hexdec("1A054A6F6E6573"),
6581 self.assertSequenceEqual(
6584 impl=tag_encode(3, klass=TagClassApplication),
6586 hexdec("43054A6F6E6573"),
6588 self.assertSequenceEqual(
6592 impl=tag_encode(3, klass=TagClassApplication),
6596 hexdec("A20743054A6F6E6573"),
6598 self.assertSequenceEqual(
6602 impl=tag_encode(3, klass=TagClassApplication),
6604 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6606 hexdec("670743054A6F6E6573"),
6608 self.assertSequenceEqual(
6609 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6610 hexdec("82054A6F6E6573"),
6614 class TestExplOOB(TestCase):
6616 expl = tag_ctxc(123)
6617 raw = Integer(123).encode() + Integer(234).encode()
6618 raw = b"".join((expl, len_encode(len(raw)), raw))
6619 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6620 Integer(expl=expl).decode(raw)
6621 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
6624 class TestPickleDifferentVersion(TestCase):
6626 pickled = pickle_dumps(Integer(123), pickle_proto)
6628 version_orig = pyderasn.__version__
6629 pyderasn.__version__ += "different"
6630 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
6631 pickle_loads(pickled)
6632 pyderasn.__version__ = version_orig
6633 pickle_loads(pickled)