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(
3719 min_value=self.min_datetime,
3720 max_value=self.max_datetime,
3722 obj = self.base_klass(value)
3723 self.assertTrue(obj.ready)
3726 pprint(obj, big_blobs=True, with_decode_path=True)
3728 @given(data_strategy())
3729 def test_comparison(self, d):
3730 value1 = d.draw(datetimes(
3731 min_value=self.min_datetime,
3732 max_value=self.max_datetime,
3734 value2 = d.draw(datetimes(
3735 min_value=self.min_datetime,
3736 max_value=self.max_datetime,
3738 tag1 = d.draw(binary(min_size=1))
3739 tag2 = d.draw(binary(min_size=1))
3741 value1 = value1.replace(microsecond=0)
3742 value2 = value2.replace(microsecond=0)
3743 obj1 = self.base_klass(value1)
3744 obj2 = self.base_klass(value2)
3745 self.assertEqual(obj1 == obj2, value1 == value2)
3746 self.assertEqual(obj1 != obj2, value1 != value2)
3747 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3748 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3749 obj1 = self.base_klass(value1, impl=tag1)
3750 obj2 = self.base_klass(value1, impl=tag2)
3751 self.assertEqual(obj1 == obj2, tag1 == tag2)
3752 self.assertEqual(obj1 != obj2, tag1 != tag2)
3754 @given(data_strategy())
3755 def test_call(self, d):
3763 ) = d.draw(generalized_time_values_strategy(
3764 min_datetime=self.min_datetime,
3765 max_datetime=self.max_datetime,
3766 omit_ms=self.omit_ms,
3768 obj_initial = self.base_klass(
3769 value=value_initial,
3772 default=default_initial,
3773 optional=optional_initial or False,
3774 _decoded=_decoded_initial,
3783 ) = d.draw(generalized_time_values_strategy(
3784 min_datetime=self.min_datetime,
3785 max_datetime=self.max_datetime,
3786 omit_ms=self.omit_ms,
3787 do_expl=impl_initial is None,
3797 value_expected = default if value is None else value
3799 default_initial if value_expected is None
3802 self.assertEqual(obj, value_expected)
3803 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3804 self.assertEqual(obj.expl_tag, expl or expl_initial)
3807 default_initial if default is None else default,
3809 if obj.default is None:
3810 optional = optional_initial if optional is None else optional
3811 optional = False if optional is None else optional
3814 self.assertEqual(obj.optional, optional)
3816 @given(data_strategy())
3817 def test_copy(self, d):
3818 values = d.draw(generalized_time_values_strategy(
3819 min_datetime=self.min_datetime,
3820 max_datetime=self.max_datetime,
3822 obj = self.base_klass(*values)
3823 for copy_func in copy_funcs:
3824 obj_copied = copy_func(obj)
3825 self.assert_copied_basic_fields(obj, obj_copied)
3826 self.assertEqual(obj._value, obj_copied._value)
3828 @given(data_strategy())
3829 def test_stripped(self, d):
3830 value = d.draw(datetimes(
3831 min_value=self.min_datetime,
3832 max_value=self.max_datetime,
3834 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3835 obj = self.base_klass(value, impl=tag_impl)
3836 with self.assertRaises(NotEnoughData):
3837 obj.decode(obj.encode()[:-1])
3839 @given(data_strategy())
3840 def test_stripped_expl(self, d):
3841 value = d.draw(datetimes(
3842 min_value=self.min_datetime,
3843 max_value=self.max_datetime,
3845 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3846 obj = self.base_klass(value, expl=tag_expl)
3847 with self.assertRaises(NotEnoughData):
3848 obj.decode(obj.encode()[:-1])
3850 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3851 @given(data_strategy())
3852 def test_symmetric(self, d):
3853 values = d.draw(generalized_time_values_strategy(
3854 min_datetime=self.min_datetime,
3855 max_datetime=self.max_datetime,
3857 value = d.draw(datetimes(
3858 min_value=self.min_datetime,
3859 max_value=self.max_datetime,
3861 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3862 offset = d.draw(integers(min_value=0))
3863 tail_junk = d.draw(binary(max_size=5))
3864 _, _, _, default, optional, _decoded = values
3865 obj = self.base_klass(
3873 pprint(obj, big_blobs=True, with_decode_path=True)
3874 self.assertFalse(obj.expled)
3875 obj_encoded = obj.encode()
3876 self.additional_symmetric_check(value, obj_encoded)
3877 obj_expled = obj(value, expl=tag_expl)
3878 self.assertTrue(obj_expled.expled)
3880 list(obj_expled.pps())
3881 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3882 obj_expled_encoded = obj_expled.encode()
3883 ctx_copied = deepcopy(ctx_dummy)
3884 obj_decoded, tail = obj_expled.decode(
3885 obj_expled_encoded + tail_junk,
3889 self.assertDictEqual(ctx_copied, ctx_dummy)
3891 list(obj_decoded.pps())
3892 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3893 self.assertEqual(tail, tail_junk)
3894 self.assertEqual(obj_decoded, obj_expled)
3895 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3896 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3897 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3898 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3899 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3901 obj_decoded.expl_llen,
3902 len(len_encode(len(obj_encoded))),
3904 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3905 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3908 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3910 self.assertEqual(obj_decoded.expl_offset, offset)
3911 assert_exceeding_data(
3913 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3918 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3919 base_klass = GeneralizedTime
3921 min_datetime = datetime(1900, 1, 1)
3922 max_datetime = datetime(9999, 12, 31)
3924 def additional_symmetric_check(self, value, obj_encoded):
3925 if value.microsecond > 0:
3926 self.assertFalse(obj_encoded.endswith(b"0Z"))
3928 def test_x690_vector_valid(self):
3932 b"19920722132100.3Z",
3934 GeneralizedTime(data)
3936 def test_x690_vector_invalid(self):
3939 b"19920622123421.0Z",
3940 b"19920722132100.30Z",
3942 with self.assertRaises(DecodeError) as err:
3943 GeneralizedTime(data)
3946 def test_go_vectors_invalid(self):
3958 b"-20100102030410Z",
3959 b"2010-0102030410Z",
3960 b"2010-0002030410Z",
3961 b"201001-02030410Z",
3962 b"20100102-030410Z",
3963 b"2010010203-0410Z",
3964 b"201001020304-10Z",
3965 # These ones are INVALID in *DER*, but accepted
3966 # by Go's encoding/asn1
3967 b"20100102030405+0607",
3968 b"20100102030405-0607",
3970 with self.assertRaises(DecodeError) as err:
3971 GeneralizedTime(data)
3974 def test_go_vectors_valid(self):
3976 GeneralizedTime(b"20100102030405Z").todatetime(),
3977 datetime(2010, 1, 2, 3, 4, 5, 0),
3982 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3983 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3985 binary(min_size=1, max_size=1),
3987 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3988 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3991 def test_junk(self, part0, part1, part2):
3992 junk = part0 + part1 + part2
3993 assume(not (set(junk) <= set(digits.encode("ascii"))))
3994 with self.assertRaises(DecodeError):
3995 GeneralizedTime().decode(
3996 GeneralizedTime.tag_default +
3997 len_encode(len(junk)) +
4003 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4004 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4006 binary(min_size=1, max_size=1),
4008 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4009 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4012 def test_junk_dm(self, part0, part1, part2):
4013 junk = part0 + part1 + part2
4014 assume(not (set(junk) <= set(digits.encode("ascii"))))
4015 with self.assertRaises(DecodeError):
4016 GeneralizedTime().decode(
4017 GeneralizedTime.tag_default +
4018 len_encode(len(junk)) +
4022 def test_ns_fractions(self):
4023 GeneralizedTime(b"20010101000000.000001Z")
4024 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
4025 GeneralizedTime(b"20010101000000.0000001Z")
4028 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4029 base_klass = UTCTime
4031 min_datetime = datetime(2000, 1, 1)
4032 max_datetime = datetime(2049, 12, 31)
4034 def additional_symmetric_check(self, value, obj_encoded):
4037 def test_x690_vector_valid(self):
4045 def test_x690_vector_invalid(self):
4050 with self.assertRaises(DecodeError) as err:
4054 def test_go_vectors_invalid(self):
4080 # These ones are INVALID in *DER*, but accepted
4081 # by Go's encoding/asn1
4082 b"910506164540-0700",
4083 b"910506164540+0730",
4087 with self.assertRaises(DecodeError) as err:
4091 def test_go_vectors_valid(self):
4093 UTCTime(b"910506234540Z").todatetime(),
4094 datetime(1991, 5, 6, 23, 45, 40, 0),
4097 @given(integers(min_value=0, max_value=49))
4098 def test_pre50(self, year):
4100 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4104 @given(integers(min_value=50, max_value=99))
4105 def test_post50(self, year):
4107 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4113 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4114 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4116 binary(min_size=1, max_size=1),
4118 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4119 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4122 def test_junk(self, part0, part1, part2):
4123 junk = part0 + part1 + part2
4124 assume(not (set(junk) <= set(digits.encode("ascii"))))
4125 with self.assertRaises(DecodeError):
4127 UTCTime.tag_default +
4128 len_encode(len(junk)) +
4134 def any_values_strategy(draw, do_expl=False):
4135 value = draw(one_of(none(), binary()))
4138 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4139 optional = draw(one_of(none(), booleans()))
4141 draw(integers(min_value=0)),
4142 draw(integers(min_value=0)),
4143 draw(integers(min_value=0)),
4145 return (value, expl, optional, _decoded)
4148 class AnyInherited(Any):
4152 class TestAny(CommonMixin, TestCase):
4155 def test_invalid_value_type(self):
4156 with self.assertRaises(InvalidValueType) as err:
4161 def test_optional(self, optional):
4162 obj = Any(optional=optional)
4163 self.assertEqual(obj.optional, optional)
4166 def test_ready(self, value):
4168 self.assertFalse(obj.ready)
4171 pprint(obj, big_blobs=True, with_decode_path=True)
4172 with self.assertRaises(ObjNotReady) as err:
4176 self.assertTrue(obj.ready)
4179 pprint(obj, big_blobs=True, with_decode_path=True)
4182 def test_basic(self, value):
4183 integer_encoded = Integer(value).encode()
4185 Any(integer_encoded),
4186 Any(Integer(value)),
4187 Any(Any(Integer(value))),
4189 self.assertSequenceEqual(bytes(obj), integer_encoded)
4191 obj.decode(obj.encode())[0].vlen,
4192 len(integer_encoded),
4196 pprint(obj, big_blobs=True, with_decode_path=True)
4197 self.assertSequenceEqual(obj.encode(), integer_encoded)
4199 @given(binary(), binary())
4200 def test_comparison(self, value1, value2):
4201 for klass in (Any, AnyInherited):
4202 obj1 = klass(value1)
4203 obj2 = klass(value2)
4204 self.assertEqual(obj1 == obj2, value1 == value2)
4205 self.assertEqual(obj1 != obj2, value1 != value2)
4206 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4208 @given(data_strategy())
4209 def test_call(self, d):
4210 for klass in (Any, AnyInherited):
4216 ) = d.draw(any_values_strategy())
4217 obj_initial = klass(
4220 optional_initial or False,
4228 ) = d.draw(any_values_strategy(do_expl=True))
4229 obj = obj_initial(value, expl, optional)
4231 value_expected = None if value is None else value
4232 self.assertEqual(obj, value_expected)
4233 self.assertEqual(obj.expl_tag, expl or expl_initial)
4234 if obj.default is None:
4235 optional = optional_initial if optional is None else optional
4236 optional = False if optional is None else optional
4237 self.assertEqual(obj.optional, optional)
4239 def test_simultaneous_impl_expl(self):
4240 # override it, as Any does not have implicit tag
4243 def test_decoded(self):
4244 # override it, as Any does not have implicit tag
4247 @given(any_values_strategy())
4248 def test_copy(self, values):
4249 for klass in (Any, AnyInherited):
4250 obj = klass(*values)
4251 for copy_func in copy_funcs:
4252 obj_copied = copy_func(obj)
4253 self.assert_copied_basic_fields(obj, obj_copied)
4254 self.assertEqual(obj._value, obj_copied._value)
4256 @given(binary().map(OctetString))
4257 def test_stripped(self, value):
4259 with self.assertRaises(NotEnoughData):
4260 obj.decode(obj.encode()[:-1])
4264 integers(min_value=1).map(tag_ctxc),
4266 def test_stripped_expl(self, value, tag_expl):
4267 obj = Any(value, expl=tag_expl)
4268 with self.assertRaises(NotEnoughData):
4269 obj.decode(obj.encode()[:-1])
4272 integers(min_value=31),
4273 integers(min_value=0),
4276 def test_bad_tag(self, tag, offset, decode_path):
4277 with self.assertRaises(DecodeError) as err:
4279 tag_encode(tag)[:-1],
4281 decode_path=decode_path,
4284 self.assertEqual(err.exception.offset, offset)
4285 self.assertEqual(err.exception.decode_path, decode_path)
4288 integers(min_value=128),
4289 integers(min_value=0),
4292 def test_bad_len(self, l, offset, decode_path):
4293 with self.assertRaises(DecodeError) as err:
4295 Any.tag_default + len_encode(l)[:-1],
4297 decode_path=decode_path,
4300 self.assertEqual(err.exception.offset, offset)
4301 self.assertEqual(err.exception.decode_path, decode_path)
4303 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4305 any_values_strategy(),
4306 integers().map(lambda x: Integer(x).encode()),
4307 integers(min_value=1).map(tag_ctxc),
4308 integers(min_value=0),
4311 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4312 for klass in (Any, AnyInherited):
4313 _, _, optional, _decoded = values
4314 obj = klass(value=value, optional=optional, _decoded=_decoded)
4317 pprint(obj, big_blobs=True, with_decode_path=True)
4318 self.assertFalse(obj.expled)
4319 obj_encoded = obj.encode()
4320 obj_expled = obj(value, expl=tag_expl)
4321 self.assertTrue(obj_expled.expled)
4323 list(obj_expled.pps())
4324 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4325 obj_expled_encoded = obj_expled.encode()
4326 ctx_copied = deepcopy(ctx_dummy)
4327 obj_decoded, tail = obj_expled.decode(
4328 obj_expled_encoded + tail_junk,
4332 self.assertDictEqual(ctx_copied, ctx_dummy)
4334 list(obj_decoded.pps())
4335 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4336 self.assertEqual(tail, tail_junk)
4337 self.assertEqual(obj_decoded, obj_expled)
4338 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4339 self.assertEqual(bytes(obj_decoded), bytes(obj))
4340 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4341 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4342 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4344 obj_decoded.expl_llen,
4345 len(len_encode(len(obj_encoded))),
4347 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4348 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4351 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4353 self.assertEqual(obj_decoded.expl_offset, offset)
4354 self.assertEqual(obj_decoded.tlen, 0)
4355 self.assertEqual(obj_decoded.llen, 0)
4356 self.assertEqual(obj_decoded.vlen, len(value))
4357 assert_exceeding_data(
4359 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4364 integers(min_value=1).map(tag_ctxc),
4365 integers(min_value=0, max_value=3),
4366 integers(min_value=0),
4370 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4371 chunk = Boolean(False, expl=expl).encode()
4373 OctetString.tag_default +
4375 b"".join([chunk] * chunks) +
4378 with self.assertRaises(LenIndefForm):
4382 decode_path=decode_path,
4384 obj, tail = Any().decode(
4387 decode_path=decode_path,
4388 ctx={"bered": True},
4390 self.assertSequenceEqual(tail, junk)
4391 self.assertEqual(obj.offset, offset)
4392 self.assertEqual(obj.tlvlen, len(encoded))
4393 self.assertTrue(obj.lenindef)
4394 self.assertFalse(obj.ber_encoded)
4395 self.assertTrue(obj.bered)
4397 self.assertTrue(obj.lenindef)
4398 self.assertFalse(obj.ber_encoded)
4399 self.assertTrue(obj.bered)
4402 pprint(obj, big_blobs=True, with_decode_path=True)
4403 with self.assertRaises(NotEnoughData) as err:
4407 decode_path=decode_path,
4408 ctx={"bered": True},
4410 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4411 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4413 class SeqOf(SequenceOf):
4414 schema = Boolean(expl=expl)
4416 class Seq(Sequence):
4418 ("type", ObjectIdentifier(defines=((("value",), {
4419 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4424 ("type", ObjectIdentifier("1.2.3")),
4425 ("value", Any(encoded)),
4427 seq_encoded = seq.encode()
4428 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4429 self.assertIsNotNone(seq_decoded["value"].defined)
4431 list(seq_decoded.pps())
4432 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4433 self.assertTrue(seq_decoded.bered)
4434 self.assertFalse(seq_decoded["type"].bered)
4435 self.assertTrue(seq_decoded["value"].bered)
4437 chunk = chunk[:-1] + b"\x01"
4438 chunks = b"".join([chunk] * (chunks + 1))
4439 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4441 ("type", ObjectIdentifier("1.2.3")),
4442 ("value", Any(encoded)),
4444 seq_encoded = seq.encode()
4445 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4446 self.assertIsNotNone(seq_decoded["value"].defined)
4448 list(seq_decoded.pps())
4449 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4450 self.assertTrue(seq_decoded.bered)
4451 self.assertFalse(seq_decoded["type"].bered)
4452 self.assertTrue(seq_decoded["value"].bered)
4456 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4458 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4459 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4461 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4462 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4464 min_size=len(names),
4465 max_size=len(names),
4468 (name, Integer(**tag_kwargs))
4469 for name, tag_kwargs in zip(names, tags)
4472 if value_required or draw(booleans()):
4473 value = draw(tuples(
4474 sampled_from([name for name, _ in schema]),
4475 integers().map(Integer),
4479 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4480 default = draw(one_of(
4482 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4484 optional = draw(one_of(none(), booleans()))
4486 draw(integers(min_value=0)),
4487 draw(integers(min_value=0)),
4488 draw(integers(min_value=0)),
4490 return (schema, value, expl, default, optional, _decoded)
4493 class ChoiceInherited(Choice):
4497 class TestChoice(CommonMixin, TestCase):
4499 schema = (("whatever", Boolean()),)
4502 def test_schema_required(self):
4503 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4506 def test_impl_forbidden(self):
4507 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4508 Choice(impl=b"whatever")
4510 def test_invalid_value_type(self):
4511 with self.assertRaises(InvalidValueType) as err:
4512 self.base_klass(123)
4514 with self.assertRaises(ObjUnknown) as err:
4515 self.base_klass(("whenever", Boolean(False)))
4517 with self.assertRaises(InvalidValueType) as err:
4518 self.base_klass(("whatever", Integer(123)))
4522 def test_optional(self, optional):
4523 obj = self.base_klass(
4524 default=self.base_klass(("whatever", Boolean(False))),
4527 self.assertTrue(obj.optional)
4530 def test_ready(self, value):
4531 obj = self.base_klass()
4532 self.assertFalse(obj.ready)
4535 pprint(obj, big_blobs=True, with_decode_path=True)
4536 self.assertIsNone(obj["whatever"])
4537 with self.assertRaises(ObjNotReady) as err:
4540 obj["whatever"] = Boolean()
4541 self.assertFalse(obj.ready)
4544 pprint(obj, big_blobs=True, with_decode_path=True)
4545 obj["whatever"] = Boolean(value)
4546 self.assertTrue(obj.ready)
4549 pprint(obj, big_blobs=True, with_decode_path=True)
4551 @given(booleans(), booleans())
4552 def test_comparison(self, value1, value2):
4553 class WahlInherited(self.base_klass):
4555 for klass in (self.base_klass, WahlInherited):
4556 obj1 = klass(("whatever", Boolean(value1)))
4557 obj2 = klass(("whatever", Boolean(value2)))
4558 self.assertEqual(obj1 == obj2, value1 == value2)
4559 self.assertEqual(obj1 != obj2, value1 != value2)
4560 self.assertEqual(obj1 == obj2._value, value1 == value2)
4561 self.assertFalse(obj1 == obj2._value[1])
4563 @given(data_strategy())
4564 def test_call(self, d):
4565 for klass in (Choice, ChoiceInherited):
4573 ) = d.draw(choice_values_strategy())
4576 schema = schema_initial
4578 value=value_initial,
4580 default=default_initial,
4581 optional=optional_initial or False,
4582 _decoded=_decoded_initial,
4591 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4592 obj = obj_initial(value, expl, default, optional)
4594 value_expected = default if value is None else value
4596 default_initial if value_expected is None
4599 self.assertEqual(obj.choice, value_expected[0])
4600 self.assertEqual(obj.value, int(value_expected[1]))
4601 self.assertEqual(obj.expl_tag, expl or expl_initial)
4602 default_expect = default_initial if default is None else default
4603 if default_expect is not None:
4604 self.assertEqual(obj.default.choice, default_expect[0])
4605 self.assertEqual(obj.default.value, int(default_expect[1]))
4606 if obj.default is None:
4607 optional = optional_initial if optional is None else optional
4608 optional = False if optional is None else optional
4611 self.assertEqual(obj.optional, optional)
4612 self.assertEqual(obj.specs, obj_initial.specs)
4614 def test_simultaneous_impl_expl(self):
4615 # override it, as Any does not have implicit tag
4618 def test_decoded(self):
4619 # override it, as Any does not have implicit tag
4622 @given(choice_values_strategy())
4623 def test_copy(self, values):
4624 _schema, value, expl, default, optional, _decoded = values
4626 class Wahl(self.base_klass):
4628 register_class(Wahl)
4633 optional=optional or False,
4636 for copy_func in copy_funcs:
4637 obj_copied = copy_func(obj)
4638 self.assertIsNone(obj.tag)
4639 self.assertIsNone(obj_copied.tag)
4640 # hack for assert_copied_basic_fields
4641 obj.tag = "whatever"
4642 obj_copied.tag = "whatever"
4643 self.assert_copied_basic_fields(obj, obj_copied)
4645 self.assertEqual(obj._value, obj_copied._value)
4646 self.assertEqual(obj.specs, obj_copied.specs)
4649 def test_stripped(self, value):
4650 obj = self.base_klass(("whatever", Boolean(value)))
4651 with self.assertRaises(NotEnoughData):
4652 obj.decode(obj.encode()[:-1])
4656 integers(min_value=1).map(tag_ctxc),
4658 def test_stripped_expl(self, value, tag_expl):
4659 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4660 with self.assertRaises(NotEnoughData):
4661 obj.decode(obj.encode()[:-1])
4663 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4664 @given(data_strategy())
4665 def test_symmetric(self, d):
4666 _schema, value, _, default, optional, _decoded = d.draw(
4667 choice_values_strategy(value_required=True)
4669 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4670 offset = d.draw(integers(min_value=0))
4671 tail_junk = d.draw(binary(max_size=5))
4673 class Wahl(self.base_klass):
4683 pprint(obj, big_blobs=True, with_decode_path=True)
4684 self.assertFalse(obj.expled)
4685 obj_encoded = obj.encode()
4686 obj_expled = obj(value, expl=tag_expl)
4687 self.assertTrue(obj_expled.expled)
4689 list(obj_expled.pps())
4690 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4691 obj_expled_encoded = obj_expled.encode()
4692 ctx_copied = deepcopy(ctx_dummy)
4693 obj_decoded, tail = obj_expled.decode(
4694 obj_expled_encoded + tail_junk,
4698 self.assertDictEqual(ctx_copied, ctx_dummy)
4700 list(obj_decoded.pps())
4701 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4702 self.assertEqual(tail, tail_junk)
4703 self.assertEqual(obj_decoded, obj_expled)
4704 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4705 self.assertEqual(obj_decoded.value, obj_expled.value)
4706 self.assertEqual(obj_decoded.choice, obj.choice)
4707 self.assertEqual(obj_decoded.value, obj.value)
4708 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4709 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4710 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4712 obj_decoded.expl_llen,
4713 len(len_encode(len(obj_encoded))),
4715 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4716 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4719 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4721 self.assertEqual(obj_decoded.expl_offset, offset)
4722 self.assertSequenceEqual(
4724 obj_decoded.value.fulloffset - offset:
4725 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4729 assert_exceeding_data(
4731 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4736 def test_set_get(self, value):
4739 ("erste", Boolean()),
4740 ("zweite", Integer()),
4743 with self.assertRaises(ObjUnknown) as err:
4744 obj["whatever"] = "whenever"
4745 with self.assertRaises(InvalidValueType) as err:
4746 obj["zweite"] = Boolean(False)
4747 obj["zweite"] = Integer(value)
4749 with self.assertRaises(ObjUnknown) as err:
4752 self.assertIsNone(obj["erste"])
4753 self.assertEqual(obj["zweite"], Integer(value))
4755 def test_tag_mismatch(self):
4758 ("erste", Boolean()),
4760 int_encoded = Integer(123).encode()
4761 bool_encoded = Boolean(False).encode()
4763 obj.decode(bool_encoded)
4764 with self.assertRaises(TagMismatch):
4765 obj.decode(int_encoded)
4767 def test_tag_mismatch_underlying(self):
4768 class SeqOfBoolean(SequenceOf):
4771 class SeqOfInteger(SequenceOf):
4776 ("erste", SeqOfBoolean()),
4779 int_encoded = SeqOfInteger((Integer(123),)).encode()
4780 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4782 obj.decode(bool_encoded)
4783 with self.assertRaises(TagMismatch) as err:
4784 obj.decode(int_encoded)
4785 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4789 def seq_values_strategy(draw, seq_klass, do_expl=False):
4791 if draw(booleans()):
4793 value._value = draw(dictionaries(
4796 booleans().map(Boolean),
4797 integers().map(Integer),
4801 if draw(booleans()):
4802 schema = list(draw(dictionaries(
4805 booleans().map(Boolean),
4806 integers().map(Integer),
4812 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4814 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4816 if draw(booleans()):
4817 default = seq_klass()
4818 default._value = draw(dictionaries(
4821 booleans().map(Boolean),
4822 integers().map(Integer),
4825 optional = draw(one_of(none(), booleans()))
4827 draw(integers(min_value=0)),
4828 draw(integers(min_value=0)),
4829 draw(integers(min_value=0)),
4831 return (value, schema, impl, expl, default, optional, _decoded)
4835 def sequence_strategy(draw, seq_klass):
4836 inputs = draw(lists(
4838 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4839 tuples(just(Integer), integers(), one_of(none(), integers())),
4844 integers(min_value=1),
4845 min_size=len(inputs),
4846 max_size=len(inputs),
4849 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4850 for tag, expled in zip(tags, draw(lists(
4852 min_size=len(inputs),
4853 max_size=len(inputs),
4857 for i, optional in enumerate(draw(lists(
4858 sampled_from(("required", "optional", "empty")),
4859 min_size=len(inputs),
4860 max_size=len(inputs),
4862 if optional in ("optional", "empty"):
4863 inits[i]["optional"] = True
4864 if optional == "empty":
4866 empties = set(empties)
4867 names = list(draw(sets(
4869 min_size=len(inputs),
4870 max_size=len(inputs),
4873 for i, (klass, value, default) in enumerate(inputs):
4874 schema.append((names[i], klass(default=default, **inits[i])))
4875 seq_name = draw(text_letters())
4876 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4879 for i, (klass, value, default) in enumerate(inputs):
4886 "default_value": None if spec.default is None else default,
4890 expect["optional"] = True
4892 expect["presented"] = True
4893 expect["value"] = value
4895 expect["optional"] = True
4896 if default is not None and default == value:
4897 expect["presented"] = False
4898 seq[name] = klass(value)
4899 expects.append(expect)
4904 def sequences_strategy(draw, seq_klass):
4905 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4907 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4908 for tag, expled in zip(tags, draw(lists(
4915 i for i, is_default in enumerate(draw(lists(
4921 names = list(draw(sets(
4926 seq_expectses = draw(lists(
4927 sequence_strategy(seq_klass=seq_klass),
4931 seqs = [seq for seq, _ in seq_expectses]
4933 for i, (name, seq) in enumerate(zip(names, seqs)):
4936 seq(default=(seq if i in defaulted else None), **inits[i]),
4938 seq_name = draw(text_letters())
4939 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4942 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4945 "expects": expects_inner,
4948 seq_outer[name] = seq_inner
4949 if seq_outer.specs[name].default is None:
4950 expect["presented"] = True
4951 expect_outers.append(expect)
4952 return seq_outer, expect_outers
4955 class SeqMixing(object):
4956 def test_invalid_value_type(self):
4957 with self.assertRaises(InvalidValueType) as err:
4958 self.base_klass(123)
4961 def test_invalid_value_type_set(self):
4962 class Seq(self.base_klass):
4963 schema = (("whatever", Boolean()),)
4965 with self.assertRaises(InvalidValueType) as err:
4966 seq["whatever"] = Integer(123)
4970 def test_optional(self, optional):
4971 obj = self.base_klass(default=self.base_klass(), optional=optional)
4972 self.assertTrue(obj.optional)
4974 @given(data_strategy())
4975 def test_ready(self, d):
4977 str(i): v for i, v in enumerate(d.draw(lists(
4984 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4991 for name in d.draw(permutations(
4992 list(ready.keys()) + list(non_ready.keys()),
4994 schema_input.append((name, Boolean()))
4996 class Seq(self.base_klass):
4997 schema = tuple(schema_input)
4999 for name in ready.keys():
5001 seq[name] = Boolean()
5002 self.assertFalse(seq.ready)
5005 pprint(seq, big_blobs=True, with_decode_path=True)
5006 for name, value in ready.items():
5007 seq[name] = Boolean(value)
5008 self.assertFalse(seq.ready)
5011 pprint(seq, big_blobs=True, with_decode_path=True)
5012 with self.assertRaises(ObjNotReady) as err:
5015 for name, value in non_ready.items():
5016 seq[name] = Boolean(value)
5017 self.assertTrue(seq.ready)
5020 pprint(seq, big_blobs=True, with_decode_path=True)
5022 @given(data_strategy())
5023 def test_call(self, d):
5024 class SeqInherited(self.base_klass):
5026 for klass in (self.base_klass, SeqInherited):
5035 ) = d.draw(seq_values_strategy(seq_klass=klass))
5036 obj_initial = klass(
5042 optional_initial or False,
5053 ) = d.draw(seq_values_strategy(
5055 do_expl=impl_initial is None,
5057 obj = obj_initial(value, impl, expl, default, optional)
5058 value_expected = default if value is None else value
5060 default_initial if value_expected is None
5063 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5064 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5065 self.assertEqual(obj.expl_tag, expl or expl_initial)
5067 {} if obj.default is None else obj.default._value,
5068 getattr(default_initial if default is None else default, "_value", {}),
5070 if obj.default is None:
5071 optional = optional_initial if optional is None else optional
5072 optional = False if optional is None else optional
5075 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5076 self.assertEqual(obj.optional, optional)
5078 @given(data_strategy())
5079 def test_copy(self, d):
5080 class SeqInherited(self.base_klass):
5082 register_class(SeqInherited)
5083 for klass in (self.base_klass, SeqInherited):
5084 values = d.draw(seq_values_strategy(seq_klass=klass))
5085 obj = klass(*values)
5086 for copy_func in copy_funcs:
5087 obj_copied = copy_func(obj)
5088 self.assert_copied_basic_fields(obj, obj_copied)
5089 self.assertEqual(obj.specs, obj_copied.specs)
5090 self.assertEqual(obj._value, obj_copied._value)
5092 @given(data_strategy())
5093 def test_stripped(self, d):
5094 value = d.draw(integers())
5095 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5097 class Seq(self.base_klass):
5099 schema = (("whatever", Integer()),)
5101 seq["whatever"] = Integer(value)
5102 with self.assertRaises(NotEnoughData):
5103 seq.decode(seq.encode()[:-1])
5105 @given(data_strategy())
5106 def test_stripped_expl(self, d):
5107 value = d.draw(integers())
5108 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5110 class Seq(self.base_klass):
5112 schema = (("whatever", Integer()),)
5114 seq["whatever"] = Integer(value)
5115 with self.assertRaises(NotEnoughData):
5116 seq.decode(seq.encode()[:-1])
5118 @given(binary(min_size=2))
5119 def test_non_tag_mismatch_raised(self, junk):
5121 _, _, len_encoded = tag_strip(memoryview(junk))
5122 len_decode(len_encoded)
5128 class Seq(self.base_klass):
5130 ("whatever", Integer()),
5132 ("whenever", Integer()),
5135 seq["whatever"] = Integer(123)
5136 seq["junk"] = Any(junk)
5137 seq["whenever"] = Integer(123)
5138 with self.assertRaises(DecodeError):
5139 seq.decode(seq.encode())
5142 integers(min_value=31),
5143 integers(min_value=0),
5146 def test_bad_tag(self, tag, offset, decode_path):
5147 with self.assertRaises(DecodeError) as err:
5148 self.base_klass().decode(
5149 tag_encode(tag)[:-1],
5151 decode_path=decode_path,
5154 self.assertEqual(err.exception.offset, offset)
5155 self.assertEqual(err.exception.decode_path, decode_path)
5158 integers(min_value=128),
5159 integers(min_value=0),
5162 def test_bad_len(self, l, offset, decode_path):
5163 with self.assertRaises(DecodeError) as err:
5164 self.base_klass().decode(
5165 self.base_klass.tag_default + len_encode(l)[:-1],
5167 decode_path=decode_path,
5170 self.assertEqual(err.exception.offset, offset)
5171 self.assertEqual(err.exception.decode_path, decode_path)
5173 def _assert_expects(self, seq, expects):
5174 for expect in expects:
5176 seq.specs[expect["name"]].optional,
5179 if expect["default_value"] is not None:
5181 seq.specs[expect["name"]].default,
5182 expect["default_value"],
5184 if expect["presented"]:
5185 self.assertIn(expect["name"], seq)
5186 self.assertEqual(seq[expect["name"]], expect["value"])
5188 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5189 @given(data_strategy())
5190 def test_symmetric(self, d):
5191 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5192 tail_junk = d.draw(binary(max_size=5))
5193 self.assertTrue(seq.ready)
5194 self.assertFalse(seq.decoded)
5195 self._assert_expects(seq, expects)
5198 pprint(seq, big_blobs=True, with_decode_path=True)
5199 self.assertTrue(seq.ready)
5200 seq_encoded = seq.encode()
5201 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5202 self.assertFalse(seq_decoded.lenindef)
5203 self.assertFalse(seq_decoded.ber_encoded)
5204 self.assertFalse(seq_decoded.bered)
5206 t, _, lv = tag_strip(seq_encoded)
5207 _, _, v = len_decode(lv)
5208 seq_encoded_lenindef = t + LENINDEF + v + EOC
5209 ctx_copied = deepcopy(ctx_dummy)
5210 ctx_copied["bered"] = True
5211 seq_decoded_lenindef, tail_lenindef = seq.decode(
5212 seq_encoded_lenindef + tail_junk,
5215 del ctx_copied["bered"]
5216 self.assertDictEqual(ctx_copied, ctx_dummy)
5217 self.assertTrue(seq_decoded_lenindef.lenindef)
5218 self.assertTrue(seq_decoded_lenindef.bered)
5219 seq_decoded_lenindef = copy(seq_decoded_lenindef)
5220 self.assertTrue(seq_decoded_lenindef.lenindef)
5221 self.assertTrue(seq_decoded_lenindef.bered)
5222 with self.assertRaises(DecodeError):
5223 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5224 with self.assertRaises(DecodeError):
5225 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5226 repr(seq_decoded_lenindef)
5227 list(seq_decoded_lenindef.pps())
5228 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5229 self.assertTrue(seq_decoded_lenindef.ready)
5231 for decoded, decoded_tail, encoded in (
5232 (seq_decoded, tail, seq_encoded),
5233 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5235 self.assertEqual(decoded_tail, tail_junk)
5236 self._assert_expects(decoded, expects)
5237 self.assertEqual(seq, decoded)
5238 self.assertEqual(decoded.encode(), seq_encoded)
5239 self.assertEqual(decoded.tlvlen, len(encoded))
5240 for expect in expects:
5241 if not expect["presented"]:
5242 self.assertNotIn(expect["name"], decoded)
5244 self.assertIn(expect["name"], decoded)
5245 obj = decoded[expect["name"]]
5246 self.assertTrue(obj.decoded)
5247 offset = obj.expl_offset if obj.expled else obj.offset
5248 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5249 self.assertSequenceEqual(
5250 seq_encoded[offset:offset + tlvlen],
5254 assert_exceeding_data(
5256 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
5260 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5261 @given(data_strategy())
5262 def test_symmetric_with_seq(self, d):
5263 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5264 self.assertTrue(seq.ready)
5265 seq_encoded = seq.encode()
5266 seq_decoded, tail = seq.decode(seq_encoded)
5267 self.assertEqual(tail, b"")
5268 self.assertTrue(seq.ready)
5269 self.assertEqual(seq, seq_decoded)
5270 self.assertEqual(seq_decoded.encode(), seq_encoded)
5271 for expect_outer in expect_outers:
5272 if not expect_outer["presented"]:
5273 self.assertNotIn(expect_outer["name"], seq_decoded)
5275 self.assertIn(expect_outer["name"], seq_decoded)
5276 obj = seq_decoded[expect_outer["name"]]
5277 self.assertTrue(obj.decoded)
5278 offset = obj.expl_offset if obj.expled else obj.offset
5279 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5280 self.assertSequenceEqual(
5281 seq_encoded[offset:offset + tlvlen],
5284 self._assert_expects(obj, expect_outer["expects"])
5286 @given(data_strategy())
5287 def test_default_disappears(self, d):
5288 _schema = list(d.draw(dictionaries(
5290 sets(integers(), min_size=2, max_size=2),
5294 class Seq(self.base_klass):
5296 (n, Integer(default=d))
5297 for n, (_, d) in _schema
5300 for name, (value, _) in _schema:
5301 seq[name] = Integer(value)
5302 self.assertEqual(len(seq._value), len(_schema))
5303 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5304 self.assertGreater(len(seq.encode()), len(empty_seq))
5305 for name, (_, default) in _schema:
5306 seq[name] = Integer(default)
5307 self.assertEqual(len(seq._value), 0)
5308 self.assertSequenceEqual(seq.encode(), empty_seq)
5310 @given(data_strategy())
5311 def test_encoded_default_not_accepted(self, d):
5312 _schema = list(d.draw(dictionaries(
5317 tags = [tag_encode(tag) for tag in d.draw(sets(
5318 integers(min_value=0),
5319 min_size=len(_schema),
5320 max_size=len(_schema),
5323 class SeqWithoutDefault(self.base_klass):
5325 (n, Integer(impl=t))
5326 for (n, _), t in zip(_schema, tags)
5328 seq_without_default = SeqWithoutDefault()
5329 for name, value in _schema:
5330 seq_without_default[name] = Integer(value)
5331 seq_encoded = seq_without_default.encode()
5333 class SeqWithDefault(self.base_klass):
5335 (n, Integer(default=v, impl=t))
5336 for (n, v), t in zip(_schema, tags)
5338 seq_with_default = SeqWithDefault()
5339 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5340 seq_with_default.decode(seq_encoded)
5341 for ctx in ({"bered": True}, {"allow_default_values": True}):
5342 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5343 self.assertTrue(seq_decoded.ber_encoded)
5344 self.assertTrue(seq_decoded.bered)
5345 seq_decoded = copy(seq_decoded)
5346 self.assertTrue(seq_decoded.ber_encoded)
5347 self.assertTrue(seq_decoded.bered)
5348 for name, value in _schema:
5349 self.assertEqual(seq_decoded[name], seq_with_default[name])
5350 self.assertEqual(seq_decoded[name], value)
5352 @given(data_strategy())
5353 def test_missing_from_spec(self, d):
5354 names = list(d.draw(sets(text_letters(), min_size=2)))
5355 tags = [tag_encode(tag) for tag in d.draw(sets(
5356 integers(min_value=0),
5357 min_size=len(names),
5358 max_size=len(names),
5360 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5362 class SeqFull(self.base_klass):
5363 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5364 seq_full = SeqFull()
5365 for i, name in enumerate(names):
5366 seq_full[name] = Integer(i)
5367 seq_encoded = seq_full.encode()
5368 altered = names_tags[:-2] + names_tags[-1:]
5370 class SeqMissing(self.base_klass):
5371 schema = [(n, Integer(impl=t)) for n, t in altered]
5372 seq_missing = SeqMissing()
5373 with self.assertRaises(TagMismatch):
5374 seq_missing.decode(seq_encoded)
5376 def test_bered(self):
5377 class Seq(self.base_klass):
5378 schema = (("underlying", Boolean()),)
5379 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5380 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5381 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5382 self.assertFalse(decoded.ber_encoded)
5383 self.assertFalse(decoded.lenindef)
5384 self.assertTrue(decoded.bered)
5385 decoded = copy(decoded)
5386 self.assertFalse(decoded.ber_encoded)
5387 self.assertFalse(decoded.lenindef)
5388 self.assertTrue(decoded.bered)
5390 class Seq(self.base_klass):
5391 schema = (("underlying", OctetString()),)
5393 tag_encode(form=TagFormConstructed, num=4) +
5395 OctetString(b"whatever").encode() +
5398 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5399 with self.assertRaises(DecodeError):
5400 Seq().decode(encoded)
5401 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5402 self.assertFalse(decoded.ber_encoded)
5403 self.assertFalse(decoded.lenindef)
5404 self.assertTrue(decoded.bered)
5405 decoded = copy(decoded)
5406 self.assertFalse(decoded.ber_encoded)
5407 self.assertFalse(decoded.lenindef)
5408 self.assertTrue(decoded.bered)
5411 class TestSequence(SeqMixing, CommonMixin, TestCase):
5412 base_klass = Sequence
5418 def test_remaining(self, value, junk):
5419 class Seq(Sequence):
5421 ("whatever", Integer()),
5423 int_encoded = Integer(value).encode()
5425 Sequence.tag_default,
5426 len_encode(len(int_encoded + junk)),
5429 with assertRaisesRegex(self, DecodeError, "remaining"):
5430 Seq().decode(junked)
5432 @given(sets(text_letters(), min_size=2))
5433 def test_obj_unknown(self, names):
5434 missing = names.pop()
5436 class Seq(Sequence):
5437 schema = [(n, Boolean()) for n in names]
5439 with self.assertRaises(ObjUnknown) as err:
5442 with self.assertRaises(ObjUnknown) as err:
5443 seq[missing] = Boolean()
5446 def test_x690_vector(self):
5447 class Seq(Sequence):
5449 ("name", IA5String()),
5452 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5453 self.assertEqual(seq["name"], "Smith")
5454 self.assertEqual(seq["ok"], True)
5457 class TestSet(SeqMixing, CommonMixin, TestCase):
5460 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5461 @given(data_strategy())
5462 def test_sorted(self, d):
5464 tag_encode(tag) for tag in
5465 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5469 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5471 for name, _ in Seq.schema:
5472 seq[name] = OctetString(b"")
5473 seq_encoded = seq.encode()
5474 seq_decoded, _ = seq.decode(seq_encoded)
5475 self.assertSequenceEqual(
5476 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5477 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5480 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5481 @given(data_strategy())
5482 def test_unsorted(self, d):
5484 tag_encode(tag) for tag in
5485 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5487 tags = d.draw(permutations(tags))
5488 assume(tags != sorted(tags))
5489 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5490 seq_encoded = b"".join((
5492 len_encode(len(encoded)),
5497 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5499 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5500 seq.decode(seq_encoded)
5501 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5502 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5503 self.assertTrue(seq_decoded.ber_encoded)
5504 self.assertTrue(seq_decoded.bered)
5505 seq_decoded = copy(seq_decoded)
5506 self.assertTrue(seq_decoded.ber_encoded)
5507 self.assertTrue(seq_decoded.bered)
5508 self.assertSequenceEqual(
5509 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5515 def seqof_values_strategy(draw, schema=None, do_expl=False):
5517 schema = draw(sampled_from((Boolean(), Integer())))
5518 bound_min, bound_max = sorted(draw(sets(
5519 integers(min_value=0, max_value=10),
5523 if isinstance(schema, Boolean):
5524 values_generator = booleans().map(Boolean)
5525 elif isinstance(schema, Integer):
5526 values_generator = integers().map(Integer)
5527 values_generator = lists(
5532 values = draw(one_of(none(), values_generator))
5536 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5538 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5539 default = draw(one_of(none(), values_generator))
5540 optional = draw(one_of(none(), booleans()))
5542 draw(integers(min_value=0)),
5543 draw(integers(min_value=0)),
5544 draw(integers(min_value=0)),
5549 (bound_min, bound_max),
5558 class SeqOfMixing(object):
5559 def test_invalid_value_type(self):
5560 with self.assertRaises(InvalidValueType) as err:
5561 self.base_klass(123)
5564 def test_invalid_values_type(self):
5565 class SeqOf(self.base_klass):
5567 with self.assertRaises(InvalidValueType) as err:
5568 SeqOf([Integer(123), Boolean(False), Integer(234)])
5571 def test_schema_required(self):
5572 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5573 self.base_klass.__mro__[1]()
5575 @given(booleans(), booleans(), binary(), binary())
5576 def test_comparison(self, value1, value2, tag1, tag2):
5577 class SeqOf(self.base_klass):
5579 obj1 = SeqOf([Boolean(value1)])
5580 obj2 = SeqOf([Boolean(value2)])
5581 self.assertEqual(obj1 == obj2, value1 == value2)
5582 self.assertEqual(obj1 != obj2, value1 != value2)
5583 self.assertEqual(obj1 == list(obj2), value1 == value2)
5584 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5585 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5586 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5587 self.assertEqual(obj1 == obj2, tag1 == tag2)
5588 self.assertEqual(obj1 != obj2, tag1 != tag2)
5590 @given(lists(booleans()))
5591 def test_iter(self, values):
5592 class SeqOf(self.base_klass):
5594 obj = SeqOf([Boolean(value) for value in values])
5595 self.assertEqual(len(obj), len(values))
5596 for i, value in enumerate(obj):
5597 self.assertEqual(value, values[i])
5599 @given(data_strategy())
5600 def test_ready(self, d):
5601 ready = [Integer(v) for v in d.draw(lists(
5608 range(d.draw(integers(min_value=1, max_value=5)))
5611 class SeqOf(self.base_klass):
5613 values = d.draw(permutations(ready + non_ready))
5615 for value in values:
5617 self.assertFalse(seqof.ready)
5620 pprint(seqof, big_blobs=True, with_decode_path=True)
5621 with self.assertRaises(ObjNotReady) as err:
5624 for i, value in enumerate(values):
5625 self.assertEqual(seqof[i], value)
5626 if not seqof[i].ready:
5627 seqof[i] = Integer(i)
5628 self.assertTrue(seqof.ready)
5631 pprint(seqof, big_blobs=True, with_decode_path=True)
5633 def test_spec_mismatch(self):
5634 class SeqOf(self.base_klass):
5637 seqof.append(Integer(123))
5638 with self.assertRaises(ValueError):
5639 seqof.append(Boolean(False))
5640 with self.assertRaises(ValueError):
5641 seqof[0] = Boolean(False)
5643 @given(data_strategy())
5644 def test_bounds_satisfied(self, d):
5645 class SeqOf(self.base_klass):
5647 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5648 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5649 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5650 SeqOf(value=value, bounds=(bound_min, bound_max))
5652 @given(data_strategy())
5653 def test_bounds_unsatisfied(self, d):
5654 class SeqOf(self.base_klass):
5656 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5657 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5658 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5659 with self.assertRaises(BoundsError) as err:
5660 SeqOf(value=value, bounds=(bound_min, bound_max))
5662 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5663 SeqOf(bounds=(bound_min, bound_max)).decode(
5664 SeqOf(value).encode()
5667 value = [Boolean(True)] * d.draw(integers(
5668 min_value=bound_max + 1,
5669 max_value=bound_max + 10,
5671 with self.assertRaises(BoundsError) as err:
5672 SeqOf(value=value, bounds=(bound_min, bound_max))
5674 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5675 SeqOf(bounds=(bound_min, bound_max)).decode(
5676 SeqOf(value).encode()
5680 @given(integers(min_value=1, max_value=10))
5681 def test_out_of_bounds(self, bound_max):
5682 class SeqOf(self.base_klass):
5684 bounds = (0, bound_max)
5686 for _ in range(bound_max):
5687 seqof.append(Integer(123))
5688 with self.assertRaises(BoundsError):
5689 seqof.append(Integer(123))
5691 @given(data_strategy())
5692 def test_call(self, d):
5702 ) = d.draw(seqof_values_strategy())
5704 class SeqOf(self.base_klass):
5705 schema = schema_initial
5706 obj_initial = SeqOf(
5707 value=value_initial,
5708 bounds=bounds_initial,
5711 default=default_initial,
5712 optional=optional_initial or False,
5713 _decoded=_decoded_initial,
5724 ) = d.draw(seqof_values_strategy(
5725 schema=schema_initial,
5726 do_expl=impl_initial is None,
5728 if (default is None) and (obj_initial.default is not None):
5731 (bounds is None) and
5732 (value is not None) and
5733 (bounds_initial is not None) and
5734 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5738 (bounds is None) and
5739 (default is not None) and
5740 (bounds_initial is not None) and
5741 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5753 value_expected = default if value is None else value
5755 default_initial if value_expected is None
5758 value_expected = () if value_expected is None else value_expected
5759 self.assertEqual(obj, value_expected)
5760 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5761 self.assertEqual(obj.expl_tag, expl or expl_initial)
5764 default_initial if default is None else default,
5766 if obj.default is None:
5767 optional = optional_initial if optional is None else optional
5768 optional = False if optional is None else optional
5771 self.assertEqual(obj.optional, optional)
5773 (obj._bound_min, obj._bound_max),
5774 bounds or bounds_initial or (0, float("+inf")),
5777 @given(seqof_values_strategy())
5778 def test_copy(self, values):
5779 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5781 class SeqOf(self.base_klass):
5783 register_class(SeqOf)
5790 optional=optional or False,
5793 for copy_func in copy_funcs:
5794 obj_copied = copy_func(obj)
5795 self.assert_copied_basic_fields(obj, obj_copied)
5796 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5797 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5798 self.assertEqual(obj._value, obj_copied._value)
5802 integers(min_value=1).map(tag_encode),
5804 def test_stripped(self, values, tag_impl):
5805 class SeqOf(self.base_klass):
5806 schema = OctetString()
5807 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5808 with self.assertRaises(NotEnoughData):
5809 obj.decode(obj.encode()[:-1])
5813 integers(min_value=1).map(tag_ctxc),
5815 def test_stripped_expl(self, values, tag_expl):
5816 class SeqOf(self.base_klass):
5817 schema = OctetString()
5818 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5819 with self.assertRaises(NotEnoughData):
5820 obj.decode(obj.encode()[:-1])
5823 integers(min_value=31),
5824 integers(min_value=0),
5827 def test_bad_tag(self, tag, offset, decode_path):
5828 with self.assertRaises(DecodeError) as err:
5829 self.base_klass().decode(
5830 tag_encode(tag)[:-1],
5832 decode_path=decode_path,
5835 self.assertEqual(err.exception.offset, offset)
5836 self.assertEqual(err.exception.decode_path, decode_path)
5839 integers(min_value=128),
5840 integers(min_value=0),
5843 def test_bad_len(self, l, offset, decode_path):
5844 with self.assertRaises(DecodeError) as err:
5845 self.base_klass().decode(
5846 self.base_klass.tag_default + len_encode(l)[:-1],
5848 decode_path=decode_path,
5851 self.assertEqual(err.exception.offset, offset)
5852 self.assertEqual(err.exception.decode_path, decode_path)
5854 @given(binary(min_size=1))
5855 def test_tag_mismatch(self, impl):
5856 assume(impl != self.base_klass.tag_default)
5857 with self.assertRaises(TagMismatch):
5858 self.base_klass(impl=impl).decode(self.base_klass().encode())
5860 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5862 seqof_values_strategy(schema=Integer()),
5863 lists(integers().map(Integer)),
5864 integers(min_value=1).map(tag_ctxc),
5865 integers(min_value=0),
5868 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5869 _, _, _, _, _, default, optional, _decoded = values
5871 class SeqOf(self.base_klass):
5881 pprint(obj, big_blobs=True, with_decode_path=True)
5882 self.assertFalse(obj.expled)
5883 obj_encoded = obj.encode()
5884 obj_expled = obj(value, expl=tag_expl)
5885 self.assertTrue(obj_expled.expled)
5887 list(obj_expled.pps())
5888 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5889 obj_expled_encoded = obj_expled.encode()
5890 ctx_copied = deepcopy(ctx_dummy)
5891 obj_decoded, tail = obj_expled.decode(
5892 obj_expled_encoded + tail_junk,
5896 self.assertDictEqual(ctx_copied, ctx_dummy)
5898 list(obj_decoded.pps())
5899 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5900 self.assertEqual(tail, tail_junk)
5901 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5902 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5903 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5904 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5906 obj_decoded.expl_llen,
5907 len(len_encode(len(obj_encoded))),
5909 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5910 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5913 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5915 self.assertEqual(obj_decoded.expl_offset, offset)
5916 for obj_inner in obj_decoded:
5917 self.assertIn(obj_inner, obj_decoded)
5918 self.assertSequenceEqual(
5921 obj_inner.offset - offset:
5922 obj_inner.offset + obj_inner.tlvlen - offset
5926 t, _, lv = tag_strip(obj_encoded)
5927 _, _, v = len_decode(lv)
5928 obj_encoded_lenindef = t + LENINDEF + v + EOC
5929 obj_decoded_lenindef, tail_lenindef = obj.decode(
5930 obj_encoded_lenindef + tail_junk,
5931 ctx={"bered": True},
5933 self.assertTrue(obj_decoded_lenindef.lenindef)
5934 self.assertTrue(obj_decoded_lenindef.bered)
5935 obj_decoded_lenindef = copy(obj_decoded_lenindef)
5936 self.assertTrue(obj_decoded_lenindef.lenindef)
5937 self.assertTrue(obj_decoded_lenindef.bered)
5938 repr(obj_decoded_lenindef)
5939 list(obj_decoded_lenindef.pps())
5940 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5941 self.assertEqual(tail_lenindef, tail_junk)
5942 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5943 with self.assertRaises(DecodeError):
5944 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5945 with self.assertRaises(DecodeError):
5946 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5948 assert_exceeding_data(
5950 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5954 def test_bered(self):
5955 class SeqOf(self.base_klass):
5957 encoded = Boolean(False).encode()
5958 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5959 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5960 with self.assertRaises(DecodeError):
5961 SeqOf().decode(encoded)
5962 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5963 self.assertFalse(decoded.ber_encoded)
5964 self.assertFalse(decoded.lenindef)
5965 self.assertTrue(decoded.bered)
5966 decoded = copy(decoded)
5967 self.assertFalse(decoded.ber_encoded)
5968 self.assertFalse(decoded.lenindef)
5969 self.assertTrue(decoded.bered)
5971 class SeqOf(self.base_klass):
5972 schema = OctetString()
5973 encoded = OctetString(b"whatever").encode()
5975 tag_encode(form=TagFormConstructed, num=4) +
5977 OctetString(b"whatever").encode() +
5980 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5981 with self.assertRaises(DecodeError):
5982 SeqOf().decode(encoded)
5983 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5984 self.assertFalse(decoded.ber_encoded)
5985 self.assertFalse(decoded.lenindef)
5986 self.assertTrue(decoded.bered)
5987 decoded = copy(decoded)
5988 self.assertFalse(decoded.ber_encoded)
5989 self.assertFalse(decoded.lenindef)
5990 self.assertTrue(decoded.bered)
5993 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5994 class SeqOf(SequenceOf):
5998 def _test_symmetric_compare_objs(self, obj1, obj2):
5999 self.assertEqual(obj1, obj2)
6000 self.assertSequenceEqual(list(obj1), list(obj2))
6003 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
6008 def _test_symmetric_compare_objs(self, obj1, obj2):
6009 self.assertSetEqual(
6010 set(int(v) for v in obj1),
6011 set(int(v) for v in obj2),
6014 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6015 @given(data_strategy())
6016 def test_sorted(self, d):
6017 values = [OctetString(v) for v in d.draw(lists(binary()))]
6020 schema = OctetString()
6022 seq_encoded = seq.encode()
6023 seq_decoded, _ = seq.decode(seq_encoded)
6024 self.assertSequenceEqual(
6025 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6026 b"".join(sorted([v.encode() for v in values])),
6029 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6030 @given(data_strategy())
6031 def test_unsorted(self, d):
6032 values = [OctetString(v).encode() for v in d.draw(sets(
6033 binary(min_size=1, max_size=5),
6037 values = d.draw(permutations(values))
6038 assume(values != sorted(values))
6039 encoded = b"".join(values)
6040 seq_encoded = b"".join((
6042 len_encode(len(encoded)),
6047 schema = OctetString()
6049 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6050 seq.decode(seq_encoded)
6052 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6053 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6054 self.assertTrue(seq_decoded.ber_encoded)
6055 self.assertTrue(seq_decoded.bered)
6056 seq_decoded = copy(seq_decoded)
6057 self.assertTrue(seq_decoded.ber_encoded)
6058 self.assertTrue(seq_decoded.bered)
6059 self.assertSequenceEqual(
6060 [obj.encode() for obj in seq_decoded],
6065 class TestGoMarshalVectors(TestCase):
6067 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6068 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6069 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6070 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6071 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6073 class Seq(Sequence):
6075 ("erste", Integer()),
6076 ("zweite", Integer(optional=True))
6079 seq["erste"] = Integer(64)
6080 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6081 seq["erste"] = Integer(0x123456)
6082 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6083 seq["erste"] = Integer(64)
6084 seq["zweite"] = Integer(65)
6085 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6087 class NestedSeq(Sequence):
6091 seq["erste"] = Integer(127)
6092 seq["zweite"] = None
6093 nested = NestedSeq()
6094 nested["nest"] = seq
6095 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6097 self.assertSequenceEqual(
6098 OctetString(b"\x01\x02\x03").encode(),
6099 hexdec("0403010203"),
6102 class Seq(Sequence):
6104 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6107 seq["erste"] = Integer(64)
6108 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6110 class Seq(Sequence):
6112 ("erste", Integer(expl=tag_ctxc(5))),
6115 seq["erste"] = Integer(64)
6116 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6118 class Seq(Sequence):
6121 impl=tag_encode(0, klass=TagClassContext),
6126 seq["erste"] = Null()
6127 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6129 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6131 self.assertSequenceEqual(
6132 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6133 hexdec("170d3730303130313030303030305a"),
6135 self.assertSequenceEqual(
6136 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6137 hexdec("170d3039313131353232353631365a"),
6139 self.assertSequenceEqual(
6140 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6141 hexdec("180f32313030303430353132303130315a"),
6144 class Seq(Sequence):
6146 ("erste", GeneralizedTime()),
6149 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6150 self.assertSequenceEqual(
6152 hexdec("3011180f32303039313131353232353631365a"),
6155 self.assertSequenceEqual(
6156 BitString((1, b"\x80")).encode(),
6159 self.assertSequenceEqual(
6160 BitString((12, b"\x81\xF0")).encode(),
6161 hexdec("03030481f0"),
6164 self.assertSequenceEqual(
6165 ObjectIdentifier("1.2.3.4").encode(),
6166 hexdec("06032a0304"),
6168 self.assertSequenceEqual(
6169 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6170 hexdec("06092a864888932d010105"),
6172 self.assertSequenceEqual(
6173 ObjectIdentifier("2.100.3").encode(),
6174 hexdec("0603813403"),
6177 self.assertSequenceEqual(
6178 PrintableString("test").encode(),
6179 hexdec("130474657374"),
6181 self.assertSequenceEqual(
6182 PrintableString("x" * 127).encode(),
6183 hexdec("137F" + "78" * 127),
6185 self.assertSequenceEqual(
6186 PrintableString("x" * 128).encode(),
6187 hexdec("138180" + "78" * 128),
6189 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6191 class Seq(Sequence):
6193 ("erste", IA5String()),
6196 seq["erste"] = IA5String("test")
6197 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6199 class Seq(Sequence):
6201 ("erste", PrintableString()),
6204 seq["erste"] = PrintableString("test")
6205 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6206 # Asterisk is actually not allowable
6207 PrintableString._allowable_chars |= set(b"*")
6208 seq["erste"] = PrintableString("test*")
6209 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6210 PrintableString._allowable_chars -= set(b"*")
6212 class Seq(Sequence):
6214 ("erste", Any(optional=True)),
6215 ("zweite", Integer()),
6218 seq["zweite"] = Integer(64)
6219 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6224 seq.append(Integer(10))
6225 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6227 class _SeqOf(SequenceOf):
6228 schema = PrintableString()
6230 class SeqOf(SequenceOf):
6233 _seqof.append(PrintableString("1"))
6235 seqof.append(_seqof)
6236 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6238 class Seq(Sequence):
6240 ("erste", Integer(default=1)),
6243 seq["erste"] = Integer(0)
6244 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6245 seq["erste"] = Integer(1)
6246 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6247 seq["erste"] = Integer(2)
6248 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6251 class TestPP(TestCase):
6252 @given(data_strategy())
6253 def test_oid_printing(self, d):
6255 str(ObjectIdentifier(k)): v * 2
6256 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6258 chosen = d.draw(sampled_from(sorted(oids)))
6259 chosen_id = oids[chosen]
6260 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6261 self.assertNotIn(chosen_id, pp_console_row(pp))
6264 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6268 class TestAutoAddSlots(TestCase):
6270 class Inher(Integer):
6273 with self.assertRaises(AttributeError):
6275 inher.unexistent = "whatever"
6278 class TestOIDDefines(TestCase):
6279 @given(data_strategy())
6280 def runTest(self, d):
6281 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6282 value_name_chosen = d.draw(sampled_from(value_names))
6284 ObjectIdentifier(oid)
6285 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6287 oid_chosen = d.draw(sampled_from(oids))
6288 values = d.draw(lists(
6290 min_size=len(value_names),
6291 max_size=len(value_names),
6294 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6295 oid: Integer() for oid in oids[:-1]
6298 for i, value_name in enumerate(value_names):
6299 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6301 class Seq(Sequence):
6304 for value_name, value in zip(value_names, values):
6305 seq[value_name] = Any(Integer(value).encode())
6306 seq["type"] = oid_chosen
6307 seq, _ = Seq().decode(seq.encode())
6308 for value_name in value_names:
6309 if value_name == value_name_chosen:
6311 self.assertIsNone(seq[value_name].defined)
6312 if value_name_chosen in oids[:-1]:
6313 self.assertIsNotNone(seq[value_name_chosen].defined)
6314 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6315 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6318 pprint(seq, big_blobs=True, with_decode_path=True)
6321 class TestDefinesByPath(TestCase):
6322 def test_generated(self):
6323 class Seq(Sequence):
6325 ("type", ObjectIdentifier()),
6326 ("value", OctetString(expl=tag_ctxc(123))),
6329 class SeqInner(Sequence):
6331 ("typeInner", ObjectIdentifier()),
6332 ("valueInner", Any()),
6335 class PairValue(SetOf):
6338 class Pair(Sequence):
6340 ("type", ObjectIdentifier()),
6341 ("value", PairValue()),
6344 class Pairs(SequenceOf):
6351 type_octet_stringed,
6353 ObjectIdentifier(oid)
6354 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6356 seq_integered = Seq()
6357 seq_integered["type"] = type_integered
6358 seq_integered["value"] = OctetString(Integer(123).encode())
6359 seq_integered_raw = seq_integered.encode()
6363 (type_octet_stringed, OctetString(b"whatever")),
6364 (type_integered, Integer(123)),
6365 (type_octet_stringed, OctetString(b"whenever")),
6366 (type_integered, Integer(234)),
6368 for t, v in pairs_input:
6371 pair["value"] = PairValue((Any(v),))
6373 seq_inner = SeqInner()
6374 seq_inner["typeInner"] = type_innered
6375 seq_inner["valueInner"] = Any(pairs)
6376 seq_sequenced = Seq()
6377 seq_sequenced["type"] = type_sequenced
6378 seq_sequenced["value"] = OctetString(seq_inner.encode())
6379 seq_sequenced_raw = seq_sequenced.encode()
6381 list(seq_sequenced.pps())
6382 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6384 defines_by_path = []
6385 ctx_copied = deepcopy(ctx_dummy)
6386 seq_integered, _ = Seq().decode(
6390 self.assertDictEqual(ctx_copied, ctx_dummy)
6391 self.assertIsNone(seq_integered["value"].defined)
6392 defines_by_path.append(
6393 (("type",), ((("value",), {
6394 type_integered: Integer(),
6395 type_sequenced: SeqInner(),
6398 ctx_copied["defines_by_path"] = defines_by_path
6399 seq_integered, _ = Seq().decode(
6403 del ctx_copied["defines_by_path"]
6404 self.assertDictEqual(ctx_copied, ctx_dummy)
6405 self.assertIsNotNone(seq_integered["value"].defined)
6406 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6407 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6408 self.assertTrue(seq_integered_raw[
6409 seq_integered["value"].defined[1].offset:
6410 ].startswith(Integer(123).encode()))
6412 list(seq_integered.pps())
6413 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6415 ctx_copied["defines_by_path"] = defines_by_path
6416 seq_sequenced, _ = Seq().decode(
6420 del ctx_copied["defines_by_path"]
6421 self.assertDictEqual(ctx_copied, ctx_dummy)
6422 self.assertIsNotNone(seq_sequenced["value"].defined)
6423 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6424 seq_inner = seq_sequenced["value"].defined[1]
6425 self.assertIsNone(seq_inner["valueInner"].defined)
6427 list(seq_sequenced.pps())
6428 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6430 defines_by_path.append((
6431 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6432 ((("valueInner",), {type_innered: Pairs()}),),
6434 ctx_copied["defines_by_path"] = defines_by_path
6435 seq_sequenced, _ = Seq().decode(
6439 del ctx_copied["defines_by_path"]
6440 self.assertDictEqual(ctx_copied, ctx_dummy)
6441 self.assertIsNotNone(seq_sequenced["value"].defined)
6442 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6443 seq_inner = seq_sequenced["value"].defined[1]
6444 self.assertIsNotNone(seq_inner["valueInner"].defined)
6445 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6446 pairs = seq_inner["valueInner"].defined[1]
6448 self.assertIsNone(pair["value"][0].defined)
6450 list(seq_sequenced.pps())
6451 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6453 defines_by_path.append((
6456 DecodePathDefBy(type_sequenced),
6458 DecodePathDefBy(type_innered),
6463 type_integered: Integer(),
6464 type_octet_stringed: OctetString(),
6467 ctx_copied["defines_by_path"] = defines_by_path
6468 seq_sequenced, _ = Seq().decode(
6472 del ctx_copied["defines_by_path"]
6473 self.assertDictEqual(ctx_copied, ctx_dummy)
6474 self.assertIsNotNone(seq_sequenced["value"].defined)
6475 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6476 seq_inner = seq_sequenced["value"].defined[1]
6477 self.assertIsNotNone(seq_inner["valueInner"].defined)
6478 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6479 pairs_got = seq_inner["valueInner"].defined[1]
6480 for pair_input, pair_got in zip(pairs_input, pairs_got):
6481 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6482 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6484 list(seq_sequenced.pps())
6485 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6487 @given(oid_strategy(), integers())
6488 def test_simple(self, oid, tgt):
6489 class Inner(Sequence):
6491 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6492 ObjectIdentifier(oid): Integer(),
6496 class Outer(Sequence):
6499 ("tgt", OctetString()),
6503 inner["oid"] = ObjectIdentifier(oid)
6505 outer["inner"] = inner
6506 outer["tgt"] = OctetString(Integer(tgt).encode())
6507 decoded, _ = Outer().decode(outer.encode())
6508 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6511 class TestAbsDecodePath(TestCase):
6513 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6514 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6516 def test_concat(self, decode_path, rel_path):
6517 self.assertSequenceEqual(
6518 abs_decode_path(decode_path, rel_path),
6519 decode_path + rel_path,
6523 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6524 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6526 def test_abs(self, decode_path, rel_path):
6527 self.assertSequenceEqual(
6528 abs_decode_path(decode_path, ("/",) + rel_path),
6533 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6534 integers(min_value=1, max_value=3),
6535 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6537 def test_dots(self, decode_path, number_of_dots, rel_path):
6538 self.assertSequenceEqual(
6539 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6540 decode_path[:-number_of_dots] + rel_path,
6544 class TestStrictDefaultExistence(TestCase):
6545 @given(data_strategy())
6546 def runTest(self, d):
6547 count = d.draw(integers(min_value=1, max_value=10))
6548 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6550 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6551 for i in range(count)
6553 for klass in (Sequence, Set):
6557 for i in range(count):
6558 seq["int%d" % i] = Integer(123)
6560 chosen_choice = "int%d" % chosen
6561 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6562 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6564 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6565 self.assertTrue(decoded.ber_encoded)
6566 self.assertTrue(decoded.bered)
6567 decoded = copy(decoded)
6568 self.assertTrue(decoded.ber_encoded)
6569 self.assertTrue(decoded.bered)
6570 decoded, _ = seq.decode(raw, ctx={"bered": True})
6571 self.assertTrue(decoded.ber_encoded)
6572 self.assertTrue(decoded.bered)
6573 decoded = copy(decoded)
6574 self.assertTrue(decoded.ber_encoded)
6575 self.assertTrue(decoded.bered)
6578 class TestX690PrefixedType(TestCase):
6580 self.assertSequenceEqual(
6581 VisibleString("Jones").encode(),
6582 hexdec("1A054A6F6E6573"),
6584 self.assertSequenceEqual(
6587 impl=tag_encode(3, klass=TagClassApplication),
6589 hexdec("43054A6F6E6573"),
6591 self.assertSequenceEqual(
6595 impl=tag_encode(3, klass=TagClassApplication),
6599 hexdec("A20743054A6F6E6573"),
6601 self.assertSequenceEqual(
6605 impl=tag_encode(3, klass=TagClassApplication),
6607 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6609 hexdec("670743054A6F6E6573"),
6611 self.assertSequenceEqual(
6612 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6613 hexdec("82054A6F6E6573"),
6617 class TestExplOOB(TestCase):
6619 expl = tag_ctxc(123)
6620 raw = Integer(123).encode() + Integer(234).encode()
6621 raw = b"".join((expl, len_encode(len(raw)), raw))
6622 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6623 Integer(expl=expl).decode(raw)
6624 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
6627 class TestPickleDifferentVersion(TestCase):
6629 pickled = pickle_dumps(Integer(123), pickle_proto)
6631 version_orig = pyderasn.__version__
6632 pyderasn.__version__ += "different"
6633 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
6634 pickle_loads(pickled)
6635 pyderasn.__version__ = version_orig
6636 pickle_loads(pickled)