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):
160 with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)) as err:
165 class TestHex(TestCase):
167 def test_symmetric(self, data):
168 self.assertEqual(hexdec(hexenc(data)), data)
171 class TestTagCoder(TestCase):
172 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
176 integers(min_value=0, max_value=30),
179 def test_short(self, klass, form, num, junk):
180 raw = tag_encode(klass=klass, form=form, num=num)
181 self.assertEqual(tag_decode(raw), (klass, form, num))
182 self.assertEqual(len(raw), 1)
184 byte2int(tag_encode(klass=klass, form=form, num=0)),
185 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
187 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
188 self.assertSequenceEqual(stripped.tobytes(), raw)
189 self.assertEqual(tlen, len(raw))
190 self.assertSequenceEqual(tail, junk)
192 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
196 integers(min_value=31),
199 def test_long(self, klass, form, num, junk):
200 raw = tag_encode(klass=klass, form=form, num=num)
201 self.assertEqual(tag_decode(raw), (klass, form, num))
202 self.assertGreater(len(raw), 1)
204 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
207 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
208 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
209 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
210 self.assertSequenceEqual(stripped.tobytes(), raw)
211 self.assertEqual(tlen, len(raw))
212 self.assertSequenceEqual(tail, junk)
214 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
215 @given(integers(min_value=31))
216 def test_unfinished_tag(self, num):
217 raw = bytearray(tag_encode(num=num))
218 for i in range(1, len(raw)):
220 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
221 tag_strip(bytes(raw))
223 def test_go_vectors_valid(self):
224 for data, (eklass, etag, elen, eform) in (
225 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
226 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
227 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
228 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
229 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
230 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
231 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
232 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
233 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
234 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
236 tag, _, len_encoded = tag_strip(memoryview(data))
237 klass, form, num = tag_decode(tag)
238 _len, _, tail = len_decode(len_encoded)
239 self.assertSequenceEqual(tail, b"")
240 self.assertEqual(klass, eklass)
241 self.assertEqual(num, etag)
242 self.assertEqual(_len, elen)
243 self.assertEqual(form, eform)
245 def test_go_vectors_invalid(self):
253 with self.assertRaises(DecodeError):
254 _, _, len_encoded = tag_strip(memoryview(data))
255 len_decode(len_encoded)
258 integers(min_value=0, max_value=127),
259 integers(min_value=0, max_value=2),
261 def test_long_instead_of_short(self, l, dummy_num):
262 octets = (b"\x00" * dummy_num) + int2byte(l)
263 octets = int2byte((dummy_num + 1) | 0x80) + octets
264 with self.assertRaises(DecodeError):
268 class TestLenCoder(TestCase):
269 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
271 integers(min_value=0, max_value=127),
274 def test_short(self, l, junk):
275 raw = len_encode(l) + junk
276 decoded, llen, tail = len_decode(memoryview(raw))
277 self.assertEqual(decoded, l)
278 self.assertEqual(llen, 1)
279 self.assertEqual(len(raw), 1 + len(junk))
280 self.assertEqual(tail.tobytes(), junk)
282 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
284 integers(min_value=128),
287 def test_long(self, l, junk):
288 raw = len_encode(l) + junk
289 decoded, llen, tail = len_decode(memoryview(raw))
290 self.assertEqual(decoded, l)
291 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
292 self.assertEqual(llen, len(raw) - len(junk))
293 self.assertNotEqual(indexbytes(raw, 1), 0)
294 self.assertSequenceEqual(tail.tobytes(), junk)
296 def test_empty(self):
297 with self.assertRaises(NotEnoughData):
300 @given(integers(min_value=128))
301 def test_stripped(self, _len):
302 with self.assertRaises(NotEnoughData):
303 len_decode(len_encode(_len)[:-1])
306 text_printable = text(alphabet=printable, min_size=1)
310 def text_letters(draw):
311 result = draw(text(alphabet=ascii_letters, min_size=1))
313 result = result.encode("ascii")
317 class CommonMixin(object):
318 def test_tag_default(self):
319 obj = self.base_klass()
320 self.assertEqual(obj.tag, obj.tag_default)
322 def test_simultaneous_impl_expl(self):
323 with self.assertRaises(ValueError):
324 self.base_klass(impl=b"whatever", expl=b"whenever")
326 @given(binary(min_size=1), integers(), integers(), integers())
327 def test_decoded(self, impl, offset, llen, vlen):
328 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
329 self.assertEqual(obj.offset, offset)
330 self.assertEqual(obj.llen, llen)
331 self.assertEqual(obj.vlen, vlen)
332 self.assertEqual(obj.tlen, len(impl))
333 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
335 @given(binary(min_size=1))
336 def test_impl_inherited(self, impl_tag):
337 class Inherited(self.base_klass):
340 self.assertSequenceEqual(obj.impl, impl_tag)
341 self.assertFalse(obj.expled)
344 def test_expl_inherited(self, expl_tag):
345 class Inherited(self.base_klass):
348 self.assertSequenceEqual(obj.expl, expl_tag)
349 self.assertTrue(obj.expled)
351 def assert_copied_basic_fields(self, obj, obj_copied):
352 self.assertEqual(obj, obj_copied)
353 self.assertSequenceEqual(obj.tag, obj_copied.tag)
354 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
355 self.assertEqual(obj.default, obj_copied.default)
356 self.assertEqual(obj.optional, obj_copied.optional)
357 self.assertEqual(obj.offset, obj_copied.offset)
358 self.assertEqual(obj.llen, obj_copied.llen)
359 self.assertEqual(obj.vlen, obj_copied.vlen)
363 def boolean_values_strategy(draw, do_expl=False):
364 value = draw(one_of(none(), booleans()))
368 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
370 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
371 default = draw(one_of(none(), booleans()))
372 optional = draw(one_of(none(), booleans()))
374 draw(integers(min_value=0)),
375 draw(integers(min_value=0)),
376 draw(integers(min_value=0)),
378 return (value, impl, expl, default, optional, _decoded)
381 class BooleanInherited(Boolean):
385 class TestBoolean(CommonMixin, TestCase):
388 def test_invalid_value_type(self):
389 with self.assertRaises(InvalidValueType) as err:
394 def test_optional(self, optional):
395 obj = Boolean(default=Boolean(False), optional=optional)
396 self.assertTrue(obj.optional)
399 def test_ready(self, value):
401 self.assertFalse(obj.ready)
404 pprint(obj, big_blobs=True, with_decode_path=True)
405 with self.assertRaises(ObjNotReady) as err:
409 self.assertTrue(obj.ready)
412 pprint(obj, big_blobs=True, with_decode_path=True)
414 @given(booleans(), booleans(), binary(), binary())
415 def test_comparison(self, value1, value2, tag1, tag2):
416 for klass in (Boolean, BooleanInherited):
419 self.assertEqual(obj1 == obj2, value1 == value2)
420 self.assertEqual(obj1 != obj2, value1 != value2)
421 self.assertEqual(obj1 == bool(obj2), value1 == value2)
422 obj1 = klass(value1, impl=tag1)
423 obj2 = klass(value1, impl=tag2)
424 self.assertEqual(obj1 == obj2, tag1 == tag2)
425 self.assertEqual(obj1 != obj2, tag1 != tag2)
427 @given(data_strategy())
428 def test_call(self, d):
429 for klass in (Boolean, BooleanInherited):
437 ) = d.draw(boolean_values_strategy())
443 optional_initial or False,
453 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
454 obj = obj_initial(value, impl, expl, default, optional)
456 value_expected = default if value is None else value
458 default_initial if value_expected is None
461 self.assertEqual(obj, value_expected)
462 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
463 self.assertEqual(obj.expl_tag, expl or expl_initial)
466 default_initial if default is None else default,
468 if obj.default is None:
469 optional = optional_initial if optional is None else optional
470 optional = False if optional is None else optional
473 self.assertEqual(obj.optional, optional)
475 @given(boolean_values_strategy())
476 def test_copy(self, values):
477 for klass in (Boolean, BooleanInherited):
479 for copy_func in copy_funcs:
480 obj_copied = copy_func(obj)
481 self.assert_copied_basic_fields(obj, obj_copied)
485 integers(min_value=1).map(tag_encode),
487 def test_stripped(self, value, tag_impl):
488 obj = Boolean(value, impl=tag_impl)
489 with self.assertRaises(NotEnoughData):
490 obj.decode(obj.encode()[:-1])
494 integers(min_value=1).map(tag_ctxc),
496 def test_stripped_expl(self, value, tag_expl):
497 obj = Boolean(value, expl=tag_expl)
498 with self.assertRaises(NotEnoughData):
499 obj.decode(obj.encode()[:-1])
502 integers(min_value=31),
503 integers(min_value=0),
506 def test_bad_tag(self, tag, offset, decode_path):
507 with self.assertRaises(DecodeError) as err:
509 tag_encode(tag)[:-1],
511 decode_path=decode_path,
514 self.assertEqual(err.exception.offset, offset)
515 self.assertEqual(err.exception.decode_path, decode_path)
518 integers(min_value=31),
519 integers(min_value=0),
522 def test_bad_expl_tag(self, tag, offset, decode_path):
523 with self.assertRaises(DecodeError) as err:
524 Boolean(expl=Boolean.tag_default).decode(
525 tag_encode(tag)[:-1],
527 decode_path=decode_path,
530 self.assertEqual(err.exception.offset, offset)
531 self.assertEqual(err.exception.decode_path, decode_path)
534 integers(min_value=128),
535 integers(min_value=0),
538 def test_bad_len(self, l, offset, decode_path):
539 with self.assertRaises(DecodeError) as err:
541 Boolean.tag_default + len_encode(l)[:-1],
543 decode_path=decode_path,
546 self.assertEqual(err.exception.offset, offset)
547 self.assertEqual(err.exception.decode_path, decode_path)
550 integers(min_value=128),
551 integers(min_value=0),
554 def test_bad_expl_len(self, l, offset, decode_path):
555 with self.assertRaises(DecodeError) as err:
556 Boolean(expl=Boolean.tag_default).decode(
557 Boolean.tag_default + len_encode(l)[:-1],
559 decode_path=decode_path,
562 self.assertEqual(err.exception.offset, offset)
563 self.assertEqual(err.exception.decode_path, decode_path)
565 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
567 boolean_values_strategy(),
569 integers(min_value=1).map(tag_ctxc),
570 integers(min_value=0),
573 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
574 for klass in (Boolean, BooleanInherited):
575 _, _, _, default, optional, _decoded = values
584 pprint(obj, big_blobs=True, with_decode_path=True)
585 self.assertFalse(obj.expled)
586 obj_encoded = obj.encode()
587 obj_expled = obj(value, expl=tag_expl)
588 self.assertTrue(obj_expled.expled)
590 list(obj_expled.pps())
591 pprint(obj_expled, big_blobs=True, with_decode_path=True)
592 obj_expled_hex_encoded = obj_expled.hexencode()
593 ctx_copied = deepcopy(ctx_dummy)
594 obj_decoded, tail = obj_expled.hexdecode(
595 obj_expled_hex_encoded + hexenc(tail_junk),
599 self.assertDictEqual(ctx_copied, ctx_dummy)
601 list(obj_decoded.pps())
602 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
603 self.assertEqual(tail, tail_junk)
604 self.assertEqual(obj_decoded, obj_expled)
605 self.assertNotEqual(obj_decoded, obj)
606 self.assertEqual(bool(obj_decoded), bool(obj_expled))
607 self.assertEqual(bool(obj_decoded), bool(obj))
608 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
609 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
610 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
612 obj_decoded.expl_llen,
613 len(len_encode(len(obj_encoded))),
615 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
616 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
619 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
621 self.assertEqual(obj_decoded.expl_offset, offset)
622 assert_exceeding_data(
624 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
628 @given(integers(min_value=2))
629 def test_invalid_len(self, l):
630 with self.assertRaises(InvalidLength):
631 Boolean().decode(b"".join((
637 @given(integers(min_value=0 + 1, max_value=255 - 1))
638 def test_ber_value(self, value):
639 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
640 Boolean().decode(b"".join((
645 obj, _ = Boolean().decode(
653 self.assertTrue(bool(obj))
654 self.assertTrue(obj.ber_encoded)
655 self.assertFalse(obj.lenindef)
656 self.assertTrue(obj.bered)
658 self.assertTrue(obj.ber_encoded)
659 self.assertFalse(obj.lenindef)
660 self.assertTrue(obj.bered)
663 integers(min_value=1).map(tag_ctxc),
664 binary().filter(lambda x: not x.startswith(EOC)),
666 def test_ber_expl_no_eoc(self, expl, junk):
667 encoded = expl + LENINDEF + Boolean(False).encode()
668 with self.assertRaises(LenIndefForm):
669 Boolean(expl=expl).decode(encoded + junk)
670 with assertRaisesRegex(self, DecodeError, "no EOC"):
671 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
672 obj, tail = Boolean(expl=expl).decode(
673 encoded + EOC + junk,
676 self.assertTrue(obj.expl_lenindef)
677 self.assertFalse(obj.lenindef)
678 self.assertFalse(obj.ber_encoded)
679 self.assertTrue(obj.bered)
681 self.assertTrue(obj.expl_lenindef)
682 self.assertFalse(obj.lenindef)
683 self.assertFalse(obj.ber_encoded)
684 self.assertTrue(obj.bered)
685 self.assertSequenceEqual(tail, junk)
688 pprint(obj, big_blobs=True, with_decode_path=True)
691 integers(min_value=1).map(tag_ctxc),
698 def test_ber_expl(self, expl, values):
704 Boolean(value).encode() +
707 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
709 class SeqOf(SequenceOf):
710 schema = Boolean(expl=expl)
711 with self.assertRaises(LenIndefForm):
712 SeqOf().decode(encoded)
713 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
714 self.assertSequenceEqual(tail, b"")
715 self.assertSequenceEqual([bool(v) for v in seqof], values)
731 len(expl) + 1 + 3 + EOC_LEN,
742 pprint(seqof, big_blobs=True, with_decode_path=True)
746 def integer_values_strategy(draw, do_expl=False):
747 bound_min, value, default, bound_max = sorted(draw(sets(
756 _specs = draw(sets(text_letters()))
759 min_size=len(_specs),
760 max_size=len(_specs),
762 _specs = list(zip(_specs, values))
765 bounds = (bound_min, bound_max)
769 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
771 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
774 optional = draw(one_of(none(), booleans()))
776 draw(integers(min_value=0)),
777 draw(integers(min_value=0)),
778 draw(integers(min_value=0)),
780 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
783 class IntegerInherited(Integer):
787 class TestInteger(CommonMixin, TestCase):
790 def test_invalid_value_type(self):
791 with self.assertRaises(InvalidValueType) as err:
795 @given(sets(text_letters(), min_size=2))
796 def test_unknown_name(self, names_input):
797 missing = names_input.pop()
800 schema = [(n, 123) for n in names_input]
801 with self.assertRaises(ObjUnknown) as err:
805 @given(sets(text_letters(), min_size=2))
806 def test_known_name(self, names_input):
808 schema = [(n, 123) for n in names_input]
809 Int(names_input.pop())
812 def test_optional(self, optional):
813 obj = Integer(default=Integer(0), optional=optional)
814 self.assertTrue(obj.optional)
817 def test_ready(self, value):
819 self.assertFalse(obj.ready)
822 pprint(obj, big_blobs=True, with_decode_path=True)
823 with self.assertRaises(ObjNotReady) as err:
827 self.assertTrue(obj.ready)
830 pprint(obj, big_blobs=True, with_decode_path=True)
833 @given(integers(), integers(), binary(), binary())
834 def test_comparison(self, value1, value2, tag1, tag2):
835 for klass in (Integer, IntegerInherited):
838 self.assertEqual(obj1 == obj2, value1 == value2)
839 self.assertEqual(obj1 != obj2, value1 != value2)
840 self.assertEqual(obj1 == int(obj2), value1 == value2)
841 obj1 = klass(value1, impl=tag1)
842 obj2 = klass(value1, impl=tag2)
843 self.assertEqual(obj1 == obj2, tag1 == tag2)
844 self.assertEqual(obj1 != obj2, tag1 != tag2)
846 @given(lists(integers()))
847 def test_sorted_works(self, values):
848 self.assertSequenceEqual(
849 [int(v) for v in sorted(Integer(v) for v in values)],
853 @given(data_strategy())
854 def test_named(self, d):
855 names_input = list(d.draw(sets(text_letters(), min_size=1)))
856 values_input = list(d.draw(sets(
858 min_size=len(names_input),
859 max_size=len(names_input),
861 chosen_name = d.draw(sampled_from(names_input))
862 names_input = dict(zip(names_input, values_input))
866 _int = Int(chosen_name)
867 self.assertEqual(_int.named, chosen_name)
868 self.assertEqual(int(_int), names_input[chosen_name])
870 @given(integers(), integers(min_value=0), integers(min_value=0))
871 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
872 value = bound_min + value_delta
873 bound_max = value + bound_delta
874 Integer(value=value, bounds=(bound_min, bound_max))
876 @given(sets(integers(), min_size=3, max_size=3))
877 def test_bounds_unsatisfied(self, values):
878 values = sorted(values)
879 with self.assertRaises(BoundsError) as err:
880 Integer(value=values[0], bounds=(values[1], values[2]))
882 with assertRaisesRegex(self, DecodeError, "bounds") as err:
883 Integer(bounds=(values[1], values[2])).decode(
884 Integer(values[0]).encode()
887 with self.assertRaises(BoundsError) as err:
888 Integer(value=values[2], bounds=(values[0], values[1]))
890 with assertRaisesRegex(self, DecodeError, "bounds") as err:
891 Integer(bounds=(values[0], values[1])).decode(
892 Integer(values[2]).encode()
896 @given(data_strategy())
897 def test_call(self, d):
898 for klass in (Integer, IntegerInherited):
908 ) = d.draw(integer_values_strategy())
915 optional_initial or False,
928 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
929 if (default is None) and (obj_initial.default is not None):
933 (value is not None) and
934 (bounds_initial is not None) and
935 not (bounds_initial[0] <= value <= bounds_initial[1])
940 (default is not None) and
941 (bounds_initial is not None) and
942 not (bounds_initial[0] <= default <= bounds_initial[1])
945 obj = obj_initial(value, bounds, impl, expl, default, optional)
947 value_expected = default if value is None else value
949 default_initial if value_expected is None
952 self.assertEqual(obj, value_expected)
953 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
954 self.assertEqual(obj.expl_tag, expl or expl_initial)
957 default_initial if default is None else default,
959 if obj.default is None:
960 optional = optional_initial if optional is None else optional
961 optional = False if optional is None else optional
964 self.assertEqual(obj.optional, optional)
966 (obj._bound_min, obj._bound_max),
967 bounds or bounds_initial or (float("-inf"), float("+inf")),
971 {} if _specs_initial is None else dict(_specs_initial),
974 @given(integer_values_strategy())
975 def test_copy(self, values):
976 for klass in (Integer, IntegerInherited):
978 for copy_func in copy_funcs:
979 obj_copied = copy_func(obj)
980 self.assert_copied_basic_fields(obj, obj_copied)
981 self.assertEqual(obj.specs, obj_copied.specs)
982 self.assertEqual(obj._bound_min, obj_copied._bound_min)
983 self.assertEqual(obj._bound_max, obj_copied._bound_max)
984 self.assertEqual(obj._value, obj_copied._value)
988 integers(min_value=1).map(tag_encode),
990 def test_stripped(self, value, tag_impl):
991 obj = Integer(value, impl=tag_impl)
992 with self.assertRaises(NotEnoughData):
993 obj.decode(obj.encode()[:-1])
997 integers(min_value=1).map(tag_ctxc),
999 def test_stripped_expl(self, value, tag_expl):
1000 obj = Integer(value, expl=tag_expl)
1001 with self.assertRaises(NotEnoughData):
1002 obj.decode(obj.encode()[:-1])
1004 def test_zero_len(self):
1005 with self.assertRaises(NotEnoughData):
1006 Integer().decode(b"".join((
1007 Integer.tag_default,
1012 integers(min_value=31),
1013 integers(min_value=0),
1016 def test_bad_tag(self, tag, offset, decode_path):
1017 with self.assertRaises(DecodeError) as err:
1019 tag_encode(tag)[:-1],
1021 decode_path=decode_path,
1024 self.assertEqual(err.exception.offset, offset)
1025 self.assertEqual(err.exception.decode_path, decode_path)
1028 integers(min_value=128),
1029 integers(min_value=0),
1032 def test_bad_len(self, l, offset, decode_path):
1033 with self.assertRaises(DecodeError) as err:
1035 Integer.tag_default + len_encode(l)[:-1],
1037 decode_path=decode_path,
1040 self.assertEqual(err.exception.offset, offset)
1041 self.assertEqual(err.exception.decode_path, decode_path)
1044 sets(integers(), min_size=2, max_size=2),
1045 integers(min_value=0),
1048 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1049 value, bound_min = list(sorted(ints))
1052 bounds = (bound_min, bound_min)
1053 with self.assertRaises(DecodeError) as err:
1055 Integer(value).encode(),
1057 decode_path=decode_path,
1060 self.assertEqual(err.exception.offset, offset)
1061 self.assertEqual(err.exception.decode_path, decode_path)
1063 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1065 integer_values_strategy(),
1067 integers(min_value=1).map(tag_ctxc),
1068 integers(min_value=0),
1071 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1072 for klass in (Integer, IntegerInherited):
1073 _, _, _, _, default, optional, _, _decoded = values
1082 pprint(obj, big_blobs=True, with_decode_path=True)
1083 self.assertFalse(obj.expled)
1084 obj_encoded = obj.encode()
1085 obj_expled = obj(value, expl=tag_expl)
1086 self.assertTrue(obj_expled.expled)
1088 list(obj_expled.pps())
1089 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1090 obj_expled_encoded = obj_expled.encode()
1091 ctx_copied = deepcopy(ctx_dummy)
1092 obj_decoded, tail = obj_expled.decode(
1093 obj_expled_encoded + tail_junk,
1097 self.assertDictEqual(ctx_copied, ctx_dummy)
1099 list(obj_decoded.pps())
1100 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1101 self.assertEqual(tail, tail_junk)
1102 self.assertEqual(obj_decoded, obj_expled)
1103 self.assertNotEqual(obj_decoded, obj)
1104 self.assertEqual(int(obj_decoded), int(obj_expled))
1105 self.assertEqual(int(obj_decoded), int(obj))
1106 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1107 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1108 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1110 obj_decoded.expl_llen,
1111 len(len_encode(len(obj_encoded))),
1113 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1114 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1117 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1119 self.assertEqual(obj_decoded.expl_offset, offset)
1120 assert_exceeding_data(
1122 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1126 def test_go_vectors_valid(self):
1127 for data, expect in ((
1131 (b"\xff\x7f", -129),
1135 (b"\xff\x00", -256),
1139 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1140 (b"\x80\x00\x00\x00", -2147483648),
1143 Integer().decode(b"".join((
1144 Integer.tag_default,
1145 len_encode(len(data)),
1151 def test_go_vectors_invalid(self):
1156 with self.assertRaises(DecodeError):
1157 Integer().decode(b"".join((
1158 Integer.tag_default,
1159 len_encode(len(data)),
1165 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1168 if draw(booleans()):
1169 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1171 integers(min_value=0, max_value=255),
1172 min_size=len(schema),
1173 max_size=len(schema),
1175 schema = list(zip(schema, bits))
1177 def _value(value_required):
1178 if not value_required and draw(booleans()):
1180 generation_choice = 0
1182 generation_choice = draw(sampled_from((1, 2, 3)))
1183 if generation_choice == 1 or draw(booleans()):
1184 return "'%s'B" % "".join(draw(lists(
1185 sampled_from(("0", "1")),
1186 max_size=len(schema),
1188 if generation_choice == 2 or draw(booleans()):
1189 return draw(binary(max_size=len(schema) // 8))
1190 if generation_choice == 3 or draw(booleans()):
1191 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1193 value = _value(value_required)
1194 default = _value(value_required=False)
1198 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1200 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1201 optional = draw(one_of(none(), booleans()))
1203 draw(integers(min_value=0)),
1204 draw(integers(min_value=0)),
1205 draw(integers(min_value=0)),
1207 return (schema, value, impl, expl, default, optional, _decoded)
1210 class BitStringInherited(BitString):
1214 class TestBitString(CommonMixin, TestCase):
1215 base_klass = BitString
1217 @given(lists(booleans()))
1218 def test_b_encoding(self, bits):
1219 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1220 self.assertEqual(obj.bit_len, len(bits))
1221 self.assertSequenceEqual(list(obj), bits)
1222 for i, bit in enumerate(bits):
1223 self.assertEqual(obj[i], bit)
1225 @given(lists(booleans()))
1226 def test_out_of_bounds_bits(self, bits):
1227 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1228 for i in range(len(bits), len(bits) * 2):
1229 self.assertFalse(obj[i])
1231 def test_bad_b_encoding(self):
1232 with self.assertRaises(ValueError):
1233 BitString("'010120101'B")
1236 integers(min_value=1, max_value=255),
1237 integers(min_value=1, max_value=255),
1239 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1240 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1241 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1242 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1244 class BS(BitString):
1245 schema = (("whatever", 0),)
1246 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1247 self.assertEqual(obj.bit_len, leading_zeros + 1)
1248 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1250 def test_zero_len(self):
1251 with self.assertRaises(NotEnoughData):
1252 BitString().decode(b"".join((
1253 BitString.tag_default,
1257 def test_invalid_value_type(self):
1258 with self.assertRaises(InvalidValueType) as err:
1261 with self.assertRaises(InvalidValueType) as err:
1265 def test_obj_unknown(self):
1266 with self.assertRaises(ObjUnknown) as err:
1267 BitString(b"whatever")["whenever"]
1270 def test_get_invalid_type(self):
1271 with self.assertRaises(InvalidValueType) as err:
1272 BitString(b"whatever")[(1, 2, 3)]
1275 @given(data_strategy())
1276 def test_unknown_name(self, d):
1277 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1278 missing = _schema.pop()
1280 class BS(BitString):
1281 schema = [(n, i) for i, n in enumerate(_schema)]
1282 with self.assertRaises(ObjUnknown) as err:
1287 def test_optional(self, optional):
1288 obj = BitString(default=BitString(b""), optional=optional)
1289 self.assertTrue(obj.optional)
1292 def test_ready(self, value):
1294 self.assertFalse(obj.ready)
1297 pprint(obj, big_blobs=True, with_decode_path=True)
1298 with self.assertRaises(ObjNotReady) as err:
1301 obj = BitString(value)
1302 self.assertTrue(obj.ready)
1305 pprint(obj, big_blobs=True, with_decode_path=True)
1308 tuples(integers(min_value=0), binary()),
1309 tuples(integers(min_value=0), binary()),
1313 def test_comparison(self, value1, value2, tag1, tag2):
1314 for klass in (BitString, BitStringInherited):
1315 obj1 = klass(value1)
1316 obj2 = klass(value2)
1317 self.assertEqual(obj1 == obj2, value1 == value2)
1318 self.assertEqual(obj1 != obj2, value1 != value2)
1319 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1320 obj1 = klass(value1, impl=tag1)
1321 obj2 = klass(value1, impl=tag2)
1322 self.assertEqual(obj1 == obj2, tag1 == tag2)
1323 self.assertEqual(obj1 != obj2, tag1 != tag2)
1325 @given(data_strategy())
1326 def test_call(self, d):
1327 for klass in (BitString, BitStringInherited):
1336 ) = d.draw(bit_string_values_strategy())
1339 schema = schema_initial
1341 value=value_initial,
1344 default=default_initial,
1345 optional=optional_initial or False,
1346 _decoded=_decoded_initial,
1356 ) = d.draw(bit_string_values_strategy(
1357 schema=schema_initial,
1358 do_expl=impl_initial is None,
1367 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1368 self.assertEqual(obj.expl_tag, expl or expl_initial)
1369 if obj.default is None:
1370 optional = optional_initial if optional is None else optional
1371 optional = False if optional is None else optional
1374 self.assertEqual(obj.optional, optional)
1375 self.assertEqual(obj.specs, obj_initial.specs)
1377 @given(bit_string_values_strategy())
1378 def test_copy(self, values):
1379 for klass in (BitString, BitStringInherited):
1380 _schema, value, impl, expl, default, optional, _decoded = values
1390 optional=optional or False,
1393 for copy_func in copy_funcs:
1394 obj_copied = copy_func(obj)
1395 self.assert_copied_basic_fields(obj, obj_copied)
1396 self.assertEqual(obj.specs, obj_copied.specs)
1397 self.assertEqual(obj._value, obj_copied._value)
1401 integers(min_value=1).map(tag_encode),
1403 def test_stripped(self, value, tag_impl):
1404 obj = BitString(value, impl=tag_impl)
1405 with self.assertRaises(NotEnoughData):
1406 obj.decode(obj.encode()[:-1])
1410 integers(min_value=1).map(tag_ctxc),
1412 def test_stripped_expl(self, value, tag_expl):
1413 obj = BitString(value, expl=tag_expl)
1414 with self.assertRaises(NotEnoughData):
1415 obj.decode(obj.encode()[:-1])
1418 integers(min_value=31),
1419 integers(min_value=0),
1422 def test_bad_tag(self, tag, offset, decode_path):
1423 with self.assertRaises(DecodeError) as err:
1425 tag_encode(tag)[:-1],
1427 decode_path=decode_path,
1430 self.assertEqual(err.exception.offset, offset)
1431 self.assertEqual(err.exception.decode_path, decode_path)
1434 integers(min_value=128),
1435 integers(min_value=0),
1438 def test_bad_len(self, l, offset, decode_path):
1439 with self.assertRaises(DecodeError) as err:
1441 BitString.tag_default + len_encode(l)[:-1],
1443 decode_path=decode_path,
1446 self.assertEqual(err.exception.offset, offset)
1447 self.assertEqual(err.exception.decode_path, decode_path)
1449 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1450 @given(data_strategy())
1451 def test_symmetric(self, d):
1460 ) = d.draw(bit_string_values_strategy(value_required=True))
1461 tail_junk = d.draw(binary(max_size=5))
1462 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1463 offset = d.draw(integers(min_value=0))
1464 for klass in (BitString, BitStringInherited):
1475 pprint(obj, big_blobs=True, with_decode_path=True)
1476 self.assertFalse(obj.expled)
1477 obj_encoded = obj.encode()
1478 obj_expled = obj(value, expl=tag_expl)
1479 self.assertTrue(obj_expled.expled)
1481 list(obj_expled.pps())
1482 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1483 obj_expled_encoded = obj_expled.encode()
1484 ctx_copied = deepcopy(ctx_dummy)
1485 obj_decoded, tail = obj_expled.decode(
1486 obj_expled_encoded + tail_junk,
1490 self.assertDictEqual(ctx_copied, ctx_dummy)
1492 list(obj_decoded.pps())
1493 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1494 self.assertEqual(tail, tail_junk)
1495 self.assertEqual(obj_decoded, obj_expled)
1496 self.assertNotEqual(obj_decoded, obj)
1497 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1498 self.assertEqual(bytes(obj_decoded), bytes(obj))
1499 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1500 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1501 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1503 obj_decoded.expl_llen,
1504 len(len_encode(len(obj_encoded))),
1506 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1507 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1510 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1512 self.assertEqual(obj_decoded.expl_offset, offset)
1513 if isinstance(value, tuple):
1514 self.assertSetEqual(set(value), set(obj_decoded.named))
1517 assert_exceeding_data(
1519 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1523 @given(integers(min_value=1, max_value=255))
1524 def test_bad_zero_value(self, pad_size):
1525 with self.assertRaises(DecodeError):
1526 BitString().decode(b"".join((
1527 BitString.tag_default,
1532 def test_go_vectors_invalid(self):
1538 with self.assertRaises(DecodeError):
1539 BitString().decode(b"".join((
1540 BitString.tag_default,
1545 def test_go_vectors_valid(self):
1546 obj, _ = BitString().decode(b"".join((
1547 BitString.tag_default,
1551 self.assertEqual(bytes(obj), b"")
1552 self.assertEqual(obj.bit_len, 0)
1554 obj, _ = BitString().decode(b"".join((
1555 BitString.tag_default,
1559 self.assertEqual(bytes(obj), b"\x00")
1560 self.assertEqual(obj.bit_len, 1)
1562 obj = BitString((16, b"\x82\x40"))
1563 self.assertTrue(obj[0])
1564 self.assertFalse(obj[1])
1565 self.assertTrue(obj[6])
1566 self.assertTrue(obj[9])
1567 self.assertFalse(obj[17])
1570 integers(min_value=1, max_value=30),
1573 binary(min_size=1, max_size=5),
1575 binary(min_size=1, max_size=5),
1583 lists(booleans(), min_size=1),
1586 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1587 def chunk_constructed(contents):
1589 tag_encode(form=TagFormConstructed, num=3) +
1591 b"".join(BitString(content).encode() for content in contents) +
1595 payload_expected = b""
1596 bit_len_expected = 0
1597 for chunk_input in chunk_inputs:
1598 if isinstance(chunk_input, binary_type):
1599 chunks.append(BitString(chunk_input).encode())
1600 payload_expected += chunk_input
1601 bit_len_expected += len(chunk_input) * 8
1603 chunks.append(chunk_constructed(chunk_input))
1604 payload = b"".join(chunk_input)
1605 payload_expected += payload
1606 bit_len_expected += len(payload) * 8
1607 chunk_last = BitString("'%s'B" % "".join(
1608 "1" if bit else "0" for bit in chunk_last_bits
1610 payload_expected += bytes(chunk_last)
1611 bit_len_expected += chunk_last.bit_len
1612 encoded_indefinite = (
1613 tag_encode(form=TagFormConstructed, num=impl) +
1616 chunk_last.encode() +
1619 encoded_definite = (
1620 tag_encode(form=TagFormConstructed, num=impl) +
1621 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1625 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1626 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1627 for lenindef_expected, encoded in (
1628 (True, encoded_indefinite),
1629 (False, encoded_definite),
1631 obj, tail = BitString(impl=tag_encode(impl)).decode(
1633 ctx={"bered": True},
1635 self.assertSequenceEqual(tail, junk)
1636 self.assertEqual(obj.bit_len, bit_len_expected)
1637 self.assertSequenceEqual(bytes(obj), payload_expected)
1638 self.assertTrue(obj.ber_encoded)
1639 self.assertEqual(obj.lenindef, lenindef_expected)
1640 self.assertTrue(obj.bered)
1642 self.assertTrue(obj.ber_encoded)
1643 self.assertEqual(obj.lenindef, lenindef_expected)
1644 self.assertTrue(obj.bered)
1645 self.assertEqual(len(encoded), obj.tlvlen)
1648 pprint(obj, big_blobs=True, with_decode_path=True)
1651 integers(min_value=0),
1654 def test_ber_definite_too_short(self, offset, decode_path):
1655 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1657 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1659 decode_path=decode_path,
1660 ctx={"bered": True},
1662 self.assertEqual(err.exception.decode_path, decode_path)
1663 self.assertEqual(err.exception.offset, offset)
1666 integers(min_value=0),
1669 def test_ber_definite_no_data(self, offset, decode_path):
1670 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1672 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1674 decode_path=decode_path,
1675 ctx={"bered": True},
1677 self.assertEqual(err.exception.decode_path, decode_path)
1678 self.assertEqual(err.exception.offset, offset)
1681 integers(min_value=0),
1683 integers(min_value=1, max_value=3),
1685 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1686 bs = BitString(b"data").encode()
1687 with self.assertRaises(NotEnoughData) as err:
1689 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1691 decode_path=decode_path,
1692 ctx={"bered": True},
1694 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1695 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1698 integers(min_value=0),
1700 integers(min_value=1, max_value=3),
1702 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1703 bs = BitString(b"data").encode()
1704 bs_longer = BitString(b"data-longer").encode()
1705 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1708 tag_encode(3, form=TagFormConstructed) +
1709 len_encode((chunks + 1) * len(bs)) +
1714 decode_path=decode_path,
1715 ctx={"bered": True},
1717 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1718 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1721 integers(min_value=0),
1724 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1725 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1727 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1729 decode_path=decode_path,
1730 ctx={"bered": True},
1732 self.assertEqual(err.exception.decode_path, decode_path)
1733 self.assertEqual(err.exception.offset, offset)
1735 @given(data_strategy())
1736 def test_ber_indefinite_not_multiple(self, d):
1737 bs_short = BitString("'A'H").encode()
1738 bs_full = BitString("'AA'H").encode()
1739 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1740 chunks.append(bs_short)
1741 d.draw(permutations(chunks))
1742 chunks.append(bs_short)
1743 offset = d.draw(integers(min_value=0))
1744 decode_path = d.draw(decode_path_strat)
1745 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1748 tag_encode(3, form=TagFormConstructed) +
1754 decode_path=decode_path,
1755 ctx={"bered": True},
1758 err.exception.decode_path,
1759 decode_path + (str(chunks.index(bs_short)),),
1762 err.exception.offset,
1763 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1766 def test_x690_vector(self):
1767 vector = BitString("'0A3B5F291CD'H")
1768 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1769 self.assertSequenceEqual(tail, b"")
1770 self.assertEqual(obj, vector)
1771 obj, tail = BitString().decode(
1772 hexdec("23800303000A3B0305045F291CD00000"),
1773 ctx={"bered": True},
1775 self.assertSequenceEqual(tail, b"")
1776 self.assertEqual(obj, vector)
1777 self.assertTrue(obj.ber_encoded)
1778 self.assertTrue(obj.lenindef)
1779 self.assertTrue(obj.bered)
1781 self.assertTrue(obj.ber_encoded)
1782 self.assertTrue(obj.lenindef)
1783 self.assertTrue(obj.bered)
1787 def octet_string_values_strategy(draw, do_expl=False):
1788 bound_min, bound_max = sorted(draw(sets(
1789 integers(min_value=0, max_value=1 << 7),
1793 value = draw(one_of(
1795 binary(min_size=bound_min, max_size=bound_max),
1797 default = draw(one_of(
1799 binary(min_size=bound_min, max_size=bound_max),
1802 if draw(booleans()):
1803 bounds = (bound_min, bound_max)
1807 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1809 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1810 optional = draw(one_of(none(), booleans()))
1812 draw(integers(min_value=0)),
1813 draw(integers(min_value=0)),
1814 draw(integers(min_value=0)),
1816 return (value, bounds, impl, expl, default, optional, _decoded)
1819 class OctetStringInherited(OctetString):
1823 class TestOctetString(CommonMixin, TestCase):
1824 base_klass = OctetString
1826 def test_invalid_value_type(self):
1827 with self.assertRaises(InvalidValueType) as err:
1828 OctetString(text_type(123))
1832 def test_optional(self, optional):
1833 obj = OctetString(default=OctetString(b""), optional=optional)
1834 self.assertTrue(obj.optional)
1837 def test_ready(self, value):
1839 self.assertFalse(obj.ready)
1842 pprint(obj, big_blobs=True, with_decode_path=True)
1843 with self.assertRaises(ObjNotReady) as err:
1846 obj = OctetString(value)
1847 self.assertTrue(obj.ready)
1850 pprint(obj, big_blobs=True, with_decode_path=True)
1852 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1853 def test_comparison(self, value1, value2, tag1, tag2):
1854 for klass in (OctetString, OctetStringInherited):
1855 obj1 = klass(value1)
1856 obj2 = klass(value2)
1857 self.assertEqual(obj1 == obj2, value1 == value2)
1858 self.assertEqual(obj1 != obj2, value1 != value2)
1859 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1860 obj1 = klass(value1, impl=tag1)
1861 obj2 = klass(value1, impl=tag2)
1862 self.assertEqual(obj1 == obj2, tag1 == tag2)
1863 self.assertEqual(obj1 != obj2, tag1 != tag2)
1865 @given(lists(binary()))
1866 def test_sorted_works(self, values):
1867 self.assertSequenceEqual(
1868 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1872 @given(data_strategy())
1873 def test_bounds_satisfied(self, d):
1874 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1875 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1876 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1877 OctetString(value=value, bounds=(bound_min, bound_max))
1879 @given(data_strategy())
1880 def test_bounds_unsatisfied(self, d):
1881 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1882 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1883 value = d.draw(binary(max_size=bound_min - 1))
1884 with self.assertRaises(BoundsError) as err:
1885 OctetString(value=value, bounds=(bound_min, bound_max))
1887 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1888 OctetString(bounds=(bound_min, bound_max)).decode(
1889 OctetString(value).encode()
1892 value = d.draw(binary(min_size=bound_max + 1))
1893 with self.assertRaises(BoundsError) as err:
1894 OctetString(value=value, bounds=(bound_min, bound_max))
1896 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1897 OctetString(bounds=(bound_min, bound_max)).decode(
1898 OctetString(value).encode()
1902 @given(data_strategy())
1903 def test_call(self, d):
1904 for klass in (OctetString, OctetStringInherited):
1913 ) = d.draw(octet_string_values_strategy())
1914 obj_initial = klass(
1920 optional_initial or False,
1931 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1932 if (default is None) and (obj_initial.default is not None):
1935 (bounds is None) and
1936 (value is not None) and
1937 (bounds_initial is not None) and
1938 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1942 (bounds is None) and
1943 (default is not None) and
1944 (bounds_initial is not None) and
1945 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1948 obj = obj_initial(value, bounds, impl, expl, default, optional)
1950 value_expected = default if value is None else value
1952 default_initial if value_expected is None
1955 self.assertEqual(obj, value_expected)
1956 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1957 self.assertEqual(obj.expl_tag, expl or expl_initial)
1960 default_initial if default is None else default,
1962 if obj.default is None:
1963 optional = optional_initial if optional is None else optional
1964 optional = False if optional is None else optional
1967 self.assertEqual(obj.optional, optional)
1969 (obj._bound_min, obj._bound_max),
1970 bounds or bounds_initial or (0, float("+inf")),
1973 @given(octet_string_values_strategy())
1974 def test_copy(self, values):
1975 for klass in (OctetString, OctetStringInherited):
1976 obj = klass(*values)
1977 for copy_func in copy_funcs:
1978 obj_copied = copy_func(obj)
1979 self.assert_copied_basic_fields(obj, obj_copied)
1980 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1981 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1982 self.assertEqual(obj._value, obj_copied._value)
1986 integers(min_value=1).map(tag_encode),
1988 def test_stripped(self, value, tag_impl):
1989 obj = OctetString(value, impl=tag_impl)
1990 with self.assertRaises(NotEnoughData):
1991 obj.decode(obj.encode()[:-1])
1995 integers(min_value=1).map(tag_ctxc),
1997 def test_stripped_expl(self, value, tag_expl):
1998 obj = OctetString(value, expl=tag_expl)
1999 with self.assertRaises(NotEnoughData):
2000 obj.decode(obj.encode()[:-1])
2003 integers(min_value=31),
2004 integers(min_value=0),
2007 def test_bad_tag(self, tag, offset, decode_path):
2008 with self.assertRaises(DecodeError) as err:
2009 OctetString().decode(
2010 tag_encode(tag)[:-1],
2012 decode_path=decode_path,
2015 self.assertEqual(err.exception.offset, offset)
2016 self.assertEqual(err.exception.decode_path, decode_path)
2019 integers(min_value=128),
2020 integers(min_value=0),
2023 def test_bad_len(self, l, offset, decode_path):
2024 with self.assertRaises(DecodeError) as err:
2025 OctetString().decode(
2026 OctetString.tag_default + len_encode(l)[:-1],
2028 decode_path=decode_path,
2031 self.assertEqual(err.exception.offset, offset)
2032 self.assertEqual(err.exception.decode_path, decode_path)
2035 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2036 integers(min_value=0),
2039 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2040 value, bound_min = list(sorted(ints))
2042 class String(OctetString):
2043 bounds = (bound_min, bound_min)
2044 with self.assertRaises(DecodeError) as err:
2046 OctetString(b"\x00" * value).encode(),
2048 decode_path=decode_path,
2051 self.assertEqual(err.exception.offset, offset)
2052 self.assertEqual(err.exception.decode_path, decode_path)
2054 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2056 octet_string_values_strategy(),
2058 integers(min_value=1).map(tag_ctxc),
2059 integers(min_value=0),
2062 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2063 for klass in (OctetString, OctetStringInherited):
2064 _, _, _, _, default, optional, _decoded = values
2073 pprint(obj, big_blobs=True, with_decode_path=True)
2074 self.assertFalse(obj.expled)
2075 obj_encoded = obj.encode()
2076 obj_expled = obj(value, expl=tag_expl)
2077 self.assertTrue(obj_expled.expled)
2079 list(obj_expled.pps())
2080 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2081 obj_expled_encoded = obj_expled.encode()
2082 ctx_copied = deepcopy(ctx_dummy)
2083 obj_decoded, tail = obj_expled.decode(
2084 obj_expled_encoded + tail_junk,
2088 self.assertDictEqual(ctx_copied, ctx_dummy)
2090 list(obj_decoded.pps())
2091 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2092 self.assertEqual(tail, tail_junk)
2093 self.assertEqual(obj_decoded, obj_expled)
2094 self.assertNotEqual(obj_decoded, obj)
2095 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2096 self.assertEqual(bytes(obj_decoded), bytes(obj))
2097 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2098 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2099 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2101 obj_decoded.expl_llen,
2102 len(len_encode(len(obj_encoded))),
2104 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2105 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2108 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2110 self.assertEqual(obj_decoded.expl_offset, offset)
2111 assert_exceeding_data(
2113 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2118 integers(min_value=1, max_value=30),
2121 binary(min_size=1, max_size=5),
2123 binary(min_size=1, max_size=5),
2133 def test_constructed(self, impl, chunk_inputs, junk):
2134 def chunk_constructed(contents):
2136 tag_encode(form=TagFormConstructed, num=4) +
2138 b"".join(OctetString(content).encode() for content in contents) +
2142 payload_expected = b""
2143 for chunk_input in chunk_inputs:
2144 if isinstance(chunk_input, binary_type):
2145 chunks.append(OctetString(chunk_input).encode())
2146 payload_expected += chunk_input
2148 chunks.append(chunk_constructed(chunk_input))
2149 payload = b"".join(chunk_input)
2150 payload_expected += payload
2151 encoded_indefinite = (
2152 tag_encode(form=TagFormConstructed, num=impl) +
2157 encoded_definite = (
2158 tag_encode(form=TagFormConstructed, num=impl) +
2159 len_encode(len(b"".join(chunks))) +
2162 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2163 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2164 for lenindef_expected, encoded in (
2165 (True, encoded_indefinite),
2166 (False, encoded_definite),
2168 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2170 ctx={"bered": True},
2172 self.assertSequenceEqual(tail, junk)
2173 self.assertSequenceEqual(bytes(obj), payload_expected)
2174 self.assertTrue(obj.ber_encoded)
2175 self.assertEqual(obj.lenindef, lenindef_expected)
2176 self.assertTrue(obj.bered)
2178 self.assertTrue(obj.ber_encoded)
2179 self.assertEqual(obj.lenindef, lenindef_expected)
2180 self.assertTrue(obj.bered)
2181 self.assertEqual(len(encoded), obj.tlvlen)
2184 pprint(obj, big_blobs=True, with_decode_path=True)
2187 integers(min_value=0),
2190 def test_ber_definite_too_short(self, offset, decode_path):
2191 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2192 OctetString().decode(
2193 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2195 decode_path=decode_path,
2196 ctx={"bered": True},
2198 self.assertEqual(err.exception.decode_path, decode_path)
2199 self.assertEqual(err.exception.offset, offset)
2202 integers(min_value=0),
2204 integers(min_value=1, max_value=3),
2206 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2207 bs = OctetString(b"data").encode()
2208 with self.assertRaises(NotEnoughData) as err:
2209 OctetString().decode(
2210 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2212 decode_path=decode_path,
2213 ctx={"bered": True},
2215 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2216 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2219 integers(min_value=0),
2221 integers(min_value=1, max_value=3),
2223 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2224 bs = OctetString(b"data").encode()
2225 bs_longer = OctetString(b"data-longer").encode()
2226 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2227 OctetString().decode(
2229 tag_encode(4, form=TagFormConstructed) +
2230 len_encode((chunks + 1) * len(bs)) +
2235 decode_path=decode_path,
2236 ctx={"bered": True},
2238 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2239 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2243 def null_values_strategy(draw, do_expl=False):
2247 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2249 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2250 optional = draw(one_of(none(), booleans()))
2252 draw(integers(min_value=0)),
2253 draw(integers(min_value=0)),
2254 draw(integers(min_value=0)),
2256 return (impl, expl, optional, _decoded)
2259 class NullInherited(Null):
2263 class TestNull(CommonMixin, TestCase):
2266 def test_ready(self):
2268 self.assertTrue(obj.ready)
2271 pprint(obj, big_blobs=True, with_decode_path=True)
2273 @given(binary(), binary())
2274 def test_comparison(self, tag1, tag2):
2275 for klass in (Null, NullInherited):
2276 obj1 = klass(impl=tag1)
2277 obj2 = klass(impl=tag2)
2278 self.assertEqual(obj1 == obj2, tag1 == tag2)
2279 self.assertEqual(obj1 != obj2, tag1 != tag2)
2280 self.assertNotEqual(obj1, tag2)
2282 @given(data_strategy())
2283 def test_call(self, d):
2284 for klass in (Null, NullInherited):
2290 ) = d.draw(null_values_strategy())
2291 obj_initial = klass(
2294 optional=optional_initial or False,
2295 _decoded=_decoded_initial,
2302 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2303 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2304 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2305 self.assertEqual(obj.expl_tag, expl or expl_initial)
2306 optional = optional_initial if optional is None else optional
2307 optional = False if optional is None else optional
2308 self.assertEqual(obj.optional, optional)
2310 @given(null_values_strategy())
2311 def test_copy(self, values):
2312 for klass in (Null, NullInherited):
2313 impl, expl, optional, _decoded = values
2317 optional=optional or False,
2320 for copy_func in copy_funcs:
2321 obj_copied = copy_func(obj)
2322 self.assert_copied_basic_fields(obj, obj_copied)
2324 @given(integers(min_value=1).map(tag_encode))
2325 def test_stripped(self, tag_impl):
2326 obj = Null(impl=tag_impl)
2327 with self.assertRaises(NotEnoughData):
2328 obj.decode(obj.encode()[:-1])
2330 @given(integers(min_value=1).map(tag_ctxc))
2331 def test_stripped_expl(self, tag_expl):
2332 obj = Null(expl=tag_expl)
2333 with self.assertRaises(NotEnoughData):
2334 obj.decode(obj.encode()[:-1])
2337 integers(min_value=31),
2338 integers(min_value=0),
2341 def test_bad_tag(self, tag, offset, decode_path):
2342 with self.assertRaises(DecodeError) as err:
2344 tag_encode(tag)[:-1],
2346 decode_path=decode_path,
2349 self.assertEqual(err.exception.offset, offset)
2350 self.assertEqual(err.exception.decode_path, decode_path)
2353 integers(min_value=128),
2354 integers(min_value=0),
2357 def test_bad_len(self, l, offset, decode_path):
2358 with self.assertRaises(DecodeError) as err:
2360 Null.tag_default + len_encode(l)[:-1],
2362 decode_path=decode_path,
2365 self.assertEqual(err.exception.offset, offset)
2366 self.assertEqual(err.exception.decode_path, decode_path)
2368 @given(binary(min_size=1))
2369 def test_tag_mismatch(self, impl):
2370 assume(impl != Null.tag_default)
2371 with self.assertRaises(TagMismatch):
2372 Null(impl=impl).decode(Null().encode())
2375 null_values_strategy(),
2376 integers(min_value=1).map(tag_ctxc),
2377 integers(min_value=0),
2380 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2381 for klass in (Null, NullInherited):
2382 _, _, optional, _decoded = values
2383 obj = klass(optional=optional, _decoded=_decoded)
2386 pprint(obj, big_blobs=True, with_decode_path=True)
2387 self.assertFalse(obj.expled)
2388 obj_encoded = obj.encode()
2389 obj_expled = obj(expl=tag_expl)
2390 self.assertTrue(obj_expled.expled)
2392 list(obj_expled.pps())
2393 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2394 obj_expled_encoded = obj_expled.encode()
2395 ctx_copied = deepcopy(ctx_dummy)
2396 obj_decoded, tail = obj_expled.decode(
2397 obj_expled_encoded + tail_junk,
2401 self.assertDictEqual(ctx_copied, ctx_dummy)
2403 list(obj_decoded.pps())
2404 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2405 self.assertEqual(tail, tail_junk)
2406 self.assertEqual(obj_decoded, obj_expled)
2407 self.assertNotEqual(obj_decoded, obj)
2408 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2409 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2410 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2412 obj_decoded.expl_llen,
2413 len(len_encode(len(obj_encoded))),
2415 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2416 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2419 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2421 self.assertEqual(obj_decoded.expl_offset, offset)
2422 assert_exceeding_data(
2424 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2428 @given(integers(min_value=1))
2429 def test_invalid_len(self, l):
2430 with self.assertRaises(InvalidLength):
2431 Null().decode(b"".join((
2438 def oid_strategy(draw):
2439 first_arc = draw(integers(min_value=0, max_value=2))
2441 if first_arc in (0, 1):
2442 second_arc = draw(integers(min_value=0, max_value=39))
2444 second_arc = draw(integers(min_value=0))
2445 other_arcs = draw(lists(integers(min_value=0)))
2446 return tuple([first_arc, second_arc] + other_arcs)
2450 def oid_values_strategy(draw, do_expl=False):
2451 value = draw(one_of(none(), oid_strategy()))
2455 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2457 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2458 default = draw(one_of(none(), oid_strategy()))
2459 optional = draw(one_of(none(), booleans()))
2461 draw(integers(min_value=0)),
2462 draw(integers(min_value=0)),
2463 draw(integers(min_value=0)),
2465 return (value, impl, expl, default, optional, _decoded)
2468 class ObjectIdentifierInherited(ObjectIdentifier):
2472 class TestObjectIdentifier(CommonMixin, TestCase):
2473 base_klass = ObjectIdentifier
2475 def test_invalid_value_type(self):
2476 with self.assertRaises(InvalidValueType) as err:
2477 ObjectIdentifier(123)
2481 def test_optional(self, optional):
2482 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2483 self.assertTrue(obj.optional)
2485 @given(oid_strategy())
2486 def test_ready(self, value):
2487 obj = ObjectIdentifier()
2488 self.assertFalse(obj.ready)
2491 pprint(obj, big_blobs=True, with_decode_path=True)
2492 with self.assertRaises(ObjNotReady) as err:
2495 obj = ObjectIdentifier(value)
2496 self.assertTrue(obj.ready)
2497 self.assertFalse(obj.ber_encoded)
2500 pprint(obj, big_blobs=True, with_decode_path=True)
2503 @given(oid_strategy(), oid_strategy(), binary(), binary())
2504 def test_comparison(self, value1, value2, tag1, tag2):
2505 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2506 obj1 = klass(value1)
2507 obj2 = klass(value2)
2508 self.assertEqual(obj1 == obj2, value1 == value2)
2509 self.assertEqual(obj1 != obj2, value1 != value2)
2510 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2511 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2512 obj1 = klass(value1, impl=tag1)
2513 obj2 = klass(value1, impl=tag2)
2514 self.assertEqual(obj1 == obj2, tag1 == tag2)
2515 self.assertEqual(obj1 != obj2, tag1 != tag2)
2517 @given(lists(oid_strategy()))
2518 def test_sorted_works(self, values):
2519 self.assertSequenceEqual(
2520 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2524 @given(data_strategy())
2525 def test_call(self, d):
2526 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2534 ) = d.draw(oid_values_strategy())
2535 obj_initial = klass(
2536 value=value_initial,
2539 default=default_initial,
2540 optional=optional_initial or False,
2541 _decoded=_decoded_initial,
2550 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2559 value_expected = default if value is None else value
2561 default_initial if value_expected is None
2564 self.assertEqual(obj, value_expected)
2565 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2566 self.assertEqual(obj.expl_tag, expl or expl_initial)
2569 default_initial if default is None else default,
2571 if obj.default is None:
2572 optional = optional_initial if optional is None else optional
2573 optional = False if optional is None else optional
2576 self.assertEqual(obj.optional, optional)
2578 @given(oid_values_strategy())
2579 def test_copy(self, values):
2580 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2597 for copy_func in copy_funcs:
2598 obj_copied = copy_func(obj)
2599 self.assert_copied_basic_fields(obj, obj_copied)
2600 self.assertEqual(obj._value, obj_copied._value)
2602 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2605 integers(min_value=1).map(tag_encode),
2607 def test_stripped(self, value, tag_impl):
2608 obj = ObjectIdentifier(value, impl=tag_impl)
2609 with self.assertRaises(NotEnoughData):
2610 obj.decode(obj.encode()[:-1])
2614 integers(min_value=1).map(tag_ctxc),
2616 def test_stripped_expl(self, value, tag_expl):
2617 obj = ObjectIdentifier(value, expl=tag_expl)
2618 with self.assertRaises(NotEnoughData):
2619 obj.decode(obj.encode()[:-1])
2622 integers(min_value=31),
2623 integers(min_value=0),
2626 def test_bad_tag(self, tag, offset, decode_path):
2627 with self.assertRaises(DecodeError) as err:
2628 ObjectIdentifier().decode(
2629 tag_encode(tag)[:-1],
2631 decode_path=decode_path,
2634 self.assertEqual(err.exception.offset, offset)
2635 self.assertEqual(err.exception.decode_path, decode_path)
2638 integers(min_value=128),
2639 integers(min_value=0),
2642 def test_bad_len(self, l, offset, decode_path):
2643 with self.assertRaises(DecodeError) as err:
2644 ObjectIdentifier().decode(
2645 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2647 decode_path=decode_path,
2650 self.assertEqual(err.exception.offset, offset)
2651 self.assertEqual(err.exception.decode_path, decode_path)
2653 def test_zero_oid(self):
2654 with self.assertRaises(NotEnoughData):
2655 ObjectIdentifier().decode(
2656 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2659 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2660 @given(oid_strategy())
2661 def test_unfinished_oid(self, value):
2662 assume(list(value)[-1] > 255)
2663 obj_encoded = ObjectIdentifier(value).encode()
2664 obj, _ = ObjectIdentifier().decode(obj_encoded)
2665 data = obj_encoded[obj.tlen + obj.llen:-1]
2667 ObjectIdentifier.tag_default,
2668 len_encode(len(data)),
2671 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2674 @given(integers(min_value=0))
2675 def test_invalid_short(self, value):
2676 with self.assertRaises(InvalidOID):
2677 ObjectIdentifier((value,))
2678 with self.assertRaises(InvalidOID):
2679 ObjectIdentifier("%d" % value)
2681 @given(integers(min_value=3), integers(min_value=0))
2682 def test_invalid_first_arc(self, first_arc, second_arc):
2683 with self.assertRaises(InvalidOID):
2684 ObjectIdentifier((first_arc, second_arc))
2685 with self.assertRaises(InvalidOID):
2686 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2688 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2689 def test_invalid_second_arc(self, first_arc, second_arc):
2690 with self.assertRaises(InvalidOID):
2691 ObjectIdentifier((first_arc, second_arc))
2692 with self.assertRaises(InvalidOID):
2693 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2695 @given(text(alphabet=ascii_letters + ".", min_size=1))
2696 def test_junk(self, oid):
2697 with self.assertRaises(InvalidOID):
2698 ObjectIdentifier(oid)
2700 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2701 @given(oid_strategy())
2702 def test_validness(self, oid):
2703 obj = ObjectIdentifier(oid)
2704 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2707 pprint(obj, big_blobs=True, with_decode_path=True)
2709 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2711 oid_values_strategy(),
2713 integers(min_value=1).map(tag_ctxc),
2714 integers(min_value=0),
2717 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2718 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2719 _, _, _, default, optional, _decoded = values
2728 pprint(obj, big_blobs=True, with_decode_path=True)
2729 self.assertFalse(obj.expled)
2730 obj_encoded = obj.encode()
2731 obj_expled = obj(value, expl=tag_expl)
2732 self.assertTrue(obj_expled.expled)
2734 list(obj_expled.pps())
2735 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2736 obj_expled_encoded = obj_expled.encode()
2737 ctx_copied = deepcopy(ctx_dummy)
2738 obj_decoded, tail = obj_expled.decode(
2739 obj_expled_encoded + tail_junk,
2743 self.assertDictEqual(ctx_copied, ctx_dummy)
2745 list(obj_decoded.pps())
2746 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2747 self.assertEqual(tail, tail_junk)
2748 self.assertEqual(obj_decoded, obj_expled)
2749 self.assertNotEqual(obj_decoded, obj)
2750 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2751 self.assertEqual(tuple(obj_decoded), tuple(obj))
2752 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2753 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2754 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2756 obj_decoded.expl_llen,
2757 len(len_encode(len(obj_encoded))),
2759 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2760 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2763 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2765 self.assertEqual(obj_decoded.expl_offset, offset)
2766 assert_exceeding_data(
2768 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2773 oid_strategy().map(ObjectIdentifier),
2774 oid_strategy().map(ObjectIdentifier),
2776 def test_add(self, oid1, oid2):
2777 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2778 for oid_to_add in (oid2, tuple(oid2)):
2779 self.assertEqual(oid1 + oid_to_add, oid_expect)
2780 with self.assertRaises(InvalidValueType):
2783 def test_go_vectors_valid(self):
2784 for data, expect in (
2786 (b"\x55\x02", (2, 5, 2)),
2787 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2788 (b"\x81\x34\x03", (2, 100, 3)),
2791 ObjectIdentifier().decode(b"".join((
2792 ObjectIdentifier.tag_default,
2793 len_encode(len(data)),
2799 def test_go_vectors_invalid(self):
2800 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2801 with self.assertRaises(DecodeError):
2802 ObjectIdentifier().decode(b"".join((
2803 Integer.tag_default,
2804 len_encode(len(data)),
2808 def test_x690_vector(self):
2810 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2811 ObjectIdentifier((2, 999, 3)),
2814 def test_nonnormalized_first_arc(self):
2816 ObjectIdentifier.tag_default +
2819 ObjectIdentifier((1, 0)).encode()[-1:]
2821 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2822 self.assertTrue(obj.ber_encoded)
2823 self.assertTrue(obj.bered)
2825 self.assertTrue(obj.ber_encoded)
2826 self.assertTrue(obj.bered)
2827 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2828 ObjectIdentifier().decode(tampered)
2830 @given(data_strategy())
2831 def test_negative_arcs(self, d):
2832 oid = list(d.draw(oid_strategy()))
2835 idx = d.draw(integers(min_value=3, max_value=len(oid)))
2837 if oid[idx - 1] == 0:
2839 with self.assertRaises(InvalidOID):
2840 ObjectIdentifier(tuple(oid))
2841 with self.assertRaises(InvalidOID):
2842 ObjectIdentifier(".".join(str(i) for i in oid))
2844 @given(data_strategy())
2845 def test_plused_arcs(self, d):
2846 oid = [str(arc) for arc in d.draw(oid_strategy())]
2847 idx = d.draw(integers(min_value=0, max_value=len(oid)))
2848 oid[idx - 1] = "+" + oid[idx - 1]
2849 with self.assertRaises(InvalidOID):
2850 ObjectIdentifier(".".join(str(i) for i in oid))
2852 @given(data_strategy())
2853 def test_nonnormalized_arcs(self, d):
2854 arcs = d.draw(lists(
2855 integers(min_value=0, max_value=100),
2859 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2860 _, _, lv = tag_strip(dered)
2861 _, _, v = len_decode(lv)
2862 v_no_first_arc = v[1:]
2863 idx_for_tamper = d.draw(integers(
2865 max_value=len(v_no_first_arc) - 1,
2867 tampered = list(bytearray(v_no_first_arc))
2868 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2869 tampered.insert(idx_for_tamper, 0x80)
2870 tampered = bytes(bytearray(tampered))
2872 ObjectIdentifier.tag_default +
2873 len_encode(len(tampered)) +
2876 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2877 self.assertTrue(obj.ber_encoded)
2878 self.assertTrue(obj.bered)
2880 self.assertTrue(obj.ber_encoded)
2881 self.assertTrue(obj.bered)
2882 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2883 ObjectIdentifier().decode(tampered)
2887 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2889 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2890 values = list(draw(sets(
2892 min_size=len(schema),
2893 max_size=len(schema),
2895 schema = list(zip(schema, values))
2896 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2900 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2902 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2903 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2904 optional = draw(one_of(none(), booleans()))
2906 draw(integers(min_value=0)),
2907 draw(integers(min_value=0)),
2908 draw(integers(min_value=0)),
2910 return (schema, value, impl, expl, default, optional, _decoded)
2913 class TestEnumerated(CommonMixin, TestCase):
2914 class EWhatever(Enumerated):
2915 schema = (("whatever", 0),)
2917 base_klass = EWhatever
2919 def test_schema_required(self):
2920 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2923 def test_invalid_value_type(self):
2924 with self.assertRaises(InvalidValueType) as err:
2925 self.base_klass((1, 2))
2928 @given(sets(text_letters(), min_size=2))
2929 def test_unknown_name(self, schema_input):
2930 missing = schema_input.pop()
2932 class E(Enumerated):
2933 schema = [(n, 123) for n in schema_input]
2934 with self.assertRaises(ObjUnknown) as err:
2939 sets(text_letters(), min_size=2),
2940 sets(integers(), min_size=2),
2942 def test_unknown_value(self, schema_input, values_input):
2944 missing_value = values_input.pop()
2945 _input = list(zip(schema_input, values_input))
2947 class E(Enumerated):
2949 with self.assertRaises(DecodeError) as err:
2954 def test_optional(self, optional):
2955 obj = self.base_klass(default="whatever", optional=optional)
2956 self.assertTrue(obj.optional)
2958 def test_ready(self):
2959 obj = self.base_klass()
2960 self.assertFalse(obj.ready)
2963 pprint(obj, big_blobs=True, with_decode_path=True)
2964 with self.assertRaises(ObjNotReady) as err:
2967 obj = self.base_klass("whatever")
2968 self.assertTrue(obj.ready)
2971 pprint(obj, big_blobs=True, with_decode_path=True)
2973 @given(integers(), integers(), binary(), binary())
2974 def test_comparison(self, value1, value2, tag1, tag2):
2975 class E(Enumerated):
2977 ("whatever0", value1),
2978 ("whatever1", value2),
2981 class EInherited(E):
2983 for klass in (E, EInherited):
2984 obj1 = klass(value1)
2985 obj2 = klass(value2)
2986 self.assertEqual(obj1 == obj2, value1 == value2)
2987 self.assertEqual(obj1 != obj2, value1 != value2)
2988 self.assertEqual(obj1 == int(obj2), value1 == value2)
2989 obj1 = klass(value1, impl=tag1)
2990 obj2 = klass(value1, impl=tag2)
2991 self.assertEqual(obj1 == obj2, tag1 == tag2)
2992 self.assertEqual(obj1 != obj2, tag1 != tag2)
2994 @given(data_strategy())
2995 def test_call(self, d):
3004 ) = d.draw(enumerated_values_strategy())
3006 class E(Enumerated):
3007 schema = schema_initial
3009 value=value_initial,
3012 default=default_initial,
3013 optional=optional_initial or False,
3014 _decoded=_decoded_initial,
3024 ) = d.draw(enumerated_values_strategy(
3025 schema=schema_initial,
3026 do_expl=impl_initial is None,
3036 value_expected = default if value is None else value
3038 default_initial if value_expected is None
3043 dict(schema_initial).get(value_expected, value_expected),
3045 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3046 self.assertEqual(obj.expl_tag, expl or expl_initial)
3049 default_initial if default is None else default,
3051 if obj.default is None:
3052 optional = optional_initial if optional is None else optional
3053 optional = False if optional is None else optional
3056 self.assertEqual(obj.optional, optional)
3057 self.assertEqual(obj.specs, dict(schema_initial))
3059 @given(enumerated_values_strategy())
3060 def test_copy(self, values):
3061 schema_input, value, impl, expl, default, optional, _decoded = values
3063 class E(Enumerated):
3064 schema = schema_input
3074 for copy_func in copy_funcs:
3075 obj_copied = copy_func(obj)
3076 self.assert_copied_basic_fields(obj, obj_copied)
3077 self.assertEqual(obj.specs, obj_copied.specs)
3079 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3080 @given(data_strategy())
3081 def test_symmetric(self, d):
3082 schema_input, _, _, _, default, optional, _decoded = d.draw(
3083 enumerated_values_strategy(),
3085 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3086 offset = d.draw(integers(min_value=0))
3087 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3088 tail_junk = d.draw(binary(max_size=5))
3090 class E(Enumerated):
3091 schema = schema_input
3100 pprint(obj, big_blobs=True, with_decode_path=True)
3101 self.assertFalse(obj.expled)
3102 obj_encoded = obj.encode()
3103 obj_expled = obj(value, expl=tag_expl)
3104 self.assertTrue(obj_expled.expled)
3106 list(obj_expled.pps())
3107 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3108 obj_expled_encoded = obj_expled.encode()
3109 ctx_copied = deepcopy(ctx_dummy)
3110 obj_decoded, tail = obj_expled.decode(
3111 obj_expled_encoded + tail_junk,
3115 self.assertDictEqual(ctx_copied, ctx_dummy)
3117 list(obj_decoded.pps())
3118 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3119 self.assertEqual(tail, tail_junk)
3120 self.assertEqual(obj_decoded, obj_expled)
3121 self.assertNotEqual(obj_decoded, obj)
3122 self.assertEqual(int(obj_decoded), int(obj_expled))
3123 self.assertEqual(int(obj_decoded), int(obj))
3124 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3125 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3126 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3128 obj_decoded.expl_llen,
3129 len(len_encode(len(obj_encoded))),
3131 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3132 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3135 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3137 self.assertEqual(obj_decoded.expl_offset, offset)
3138 assert_exceeding_data(
3140 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3146 def string_values_strategy(draw, alphabet, do_expl=False):
3147 bound_min, bound_max = sorted(draw(sets(
3148 integers(min_value=0, max_value=1 << 7),
3152 value = draw(one_of(
3154 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3156 default = draw(one_of(
3158 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3161 if draw(booleans()):
3162 bounds = (bound_min, bound_max)
3166 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3168 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3169 optional = draw(one_of(none(), booleans()))
3171 draw(integers(min_value=0)),
3172 draw(integers(min_value=0)),
3173 draw(integers(min_value=0)),
3175 return (value, bounds, impl, expl, default, optional, _decoded)
3178 class StringMixin(object):
3179 def test_invalid_value_type(self):
3180 with self.assertRaises(InvalidValueType) as err:
3181 self.base_klass((1, 2))
3184 def text_alphabet(self):
3185 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3186 return printable + whitespace
3190 def test_optional(self, optional):
3191 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3192 self.assertTrue(obj.optional)
3194 @given(data_strategy())
3195 def test_ready(self, d):
3196 obj = self.base_klass()
3197 self.assertFalse(obj.ready)
3200 pprint(obj, big_blobs=True, with_decode_path=True)
3202 with self.assertRaises(ObjNotReady) as err:
3205 value = d.draw(text(alphabet=self.text_alphabet()))
3206 obj = self.base_klass(value)
3207 self.assertTrue(obj.ready)
3210 pprint(obj, big_blobs=True, with_decode_path=True)
3213 @given(data_strategy())
3214 def test_comparison(self, d):
3215 value1 = d.draw(text(alphabet=self.text_alphabet()))
3216 value2 = d.draw(text(alphabet=self.text_alphabet()))
3217 tag1 = d.draw(binary(min_size=1))
3218 tag2 = d.draw(binary(min_size=1))
3219 obj1 = self.base_klass(value1)
3220 obj2 = self.base_klass(value2)
3221 self.assertEqual(obj1 == obj2, value1 == value2)
3222 self.assertEqual(obj1 != obj2, value1 != value2)
3223 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3224 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3225 obj1 = self.base_klass(value1, impl=tag1)
3226 obj2 = self.base_klass(value1, impl=tag2)
3227 self.assertEqual(obj1 == obj2, tag1 == tag2)
3228 self.assertEqual(obj1 != obj2, tag1 != tag2)
3230 @given(data_strategy())
3231 def test_bounds_satisfied(self, d):
3232 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3233 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3234 value = d.draw(text(
3235 alphabet=self.text_alphabet(),
3239 self.base_klass(value=value, bounds=(bound_min, bound_max))
3241 @given(data_strategy())
3242 def test_bounds_unsatisfied(self, d):
3243 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3244 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3245 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3246 with self.assertRaises(BoundsError) as err:
3247 self.base_klass(value=value, bounds=(bound_min, bound_max))
3249 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3250 self.base_klass(bounds=(bound_min, bound_max)).decode(
3251 self.base_klass(value).encode()
3254 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3255 with self.assertRaises(BoundsError) as err:
3256 self.base_klass(value=value, bounds=(bound_min, bound_max))
3258 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3259 self.base_klass(bounds=(bound_min, bound_max)).decode(
3260 self.base_klass(value).encode()
3264 @given(data_strategy())
3265 def test_call(self, d):
3274 ) = d.draw(string_values_strategy(self.text_alphabet()))
3275 obj_initial = self.base_klass(
3281 optional_initial or False,
3292 ) = d.draw(string_values_strategy(
3293 self.text_alphabet(),
3294 do_expl=impl_initial is None,
3296 if (default is None) and (obj_initial.default is not None):
3299 (bounds is None) and
3300 (value is not None) and
3301 (bounds_initial is not None) and
3302 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3306 (bounds is None) and
3307 (default is not None) and
3308 (bounds_initial is not None) and
3309 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3312 obj = obj_initial(value, bounds, impl, expl, default, optional)
3314 value_expected = default if value is None else value
3316 default_initial if value_expected is None
3319 self.assertEqual(obj, value_expected)
3320 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3321 self.assertEqual(obj.expl_tag, expl or expl_initial)
3324 default_initial if default is None else default,
3326 if obj.default is None:
3327 optional = optional_initial if optional is None else optional
3328 optional = False if optional is None else optional
3331 self.assertEqual(obj.optional, optional)
3333 (obj._bound_min, obj._bound_max),
3334 bounds or bounds_initial or (0, float("+inf")),
3337 @given(data_strategy())
3338 def test_copy(self, d):
3339 values = d.draw(string_values_strategy(self.text_alphabet()))
3340 obj = self.base_klass(*values)
3341 for copy_func in copy_funcs:
3342 obj_copied = copy_func(obj)
3343 self.assert_copied_basic_fields(obj, obj_copied)
3344 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3345 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3346 self.assertEqual(obj._value, obj_copied._value)
3348 @given(data_strategy())
3349 def test_stripped(self, d):
3350 value = d.draw(text(alphabet=self.text_alphabet()))
3351 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3352 obj = self.base_klass(value, impl=tag_impl)
3353 with self.assertRaises(NotEnoughData):
3354 obj.decode(obj.encode()[:-1])
3356 @given(data_strategy())
3357 def test_stripped_expl(self, d):
3358 value = d.draw(text(alphabet=self.text_alphabet()))
3359 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3360 obj = self.base_klass(value, expl=tag_expl)
3361 with self.assertRaises(NotEnoughData):
3362 obj.decode(obj.encode()[:-1])
3365 integers(min_value=31),
3366 integers(min_value=0),
3369 def test_bad_tag(self, tag, offset, decode_path):
3370 with self.assertRaises(DecodeError) as err:
3371 self.base_klass().decode(
3372 tag_encode(tag)[:-1],
3374 decode_path=decode_path,
3377 self.assertEqual(err.exception.offset, offset)
3378 self.assertEqual(err.exception.decode_path, decode_path)
3381 integers(min_value=128),
3382 integers(min_value=0),
3385 def test_bad_len(self, l, offset, decode_path):
3386 with self.assertRaises(DecodeError) as err:
3387 self.base_klass().decode(
3388 self.base_klass.tag_default + len_encode(l)[:-1],
3390 decode_path=decode_path,
3393 self.assertEqual(err.exception.offset, offset)
3394 self.assertEqual(err.exception.decode_path, decode_path)
3397 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3398 integers(min_value=0),
3401 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3402 value, bound_min = list(sorted(ints))
3404 class String(self.base_klass):
3405 # Multiply this value by four, to satisfy UTF-32 bounds
3406 # (4 bytes per character) validation
3407 bounds = (bound_min * 4, bound_min * 4)
3408 with self.assertRaises(DecodeError) as err:
3410 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3412 decode_path=decode_path,
3415 self.assertEqual(err.exception.offset, offset)
3416 self.assertEqual(err.exception.decode_path, decode_path)
3418 @given(data_strategy())
3419 def test_symmetric(self, d):
3420 values = d.draw(string_values_strategy(self.text_alphabet()))
3421 value = d.draw(text(alphabet=self.text_alphabet()))
3422 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3423 offset = d.draw(integers(min_value=0))
3424 tail_junk = d.draw(binary(max_size=5))
3425 _, _, _, _, default, optional, _decoded = values
3426 obj = self.base_klass(
3434 pprint(obj, big_blobs=True, with_decode_path=True)
3435 self.assertFalse(obj.expled)
3436 obj_encoded = obj.encode()
3437 obj_expled = obj(value, expl=tag_expl)
3438 self.assertTrue(obj_expled.expled)
3440 list(obj_expled.pps())
3441 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3442 obj_expled_encoded = obj_expled.encode()
3443 ctx_copied = deepcopy(ctx_dummy)
3444 obj_decoded, tail = obj_expled.decode(
3445 obj_expled_encoded + tail_junk,
3449 self.assertDictEqual(ctx_copied, ctx_dummy)
3451 list(obj_decoded.pps())
3452 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3453 self.assertEqual(tail, tail_junk)
3454 self.assertEqual(obj_decoded, obj_expled)
3455 self.assertNotEqual(obj_decoded, obj)
3456 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3457 self.assertEqual(bytes(obj_decoded), bytes(obj))
3458 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3459 self.assertEqual(text_type(obj_decoded), text_type(obj))
3460 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3461 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3462 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3464 obj_decoded.expl_llen,
3465 len(len_encode(len(obj_encoded))),
3467 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3468 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3471 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3473 self.assertEqual(obj_decoded.expl_offset, offset)
3474 assert_exceeding_data(
3476 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3481 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3482 base_klass = UTF8String
3485 cyrillic_letters = text(
3486 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3492 class UnicodeDecodeErrorMixin(object):
3493 @given(cyrillic_letters)
3494 def test_unicode_decode_error(self, cyrillic_text):
3495 with self.assertRaises(DecodeError):
3496 self.base_klass(cyrillic_text)
3499 class TestNumericString(StringMixin, CommonMixin, TestCase):
3500 base_klass = NumericString
3502 def text_alphabet(self):
3505 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3506 def test_non_numeric(self, non_numeric_text):
3507 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3508 self.base_klass(non_numeric_text)
3511 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3512 integers(min_value=0),
3515 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3516 value, bound_min = list(sorted(ints))
3518 class String(self.base_klass):
3519 bounds = (bound_min, bound_min)
3520 with self.assertRaises(DecodeError) as err:
3522 self.base_klass(b"1" * value).encode(),
3524 decode_path=decode_path,
3527 self.assertEqual(err.exception.offset, offset)
3528 self.assertEqual(err.exception.decode_path, decode_path)
3531 class TestPrintableString(
3532 UnicodeDecodeErrorMixin,
3537 base_klass = PrintableString
3539 def text_alphabet(self):
3540 return ascii_letters + digits + " '()+,-./:=?"
3542 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3543 def test_non_printable(self, non_printable_text):
3544 with assertRaisesRegex(self, DecodeError, "non-printable"):
3545 self.base_klass(non_printable_text)
3548 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3549 integers(min_value=0),
3552 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3553 value, bound_min = list(sorted(ints))
3555 class String(self.base_klass):
3556 bounds = (bound_min, bound_min)
3557 with self.assertRaises(DecodeError) as err:
3559 self.base_klass(b"1" * value).encode(),
3561 decode_path=decode_path,
3564 self.assertEqual(err.exception.offset, offset)
3565 self.assertEqual(err.exception.decode_path, decode_path)
3567 def test_allowable_invalid_chars(self):
3569 ("*", {"allow_asterisk": True}),
3570 ("&", {"allow_ampersand": True}),
3571 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3574 obj = self.base_klass(s)
3575 for prop in kwargs.keys():
3576 self.assertFalse(getattr(obj, prop))
3578 with assertRaisesRegex(self, DecodeError, "non-printable"):
3580 self.base_klass(s, **kwargs)
3581 klass = self.base_klass(**kwargs)
3583 for prop in kwargs.keys():
3584 self.assertTrue(getattr(obj, prop))
3587 for prop in kwargs.keys():
3588 self.assertTrue(getattr(obj, prop))
3591 class TestTeletexString(
3592 UnicodeDecodeErrorMixin,
3597 base_klass = TeletexString
3600 class TestVideotexString(
3601 UnicodeDecodeErrorMixin,
3606 base_klass = VideotexString
3609 class TestIA5String(
3610 UnicodeDecodeErrorMixin,
3615 base_klass = IA5String
3618 class TestGraphicString(
3619 UnicodeDecodeErrorMixin,
3624 base_klass = GraphicString
3627 class TestVisibleString(
3628 UnicodeDecodeErrorMixin,
3633 base_klass = VisibleString
3635 def test_x690_vector(self):
3636 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3637 self.assertSequenceEqual(tail, b"")
3638 self.assertEqual(str(obj), "Jones")
3639 self.assertFalse(obj.ber_encoded)
3640 self.assertFalse(obj.lenindef)
3641 self.assertFalse(obj.bered)
3643 obj, tail = VisibleString().decode(
3644 hexdec("3A0904034A6F6E04026573"),
3645 ctx={"bered": True},
3647 self.assertSequenceEqual(tail, b"")
3648 self.assertEqual(str(obj), "Jones")
3649 self.assertTrue(obj.ber_encoded)
3650 self.assertFalse(obj.lenindef)
3651 self.assertTrue(obj.bered)
3653 self.assertTrue(obj.ber_encoded)
3654 self.assertFalse(obj.lenindef)
3655 self.assertTrue(obj.bered)
3657 obj, tail = VisibleString().decode(
3658 hexdec("3A8004034A6F6E040265730000"),
3659 ctx={"bered": True},
3661 self.assertSequenceEqual(tail, b"")
3662 self.assertEqual(str(obj), "Jones")
3663 self.assertTrue(obj.ber_encoded)
3664 self.assertTrue(obj.lenindef)
3665 self.assertTrue(obj.bered)
3667 self.assertTrue(obj.ber_encoded)
3668 self.assertTrue(obj.lenindef)
3669 self.assertTrue(obj.bered)
3672 class TestGeneralString(
3673 UnicodeDecodeErrorMixin,
3678 base_klass = GeneralString
3681 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3682 base_klass = UniversalString
3685 class TestBMPString(StringMixin, CommonMixin, TestCase):
3686 base_klass = BMPString
3690 def generalized_time_values_strategy(
3698 if draw(booleans()):
3699 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3701 value = value.replace(microsecond=0)
3703 if draw(booleans()):
3704 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3706 default = default.replace(microsecond=0)
3710 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3712 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3713 optional = draw(one_of(none(), booleans()))
3715 draw(integers(min_value=0)),
3716 draw(integers(min_value=0)),
3717 draw(integers(min_value=0)),
3719 return (value, impl, expl, default, optional, _decoded)
3722 class TimeMixin(object):
3723 def test_invalid_value_type(self):
3724 with self.assertRaises(InvalidValueType) as err:
3725 self.base_klass(datetime.now().timetuple())
3728 @given(data_strategy())
3729 def test_optional(self, d):
3730 default = d.draw(datetimes(
3731 min_value=self.min_datetime,
3732 max_value=self.max_datetime,
3734 optional = d.draw(booleans())
3735 obj = self.base_klass(default=default, optional=optional)
3736 self.assertTrue(obj.optional)
3738 @given(data_strategy())
3739 def test_ready(self, d):
3740 obj = self.base_klass()
3741 self.assertFalse(obj.ready)
3744 pprint(obj, big_blobs=True, with_decode_path=True)
3745 with self.assertRaises(ObjNotReady) as err:
3748 value = d.draw(datetimes(
3749 min_value=self.min_datetime,
3750 max_value=self.max_datetime,
3752 obj = self.base_klass(value)
3753 self.assertTrue(obj.ready)
3756 pprint(obj, big_blobs=True, with_decode_path=True)
3758 @given(data_strategy())
3759 def test_comparison(self, d):
3760 value1 = d.draw(datetimes(
3761 min_value=self.min_datetime,
3762 max_value=self.max_datetime,
3764 value2 = d.draw(datetimes(
3765 min_value=self.min_datetime,
3766 max_value=self.max_datetime,
3768 tag1 = d.draw(binary(min_size=1))
3769 tag2 = d.draw(binary(min_size=1))
3771 value1 = value1.replace(microsecond=0)
3772 value2 = value2.replace(microsecond=0)
3773 obj1 = self.base_klass(value1)
3774 obj2 = self.base_klass(value2)
3775 self.assertEqual(obj1 == obj2, value1 == value2)
3776 self.assertEqual(obj1 != obj2, value1 != value2)
3777 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3778 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3779 obj1 = self.base_klass(value1, impl=tag1)
3780 obj2 = self.base_klass(value1, impl=tag2)
3781 self.assertEqual(obj1 == obj2, tag1 == tag2)
3782 self.assertEqual(obj1 != obj2, tag1 != tag2)
3784 @given(data_strategy())
3785 def test_call(self, d):
3793 ) = d.draw(generalized_time_values_strategy(
3794 min_datetime=self.min_datetime,
3795 max_datetime=self.max_datetime,
3796 omit_ms=self.omit_ms,
3798 obj_initial = self.base_klass(
3799 value=value_initial,
3802 default=default_initial,
3803 optional=optional_initial or False,
3804 _decoded=_decoded_initial,
3813 ) = d.draw(generalized_time_values_strategy(
3814 min_datetime=self.min_datetime,
3815 max_datetime=self.max_datetime,
3816 omit_ms=self.omit_ms,
3817 do_expl=impl_initial is None,
3827 value_expected = default if value is None else value
3829 default_initial if value_expected is None
3832 self.assertEqual(obj, value_expected)
3833 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3834 self.assertEqual(obj.expl_tag, expl or expl_initial)
3837 default_initial if default is None else default,
3839 if obj.default is None:
3840 optional = optional_initial if optional is None else optional
3841 optional = False if optional is None else optional
3844 self.assertEqual(obj.optional, optional)
3846 @given(data_strategy())
3847 def test_copy(self, d):
3848 values = d.draw(generalized_time_values_strategy(
3849 min_datetime=self.min_datetime,
3850 max_datetime=self.max_datetime,
3852 obj = self.base_klass(*values)
3853 for copy_func in copy_funcs:
3854 obj_copied = copy_func(obj)
3855 self.assert_copied_basic_fields(obj, obj_copied)
3856 self.assertEqual(obj._value, obj_copied._value)
3858 @given(data_strategy())
3859 def test_stripped(self, d):
3860 value = d.draw(datetimes(
3861 min_value=self.min_datetime,
3862 max_value=self.max_datetime,
3864 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3865 obj = self.base_klass(value, impl=tag_impl)
3866 with self.assertRaises(NotEnoughData):
3867 obj.decode(obj.encode()[:-1])
3869 @given(data_strategy())
3870 def test_stripped_expl(self, d):
3871 value = d.draw(datetimes(
3872 min_value=self.min_datetime,
3873 max_value=self.max_datetime,
3875 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3876 obj = self.base_klass(value, expl=tag_expl)
3877 with self.assertRaises(NotEnoughData):
3878 obj.decode(obj.encode()[:-1])
3880 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3881 @given(data_strategy())
3882 def test_symmetric(self, d):
3883 values = d.draw(generalized_time_values_strategy(
3884 min_datetime=self.min_datetime,
3885 max_datetime=self.max_datetime,
3887 value = d.draw(datetimes(
3888 min_value=self.min_datetime,
3889 max_value=self.max_datetime,
3891 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3892 offset = d.draw(integers(min_value=0))
3893 tail_junk = d.draw(binary(max_size=5))
3894 _, _, _, default, optional, _decoded = values
3895 obj = self.base_klass(
3903 pprint(obj, big_blobs=True, with_decode_path=True)
3904 self.assertFalse(obj.expled)
3905 obj_encoded = obj.encode()
3906 self.additional_symmetric_check(value, obj_encoded)
3907 obj_expled = obj(value, expl=tag_expl)
3908 self.assertTrue(obj_expled.expled)
3910 list(obj_expled.pps())
3911 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3912 obj_expled_encoded = obj_expled.encode()
3913 ctx_copied = deepcopy(ctx_dummy)
3914 obj_decoded, tail = obj_expled.decode(
3915 obj_expled_encoded + tail_junk,
3919 self.assertDictEqual(ctx_copied, ctx_dummy)
3921 list(obj_decoded.pps())
3922 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3923 self.assertEqual(tail, tail_junk)
3924 self.assertEqual(obj_decoded, obj_expled)
3925 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3926 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3927 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3928 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3929 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3931 obj_decoded.expl_llen,
3932 len(len_encode(len(obj_encoded))),
3934 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3935 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3938 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3940 self.assertEqual(obj_decoded.expl_offset, offset)
3941 assert_exceeding_data(
3943 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3948 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3949 base_klass = GeneralizedTime
3951 min_datetime = datetime(1900, 1, 1)
3952 max_datetime = datetime(9999, 12, 31)
3954 def additional_symmetric_check(self, value, obj_encoded):
3955 if value.microsecond > 0:
3956 self.assertFalse(obj_encoded.endswith(b"0Z"))
3958 def test_x690_vector_valid(self):
3962 b"19920722132100.3Z",
3964 GeneralizedTime(data)
3966 def test_x690_vector_invalid(self):
3969 b"19920622123421.0Z",
3970 b"19920722132100.30Z",
3972 with self.assertRaises(DecodeError) as err:
3973 GeneralizedTime(data)
3976 def test_go_vectors_invalid(self):
3988 b"-20100102030410Z",
3989 b"2010-0102030410Z",
3990 b"2010-0002030410Z",
3991 b"201001-02030410Z",
3992 b"20100102-030410Z",
3993 b"2010010203-0410Z",
3994 b"201001020304-10Z",
3995 # These ones are INVALID in *DER*, but accepted
3996 # by Go's encoding/asn1
3997 b"20100102030405+0607",
3998 b"20100102030405-0607",
4000 with self.assertRaises(DecodeError) as err:
4001 GeneralizedTime(data)
4004 def test_go_vectors_valid(self):
4006 GeneralizedTime(b"20100102030405Z").todatetime(),
4007 datetime(2010, 1, 2, 3, 4, 5, 0),
4012 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4013 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4015 binary(min_size=1, max_size=1),
4017 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4018 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4021 def test_junk(self, part0, part1, part2):
4022 junk = part0 + part1 + part2
4023 assume(not (set(junk) <= set(digits.encode("ascii"))))
4024 with self.assertRaises(DecodeError):
4025 GeneralizedTime().decode(
4026 GeneralizedTime.tag_default +
4027 len_encode(len(junk)) +
4033 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4034 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4036 binary(min_size=1, max_size=1),
4038 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4039 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4042 def test_junk_dm(self, part0, part1, part2):
4043 junk = part0 + part1 + part2
4044 assume(not (set(junk) <= set(digits.encode("ascii"))))
4045 with self.assertRaises(DecodeError):
4046 GeneralizedTime().decode(
4047 GeneralizedTime.tag_default +
4048 len_encode(len(junk)) +
4052 def test_ns_fractions(self):
4053 GeneralizedTime(b"20010101000000.000001Z")
4054 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
4055 GeneralizedTime(b"20010101000000.0000001Z")
4057 def test_non_pure_integers(self):
4059 # b"20000102030405Z,
4066 b"20000102030405.+6Z",
4067 b"20000102030405.-6Z",
4074 b"20000102030405. 6Z",
4081 b"20000102030405.6 Z",
4083 with self.assertRaises(DecodeError):
4084 GeneralizedTime(data)
4087 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4088 base_klass = UTCTime
4090 min_datetime = datetime(2000, 1, 1)
4091 max_datetime = datetime(2049, 12, 31)
4093 def additional_symmetric_check(self, value, obj_encoded):
4096 def test_x690_vector_valid(self):
4104 def test_x690_vector_invalid(self):
4109 with self.assertRaises(DecodeError) as err:
4113 def test_go_vectors_invalid(self):
4139 # These ones are INVALID in *DER*, but accepted
4140 # by Go's encoding/asn1
4141 b"910506164540-0700",
4142 b"910506164540+0730",
4146 with self.assertRaises(DecodeError) as err:
4150 def test_go_vectors_valid(self):
4152 UTCTime(b"910506234540Z").todatetime(),
4153 datetime(1991, 5, 6, 23, 45, 40, 0),
4156 def test_non_pure_integers(self):
4178 with self.assertRaises(DecodeError):
4181 @given(integers(min_value=0, max_value=49))
4182 def test_pre50(self, year):
4184 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4188 @given(integers(min_value=50, max_value=99))
4189 def test_post50(self, year):
4191 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4197 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4198 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4200 binary(min_size=1, max_size=1),
4202 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4203 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4206 def test_junk(self, part0, part1, part2):
4207 junk = part0 + part1 + part2
4208 assume(not (set(junk) <= set(digits.encode("ascii"))))
4209 with self.assertRaises(DecodeError):
4211 UTCTime.tag_default +
4212 len_encode(len(junk)) +
4218 def any_values_strategy(draw, do_expl=False):
4219 value = draw(one_of(none(), binary()))
4222 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4223 optional = draw(one_of(none(), booleans()))
4225 draw(integers(min_value=0)),
4226 draw(integers(min_value=0)),
4227 draw(integers(min_value=0)),
4229 return (value, expl, optional, _decoded)
4232 class AnyInherited(Any):
4236 class TestAny(CommonMixin, TestCase):
4239 def test_invalid_value_type(self):
4240 with self.assertRaises(InvalidValueType) as err:
4245 def test_optional(self, optional):
4246 obj = Any(optional=optional)
4247 self.assertEqual(obj.optional, optional)
4250 def test_ready(self, value):
4252 self.assertFalse(obj.ready)
4255 pprint(obj, big_blobs=True, with_decode_path=True)
4256 with self.assertRaises(ObjNotReady) as err:
4260 self.assertTrue(obj.ready)
4263 pprint(obj, big_blobs=True, with_decode_path=True)
4266 def test_basic(self, value):
4267 integer_encoded = Integer(value).encode()
4269 Any(integer_encoded),
4270 Any(Integer(value)),
4271 Any(Any(Integer(value))),
4273 self.assertSequenceEqual(bytes(obj), integer_encoded)
4275 obj.decode(obj.encode())[0].vlen,
4276 len(integer_encoded),
4280 pprint(obj, big_blobs=True, with_decode_path=True)
4281 self.assertSequenceEqual(obj.encode(), integer_encoded)
4283 @given(binary(), binary())
4284 def test_comparison(self, value1, value2):
4285 for klass in (Any, AnyInherited):
4286 obj1 = klass(value1)
4287 obj2 = klass(value2)
4288 self.assertEqual(obj1 == obj2, value1 == value2)
4289 self.assertEqual(obj1 != obj2, value1 != value2)
4290 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4292 @given(data_strategy())
4293 def test_call(self, d):
4294 for klass in (Any, AnyInherited):
4300 ) = d.draw(any_values_strategy())
4301 obj_initial = klass(
4304 optional_initial or False,
4312 ) = d.draw(any_values_strategy(do_expl=True))
4313 obj = obj_initial(value, expl, optional)
4315 value_expected = None if value is None else value
4316 self.assertEqual(obj, value_expected)
4317 self.assertEqual(obj.expl_tag, expl or expl_initial)
4318 if obj.default is None:
4319 optional = optional_initial if optional is None else optional
4320 optional = False if optional is None else optional
4321 self.assertEqual(obj.optional, optional)
4323 def test_simultaneous_impl_expl(self):
4324 # override it, as Any does not have implicit tag
4327 def test_decoded(self):
4328 # override it, as Any does not have implicit tag
4331 @given(any_values_strategy())
4332 def test_copy(self, values):
4333 for klass in (Any, AnyInherited):
4334 obj = klass(*values)
4335 for copy_func in copy_funcs:
4336 obj_copied = copy_func(obj)
4337 self.assert_copied_basic_fields(obj, obj_copied)
4338 self.assertEqual(obj._value, obj_copied._value)
4340 @given(binary().map(OctetString))
4341 def test_stripped(self, value):
4343 with self.assertRaises(NotEnoughData):
4344 obj.decode(obj.encode()[:-1])
4348 integers(min_value=1).map(tag_ctxc),
4350 def test_stripped_expl(self, value, tag_expl):
4351 obj = Any(value, expl=tag_expl)
4352 with self.assertRaises(NotEnoughData):
4353 obj.decode(obj.encode()[:-1])
4356 integers(min_value=31),
4357 integers(min_value=0),
4360 def test_bad_tag(self, tag, offset, decode_path):
4361 with self.assertRaises(DecodeError) as err:
4363 tag_encode(tag)[:-1],
4365 decode_path=decode_path,
4368 self.assertEqual(err.exception.offset, offset)
4369 self.assertEqual(err.exception.decode_path, decode_path)
4372 integers(min_value=128),
4373 integers(min_value=0),
4376 def test_bad_len(self, l, offset, decode_path):
4377 with self.assertRaises(DecodeError) as err:
4379 Any.tag_default + len_encode(l)[:-1],
4381 decode_path=decode_path,
4384 self.assertEqual(err.exception.offset, offset)
4385 self.assertEqual(err.exception.decode_path, decode_path)
4387 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4389 any_values_strategy(),
4390 integers().map(lambda x: Integer(x).encode()),
4391 integers(min_value=1).map(tag_ctxc),
4392 integers(min_value=0),
4395 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4396 for klass in (Any, AnyInherited):
4397 _, _, optional, _decoded = values
4398 obj = klass(value=value, optional=optional, _decoded=_decoded)
4401 pprint(obj, big_blobs=True, with_decode_path=True)
4402 self.assertFalse(obj.expled)
4403 obj_encoded = obj.encode()
4404 obj_expled = obj(value, expl=tag_expl)
4405 self.assertTrue(obj_expled.expled)
4407 list(obj_expled.pps())
4408 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4409 obj_expled_encoded = obj_expled.encode()
4410 ctx_copied = deepcopy(ctx_dummy)
4411 obj_decoded, tail = obj_expled.decode(
4412 obj_expled_encoded + tail_junk,
4416 self.assertDictEqual(ctx_copied, ctx_dummy)
4418 list(obj_decoded.pps())
4419 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4420 self.assertEqual(tail, tail_junk)
4421 self.assertEqual(obj_decoded, obj_expled)
4422 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4423 self.assertEqual(bytes(obj_decoded), bytes(obj))
4424 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4425 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4426 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4428 obj_decoded.expl_llen,
4429 len(len_encode(len(obj_encoded))),
4431 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4432 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4435 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4437 self.assertEqual(obj_decoded.expl_offset, offset)
4438 self.assertEqual(obj_decoded.tlen, 0)
4439 self.assertEqual(obj_decoded.llen, 0)
4440 self.assertEqual(obj_decoded.vlen, len(value))
4441 assert_exceeding_data(
4443 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4448 integers(min_value=1).map(tag_ctxc),
4449 integers(min_value=0, max_value=3),
4450 integers(min_value=0),
4454 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4455 chunk = Boolean(False, expl=expl).encode()
4457 OctetString.tag_default +
4459 b"".join([chunk] * chunks) +
4462 with self.assertRaises(LenIndefForm):
4466 decode_path=decode_path,
4468 obj, tail = Any().decode(
4471 decode_path=decode_path,
4472 ctx={"bered": True},
4474 self.assertSequenceEqual(tail, junk)
4475 self.assertEqual(obj.offset, offset)
4476 self.assertEqual(obj.tlvlen, len(encoded))
4477 self.assertTrue(obj.lenindef)
4478 self.assertFalse(obj.ber_encoded)
4479 self.assertTrue(obj.bered)
4481 self.assertTrue(obj.lenindef)
4482 self.assertFalse(obj.ber_encoded)
4483 self.assertTrue(obj.bered)
4486 pprint(obj, big_blobs=True, with_decode_path=True)
4487 with self.assertRaises(NotEnoughData) as err:
4491 decode_path=decode_path,
4492 ctx={"bered": True},
4494 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4495 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4497 class SeqOf(SequenceOf):
4498 schema = Boolean(expl=expl)
4500 class Seq(Sequence):
4502 ("type", ObjectIdentifier(defines=((("value",), {
4503 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4508 ("type", ObjectIdentifier("1.2.3")),
4509 ("value", Any(encoded)),
4511 seq_encoded = seq.encode()
4512 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4513 self.assertIsNotNone(seq_decoded["value"].defined)
4515 list(seq_decoded.pps())
4516 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4517 self.assertTrue(seq_decoded.bered)
4518 self.assertFalse(seq_decoded["type"].bered)
4519 self.assertTrue(seq_decoded["value"].bered)
4521 chunk = chunk[:-1] + b"\x01"
4522 chunks = b"".join([chunk] * (chunks + 1))
4523 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4525 ("type", ObjectIdentifier("1.2.3")),
4526 ("value", Any(encoded)),
4528 seq_encoded = seq.encode()
4529 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4530 self.assertIsNotNone(seq_decoded["value"].defined)
4532 list(seq_decoded.pps())
4533 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4534 self.assertTrue(seq_decoded.bered)
4535 self.assertFalse(seq_decoded["type"].bered)
4536 self.assertTrue(seq_decoded["value"].bered)
4540 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4542 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4543 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4545 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4546 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4548 min_size=len(names),
4549 max_size=len(names),
4552 (name, Integer(**tag_kwargs))
4553 for name, tag_kwargs in zip(names, tags)
4556 if value_required or draw(booleans()):
4557 value = draw(tuples(
4558 sampled_from([name for name, _ in schema]),
4559 integers().map(Integer),
4563 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4564 default = draw(one_of(
4566 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4568 optional = draw(one_of(none(), booleans()))
4570 draw(integers(min_value=0)),
4571 draw(integers(min_value=0)),
4572 draw(integers(min_value=0)),
4574 return (schema, value, expl, default, optional, _decoded)
4577 class ChoiceInherited(Choice):
4581 class TestChoice(CommonMixin, TestCase):
4583 schema = (("whatever", Boolean()),)
4586 def test_schema_required(self):
4587 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4590 def test_impl_forbidden(self):
4591 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4592 Choice(impl=b"whatever")
4594 def test_invalid_value_type(self):
4595 with self.assertRaises(InvalidValueType) as err:
4596 self.base_klass(123)
4598 with self.assertRaises(ObjUnknown) as err:
4599 self.base_klass(("whenever", Boolean(False)))
4601 with self.assertRaises(InvalidValueType) as err:
4602 self.base_klass(("whatever", Integer(123)))
4606 def test_optional(self, optional):
4607 obj = self.base_klass(
4608 default=self.base_klass(("whatever", Boolean(False))),
4611 self.assertTrue(obj.optional)
4614 def test_ready(self, value):
4615 obj = self.base_klass()
4616 self.assertFalse(obj.ready)
4619 pprint(obj, big_blobs=True, with_decode_path=True)
4620 self.assertIsNone(obj["whatever"])
4621 with self.assertRaises(ObjNotReady) as err:
4624 obj["whatever"] = Boolean()
4625 self.assertFalse(obj.ready)
4628 pprint(obj, big_blobs=True, with_decode_path=True)
4629 obj["whatever"] = Boolean(value)
4630 self.assertTrue(obj.ready)
4633 pprint(obj, big_blobs=True, with_decode_path=True)
4635 @given(booleans(), booleans())
4636 def test_comparison(self, value1, value2):
4637 class WahlInherited(self.base_klass):
4639 for klass in (self.base_klass, WahlInherited):
4640 obj1 = klass(("whatever", Boolean(value1)))
4641 obj2 = klass(("whatever", Boolean(value2)))
4642 self.assertEqual(obj1 == obj2, value1 == value2)
4643 self.assertEqual(obj1 != obj2, value1 != value2)
4644 self.assertEqual(obj1 == obj2._value, value1 == value2)
4645 self.assertFalse(obj1 == obj2._value[1])
4647 @given(data_strategy())
4648 def test_call(self, d):
4649 for klass in (Choice, ChoiceInherited):
4657 ) = d.draw(choice_values_strategy())
4660 schema = schema_initial
4662 value=value_initial,
4664 default=default_initial,
4665 optional=optional_initial or False,
4666 _decoded=_decoded_initial,
4675 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4676 obj = obj_initial(value, expl, default, optional)
4678 value_expected = default if value is None else value
4680 default_initial if value_expected is None
4683 self.assertEqual(obj.choice, value_expected[0])
4684 self.assertEqual(obj.value, int(value_expected[1]))
4685 self.assertEqual(obj.expl_tag, expl or expl_initial)
4686 default_expect = default_initial if default is None else default
4687 if default_expect is not None:
4688 self.assertEqual(obj.default.choice, default_expect[0])
4689 self.assertEqual(obj.default.value, int(default_expect[1]))
4690 if obj.default is None:
4691 optional = optional_initial if optional is None else optional
4692 optional = False if optional is None else optional
4695 self.assertEqual(obj.optional, optional)
4696 self.assertEqual(obj.specs, obj_initial.specs)
4698 def test_simultaneous_impl_expl(self):
4699 # override it, as Any does not have implicit tag
4702 def test_decoded(self):
4703 # override it, as Any does not have implicit tag
4706 @given(choice_values_strategy())
4707 def test_copy(self, values):
4708 _schema, value, expl, default, optional, _decoded = values
4710 class Wahl(self.base_klass):
4712 register_class(Wahl)
4717 optional=optional or False,
4720 for copy_func in copy_funcs:
4721 obj_copied = copy_func(obj)
4722 self.assertIsNone(obj.tag)
4723 self.assertIsNone(obj_copied.tag)
4724 # hack for assert_copied_basic_fields
4725 obj.tag = "whatever"
4726 obj_copied.tag = "whatever"
4727 self.assert_copied_basic_fields(obj, obj_copied)
4729 self.assertEqual(obj._value, obj_copied._value)
4730 self.assertEqual(obj.specs, obj_copied.specs)
4733 def test_stripped(self, value):
4734 obj = self.base_klass(("whatever", Boolean(value)))
4735 with self.assertRaises(NotEnoughData):
4736 obj.decode(obj.encode()[:-1])
4740 integers(min_value=1).map(tag_ctxc),
4742 def test_stripped_expl(self, value, tag_expl):
4743 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4744 with self.assertRaises(NotEnoughData):
4745 obj.decode(obj.encode()[:-1])
4747 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4748 @given(data_strategy())
4749 def test_symmetric(self, d):
4750 _schema, value, _, default, optional, _decoded = d.draw(
4751 choice_values_strategy(value_required=True)
4753 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4754 offset = d.draw(integers(min_value=0))
4755 tail_junk = d.draw(binary(max_size=5))
4757 class Wahl(self.base_klass):
4767 pprint(obj, big_blobs=True, with_decode_path=True)
4768 self.assertFalse(obj.expled)
4769 obj_encoded = obj.encode()
4770 obj_expled = obj(value, expl=tag_expl)
4771 self.assertTrue(obj_expled.expled)
4773 list(obj_expled.pps())
4774 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4775 obj_expled_encoded = obj_expled.encode()
4776 ctx_copied = deepcopy(ctx_dummy)
4777 obj_decoded, tail = obj_expled.decode(
4778 obj_expled_encoded + tail_junk,
4782 self.assertDictEqual(ctx_copied, ctx_dummy)
4784 list(obj_decoded.pps())
4785 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4786 self.assertEqual(tail, tail_junk)
4787 self.assertEqual(obj_decoded, obj_expled)
4788 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4789 self.assertEqual(obj_decoded.value, obj_expled.value)
4790 self.assertEqual(obj_decoded.choice, obj.choice)
4791 self.assertEqual(obj_decoded.value, obj.value)
4792 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4793 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4794 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4796 obj_decoded.expl_llen,
4797 len(len_encode(len(obj_encoded))),
4799 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4800 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4803 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4805 self.assertEqual(obj_decoded.expl_offset, offset)
4806 self.assertSequenceEqual(
4808 obj_decoded.value.fulloffset - offset:
4809 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4813 assert_exceeding_data(
4815 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4820 def test_set_get(self, value):
4823 ("erste", Boolean()),
4824 ("zweite", Integer()),
4827 with self.assertRaises(ObjUnknown) as err:
4828 obj["whatever"] = "whenever"
4829 with self.assertRaises(InvalidValueType) as err:
4830 obj["zweite"] = Boolean(False)
4831 obj["zweite"] = Integer(value)
4833 with self.assertRaises(ObjUnknown) as err:
4836 self.assertIsNone(obj["erste"])
4837 self.assertEqual(obj["zweite"], Integer(value))
4839 def test_tag_mismatch(self):
4842 ("erste", Boolean()),
4844 int_encoded = Integer(123).encode()
4845 bool_encoded = Boolean(False).encode()
4847 obj.decode(bool_encoded)
4848 with self.assertRaises(TagMismatch):
4849 obj.decode(int_encoded)
4851 def test_tag_mismatch_underlying(self):
4852 class SeqOfBoolean(SequenceOf):
4855 class SeqOfInteger(SequenceOf):
4860 ("erste", SeqOfBoolean()),
4863 int_encoded = SeqOfInteger((Integer(123),)).encode()
4864 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4866 obj.decode(bool_encoded)
4867 with self.assertRaises(TagMismatch) as err:
4868 obj.decode(int_encoded)
4869 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4873 def seq_values_strategy(draw, seq_klass, do_expl=False):
4875 if draw(booleans()):
4877 value._value = draw(dictionaries(
4880 booleans().map(Boolean),
4881 integers().map(Integer),
4885 if draw(booleans()):
4886 schema = list(draw(dictionaries(
4889 booleans().map(Boolean),
4890 integers().map(Integer),
4896 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4898 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4900 if draw(booleans()):
4901 default = seq_klass()
4902 default._value = draw(dictionaries(
4905 booleans().map(Boolean),
4906 integers().map(Integer),
4909 optional = draw(one_of(none(), booleans()))
4911 draw(integers(min_value=0)),
4912 draw(integers(min_value=0)),
4913 draw(integers(min_value=0)),
4915 return (value, schema, impl, expl, default, optional, _decoded)
4919 def sequence_strategy(draw, seq_klass):
4920 inputs = draw(lists(
4922 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4923 tuples(just(Integer), integers(), one_of(none(), integers())),
4928 integers(min_value=1),
4929 min_size=len(inputs),
4930 max_size=len(inputs),
4933 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4934 for tag, expled in zip(tags, draw(lists(
4936 min_size=len(inputs),
4937 max_size=len(inputs),
4941 for i, optional in enumerate(draw(lists(
4942 sampled_from(("required", "optional", "empty")),
4943 min_size=len(inputs),
4944 max_size=len(inputs),
4946 if optional in ("optional", "empty"):
4947 inits[i]["optional"] = True
4948 if optional == "empty":
4950 empties = set(empties)
4951 names = list(draw(sets(
4953 min_size=len(inputs),
4954 max_size=len(inputs),
4957 for i, (klass, value, default) in enumerate(inputs):
4958 schema.append((names[i], klass(default=default, **inits[i])))
4959 seq_name = draw(text_letters())
4960 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4963 for i, (klass, value, default) in enumerate(inputs):
4970 "default_value": None if spec.default is None else default,
4974 expect["optional"] = True
4976 expect["presented"] = True
4977 expect["value"] = value
4979 expect["optional"] = True
4980 if default is not None and default == value:
4981 expect["presented"] = False
4982 seq[name] = klass(value)
4983 expects.append(expect)
4988 def sequences_strategy(draw, seq_klass):
4989 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4991 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4992 for tag, expled in zip(tags, draw(lists(
4999 i for i, is_default in enumerate(draw(lists(
5005 names = list(draw(sets(
5010 seq_expectses = draw(lists(
5011 sequence_strategy(seq_klass=seq_klass),
5015 seqs = [seq for seq, _ in seq_expectses]
5017 for i, (name, seq) in enumerate(zip(names, seqs)):
5020 seq(default=(seq if i in defaulted else None), **inits[i]),
5022 seq_name = draw(text_letters())
5023 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5026 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5029 "expects": expects_inner,
5032 seq_outer[name] = seq_inner
5033 if seq_outer.specs[name].default is None:
5034 expect["presented"] = True
5035 expect_outers.append(expect)
5036 return seq_outer, expect_outers
5039 class SeqMixing(object):
5040 def test_invalid_value_type(self):
5041 with self.assertRaises(InvalidValueType) as err:
5042 self.base_klass(123)
5045 def test_invalid_value_type_set(self):
5046 class Seq(self.base_klass):
5047 schema = (("whatever", Boolean()),)
5049 with self.assertRaises(InvalidValueType) as err:
5050 seq["whatever"] = Integer(123)
5054 def test_optional(self, optional):
5055 obj = self.base_klass(default=self.base_klass(), optional=optional)
5056 self.assertTrue(obj.optional)
5058 @given(data_strategy())
5059 def test_ready(self, d):
5061 str(i): v for i, v in enumerate(d.draw(lists(
5068 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5075 for name in d.draw(permutations(
5076 list(ready.keys()) + list(non_ready.keys()),
5078 schema_input.append((name, Boolean()))
5080 class Seq(self.base_klass):
5081 schema = tuple(schema_input)
5083 for name in ready.keys():
5085 seq[name] = Boolean()
5086 self.assertFalse(seq.ready)
5089 pprint(seq, big_blobs=True, with_decode_path=True)
5090 for name, value in ready.items():
5091 seq[name] = Boolean(value)
5092 self.assertFalse(seq.ready)
5095 pprint(seq, big_blobs=True, with_decode_path=True)
5096 with self.assertRaises(ObjNotReady) as err:
5099 for name, value in non_ready.items():
5100 seq[name] = Boolean(value)
5101 self.assertTrue(seq.ready)
5104 pprint(seq, big_blobs=True, with_decode_path=True)
5106 @given(data_strategy())
5107 def test_call(self, d):
5108 class SeqInherited(self.base_klass):
5110 for klass in (self.base_klass, SeqInherited):
5119 ) = d.draw(seq_values_strategy(seq_klass=klass))
5120 obj_initial = klass(
5126 optional_initial or False,
5137 ) = d.draw(seq_values_strategy(
5139 do_expl=impl_initial is None,
5141 obj = obj_initial(value, impl, expl, default, optional)
5142 value_expected = default if value is None else value
5144 default_initial if value_expected is None
5147 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5148 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5149 self.assertEqual(obj.expl_tag, expl or expl_initial)
5151 {} if obj.default is None else obj.default._value,
5152 getattr(default_initial if default is None else default, "_value", {}),
5154 if obj.default is None:
5155 optional = optional_initial if optional is None else optional
5156 optional = False if optional is None else optional
5159 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5160 self.assertEqual(obj.optional, optional)
5162 @given(data_strategy())
5163 def test_copy(self, d):
5164 class SeqInherited(self.base_klass):
5166 register_class(SeqInherited)
5167 for klass in (self.base_klass, SeqInherited):
5168 values = d.draw(seq_values_strategy(seq_klass=klass))
5169 obj = klass(*values)
5170 for copy_func in copy_funcs:
5171 obj_copied = copy_func(obj)
5172 self.assert_copied_basic_fields(obj, obj_copied)
5173 self.assertEqual(obj.specs, obj_copied.specs)
5174 self.assertEqual(obj._value, obj_copied._value)
5176 @given(data_strategy())
5177 def test_stripped(self, d):
5178 value = d.draw(integers())
5179 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5181 class Seq(self.base_klass):
5183 schema = (("whatever", Integer()),)
5185 seq["whatever"] = Integer(value)
5186 with self.assertRaises(NotEnoughData):
5187 seq.decode(seq.encode()[:-1])
5189 @given(data_strategy())
5190 def test_stripped_expl(self, d):
5191 value = d.draw(integers())
5192 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5194 class Seq(self.base_klass):
5196 schema = (("whatever", Integer()),)
5198 seq["whatever"] = Integer(value)
5199 with self.assertRaises(NotEnoughData):
5200 seq.decode(seq.encode()[:-1])
5202 @given(binary(min_size=2))
5203 def test_non_tag_mismatch_raised(self, junk):
5205 _, _, len_encoded = tag_strip(memoryview(junk))
5206 len_decode(len_encoded)
5212 class Seq(self.base_klass):
5214 ("whatever", Integer()),
5216 ("whenever", Integer()),
5219 seq["whatever"] = Integer(123)
5220 seq["junk"] = Any(junk)
5221 seq["whenever"] = Integer(123)
5222 with self.assertRaises(DecodeError):
5223 seq.decode(seq.encode())
5226 integers(min_value=31),
5227 integers(min_value=0),
5230 def test_bad_tag(self, tag, offset, decode_path):
5231 with self.assertRaises(DecodeError) as err:
5232 self.base_klass().decode(
5233 tag_encode(tag)[:-1],
5235 decode_path=decode_path,
5238 self.assertEqual(err.exception.offset, offset)
5239 self.assertEqual(err.exception.decode_path, decode_path)
5242 integers(min_value=128),
5243 integers(min_value=0),
5246 def test_bad_len(self, l, offset, decode_path):
5247 with self.assertRaises(DecodeError) as err:
5248 self.base_klass().decode(
5249 self.base_klass.tag_default + len_encode(l)[:-1],
5251 decode_path=decode_path,
5254 self.assertEqual(err.exception.offset, offset)
5255 self.assertEqual(err.exception.decode_path, decode_path)
5257 def _assert_expects(self, seq, expects):
5258 for expect in expects:
5260 seq.specs[expect["name"]].optional,
5263 if expect["default_value"] is not None:
5265 seq.specs[expect["name"]].default,
5266 expect["default_value"],
5268 if expect["presented"]:
5269 self.assertIn(expect["name"], seq)
5270 self.assertEqual(seq[expect["name"]], expect["value"])
5272 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5273 @given(data_strategy())
5274 def test_symmetric(self, d):
5275 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5276 tail_junk = d.draw(binary(max_size=5))
5277 self.assertTrue(seq.ready)
5278 self.assertFalse(seq.decoded)
5279 self._assert_expects(seq, expects)
5282 pprint(seq, big_blobs=True, with_decode_path=True)
5283 self.assertTrue(seq.ready)
5284 seq_encoded = seq.encode()
5285 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5286 self.assertFalse(seq_decoded.lenindef)
5287 self.assertFalse(seq_decoded.ber_encoded)
5288 self.assertFalse(seq_decoded.bered)
5290 t, _, lv = tag_strip(seq_encoded)
5291 _, _, v = len_decode(lv)
5292 seq_encoded_lenindef = t + LENINDEF + v + EOC
5293 with self.assertRaises(DecodeError):
5294 seq.decode(seq_encoded_lenindef)
5295 ctx_copied = deepcopy(ctx_dummy)
5296 ctx_copied["bered"] = True
5297 seq_decoded_lenindef, tail_lenindef = seq.decode(
5298 seq_encoded_lenindef + tail_junk,
5301 del ctx_copied["bered"]
5302 self.assertDictEqual(ctx_copied, ctx_dummy)
5303 self.assertTrue(seq_decoded_lenindef.lenindef)
5304 self.assertTrue(seq_decoded_lenindef.bered)
5305 seq_decoded_lenindef = copy(seq_decoded_lenindef)
5306 self.assertTrue(seq_decoded_lenindef.lenindef)
5307 self.assertTrue(seq_decoded_lenindef.bered)
5308 with self.assertRaises(DecodeError):
5309 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5310 with self.assertRaises(DecodeError):
5311 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5312 repr(seq_decoded_lenindef)
5313 list(seq_decoded_lenindef.pps())
5314 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5315 self.assertTrue(seq_decoded_lenindef.ready)
5317 for decoded, decoded_tail, encoded in (
5318 (seq_decoded, tail, seq_encoded),
5319 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5321 self.assertEqual(decoded_tail, tail_junk)
5322 self._assert_expects(decoded, expects)
5323 self.assertEqual(seq, decoded)
5324 self.assertEqual(decoded.encode(), seq_encoded)
5325 self.assertEqual(decoded.tlvlen, len(encoded))
5326 for expect in expects:
5327 if not expect["presented"]:
5328 self.assertNotIn(expect["name"], decoded)
5330 self.assertIn(expect["name"], decoded)
5331 obj = decoded[expect["name"]]
5332 self.assertTrue(obj.decoded)
5333 offset = obj.expl_offset if obj.expled else obj.offset
5334 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5335 self.assertSequenceEqual(
5336 seq_encoded[offset:offset + tlvlen],
5340 assert_exceeding_data(
5342 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
5346 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5347 @given(data_strategy())
5348 def test_symmetric_with_seq(self, d):
5349 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5350 self.assertTrue(seq.ready)
5351 seq_encoded = seq.encode()
5352 seq_decoded, tail = seq.decode(seq_encoded)
5353 self.assertEqual(tail, b"")
5354 self.assertTrue(seq.ready)
5355 self.assertEqual(seq, seq_decoded)
5356 self.assertEqual(seq_decoded.encode(), seq_encoded)
5357 for expect_outer in expect_outers:
5358 if not expect_outer["presented"]:
5359 self.assertNotIn(expect_outer["name"], seq_decoded)
5361 self.assertIn(expect_outer["name"], seq_decoded)
5362 obj = seq_decoded[expect_outer["name"]]
5363 self.assertTrue(obj.decoded)
5364 offset = obj.expl_offset if obj.expled else obj.offset
5365 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5366 self.assertSequenceEqual(
5367 seq_encoded[offset:offset + tlvlen],
5370 self._assert_expects(obj, expect_outer["expects"])
5372 @given(data_strategy())
5373 def test_default_disappears(self, d):
5374 _schema = list(d.draw(dictionaries(
5376 sets(integers(), min_size=2, max_size=2),
5380 class Seq(self.base_klass):
5382 (n, Integer(default=d))
5383 for n, (_, d) in _schema
5386 for name, (value, _) in _schema:
5387 seq[name] = Integer(value)
5388 self.assertEqual(len(seq._value), len(_schema))
5389 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5390 self.assertGreater(len(seq.encode()), len(empty_seq))
5391 for name, (_, default) in _schema:
5392 seq[name] = Integer(default)
5393 self.assertEqual(len(seq._value), 0)
5394 self.assertSequenceEqual(seq.encode(), empty_seq)
5396 @given(data_strategy())
5397 def test_encoded_default_not_accepted(self, d):
5398 _schema = list(d.draw(dictionaries(
5403 tags = [tag_encode(tag) for tag in d.draw(sets(
5404 integers(min_value=0),
5405 min_size=len(_schema),
5406 max_size=len(_schema),
5409 class SeqWithoutDefault(self.base_klass):
5411 (n, Integer(impl=t))
5412 for (n, _), t in zip(_schema, tags)
5414 seq_without_default = SeqWithoutDefault()
5415 for name, value in _schema:
5416 seq_without_default[name] = Integer(value)
5417 seq_encoded = seq_without_default.encode()
5419 class SeqWithDefault(self.base_klass):
5421 (n, Integer(default=v, impl=t))
5422 for (n, v), t in zip(_schema, tags)
5424 seq_with_default = SeqWithDefault()
5425 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5426 seq_with_default.decode(seq_encoded)
5427 for ctx in ({"bered": True}, {"allow_default_values": True}):
5428 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5429 self.assertTrue(seq_decoded.ber_encoded)
5430 self.assertTrue(seq_decoded.bered)
5431 seq_decoded = copy(seq_decoded)
5432 self.assertTrue(seq_decoded.ber_encoded)
5433 self.assertTrue(seq_decoded.bered)
5434 for name, value in _schema:
5435 self.assertEqual(seq_decoded[name], seq_with_default[name])
5436 self.assertEqual(seq_decoded[name], value)
5438 @given(data_strategy())
5439 def test_missing_from_spec(self, d):
5440 names = list(d.draw(sets(text_letters(), min_size=2)))
5441 tags = [tag_encode(tag) for tag in d.draw(sets(
5442 integers(min_value=0),
5443 min_size=len(names),
5444 max_size=len(names),
5446 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5448 class SeqFull(self.base_klass):
5449 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5450 seq_full = SeqFull()
5451 for i, name in enumerate(names):
5452 seq_full[name] = Integer(i)
5453 seq_encoded = seq_full.encode()
5454 altered = names_tags[:-2] + names_tags[-1:]
5456 class SeqMissing(self.base_klass):
5457 schema = [(n, Integer(impl=t)) for n, t in altered]
5458 seq_missing = SeqMissing()
5459 with self.assertRaises(TagMismatch):
5460 seq_missing.decode(seq_encoded)
5462 def test_bered(self):
5463 class Seq(self.base_klass):
5464 schema = (("underlying", Boolean()),)
5465 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5466 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5467 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5468 self.assertFalse(decoded.ber_encoded)
5469 self.assertFalse(decoded.lenindef)
5470 self.assertTrue(decoded.bered)
5471 decoded = copy(decoded)
5472 self.assertFalse(decoded.ber_encoded)
5473 self.assertFalse(decoded.lenindef)
5474 self.assertTrue(decoded.bered)
5476 class Seq(self.base_klass):
5477 schema = (("underlying", OctetString()),)
5479 tag_encode(form=TagFormConstructed, num=4) +
5481 OctetString(b"whatever").encode() +
5484 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5485 with self.assertRaises(DecodeError):
5486 Seq().decode(encoded)
5487 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5488 self.assertFalse(decoded.ber_encoded)
5489 self.assertFalse(decoded.lenindef)
5490 self.assertTrue(decoded.bered)
5491 decoded = copy(decoded)
5492 self.assertFalse(decoded.ber_encoded)
5493 self.assertFalse(decoded.lenindef)
5494 self.assertTrue(decoded.bered)
5497 class TestSequence(SeqMixing, CommonMixin, TestCase):
5498 base_klass = Sequence
5504 def test_remaining(self, value, junk):
5505 class Seq(Sequence):
5507 ("whatever", Integer()),
5509 int_encoded = Integer(value).encode()
5511 Sequence.tag_default,
5512 len_encode(len(int_encoded + junk)),
5515 with assertRaisesRegex(self, DecodeError, "remaining"):
5516 Seq().decode(junked)
5518 @given(sets(text_letters(), min_size=2))
5519 def test_obj_unknown(self, names):
5520 missing = names.pop()
5522 class Seq(Sequence):
5523 schema = [(n, Boolean()) for n in names]
5525 with self.assertRaises(ObjUnknown) as err:
5528 with self.assertRaises(ObjUnknown) as err:
5529 seq[missing] = Boolean()
5532 def test_x690_vector(self):
5533 class Seq(Sequence):
5535 ("name", IA5String()),
5538 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5539 self.assertEqual(seq["name"], "Smith")
5540 self.assertEqual(seq["ok"], True)
5543 class TestSet(SeqMixing, CommonMixin, TestCase):
5546 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5547 @given(data_strategy())
5548 def test_sorted(self, d):
5550 tag_encode(tag) for tag in
5551 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5555 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5557 for name, _ in Seq.schema:
5558 seq[name] = OctetString(b"")
5559 seq_encoded = seq.encode()
5560 seq_decoded, _ = seq.decode(seq_encoded)
5561 self.assertSequenceEqual(
5562 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5563 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5566 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5567 @given(data_strategy())
5568 def test_unsorted(self, d):
5570 tag_encode(tag) for tag in
5571 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5573 tags = d.draw(permutations(tags))
5574 assume(tags != sorted(tags))
5575 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5576 seq_encoded = b"".join((
5578 len_encode(len(encoded)),
5583 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5585 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5586 seq.decode(seq_encoded)
5587 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5588 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5589 self.assertTrue(seq_decoded.ber_encoded)
5590 self.assertTrue(seq_decoded.bered)
5591 seq_decoded = copy(seq_decoded)
5592 self.assertTrue(seq_decoded.ber_encoded)
5593 self.assertTrue(seq_decoded.bered)
5594 self.assertSequenceEqual(
5595 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5601 def seqof_values_strategy(draw, schema=None, do_expl=False):
5603 schema = draw(sampled_from((Boolean(), Integer())))
5604 bound_min, bound_max = sorted(draw(sets(
5605 integers(min_value=0, max_value=10),
5609 if isinstance(schema, Boolean):
5610 values_generator = booleans().map(Boolean)
5611 elif isinstance(schema, Integer):
5612 values_generator = integers().map(Integer)
5613 values_generator = lists(
5618 values = draw(one_of(none(), values_generator))
5622 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5624 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5625 default = draw(one_of(none(), values_generator))
5626 optional = draw(one_of(none(), booleans()))
5628 draw(integers(min_value=0)),
5629 draw(integers(min_value=0)),
5630 draw(integers(min_value=0)),
5635 (bound_min, bound_max),
5644 class SeqOfMixing(object):
5645 def test_invalid_value_type(self):
5646 with self.assertRaises(InvalidValueType) as err:
5647 self.base_klass(123)
5650 def test_invalid_values_type(self):
5651 class SeqOf(self.base_klass):
5653 with self.assertRaises(InvalidValueType) as err:
5654 SeqOf([Integer(123), Boolean(False), Integer(234)])
5657 def test_schema_required(self):
5658 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5659 self.base_klass.__mro__[1]()
5661 @given(booleans(), booleans(), binary(), binary())
5662 def test_comparison(self, value1, value2, tag1, tag2):
5663 class SeqOf(self.base_klass):
5665 obj1 = SeqOf([Boolean(value1)])
5666 obj2 = SeqOf([Boolean(value2)])
5667 self.assertEqual(obj1 == obj2, value1 == value2)
5668 self.assertEqual(obj1 != obj2, value1 != value2)
5669 self.assertEqual(obj1 == list(obj2), value1 == value2)
5670 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5671 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5672 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5673 self.assertEqual(obj1 == obj2, tag1 == tag2)
5674 self.assertEqual(obj1 != obj2, tag1 != tag2)
5676 @given(lists(booleans()))
5677 def test_iter(self, values):
5678 class SeqOf(self.base_klass):
5680 obj = SeqOf([Boolean(value) for value in values])
5681 self.assertEqual(len(obj), len(values))
5682 for i, value in enumerate(obj):
5683 self.assertEqual(value, values[i])
5685 @given(data_strategy())
5686 def test_ready(self, d):
5687 ready = [Integer(v) for v in d.draw(lists(
5694 range(d.draw(integers(min_value=1, max_value=5)))
5697 class SeqOf(self.base_klass):
5699 values = d.draw(permutations(ready + non_ready))
5701 for value in values:
5703 self.assertFalse(seqof.ready)
5706 pprint(seqof, big_blobs=True, with_decode_path=True)
5707 with self.assertRaises(ObjNotReady) as err:
5710 for i, value in enumerate(values):
5711 self.assertEqual(seqof[i], value)
5712 if not seqof[i].ready:
5713 seqof[i] = Integer(i)
5714 self.assertTrue(seqof.ready)
5717 pprint(seqof, big_blobs=True, with_decode_path=True)
5719 def test_spec_mismatch(self):
5720 class SeqOf(self.base_klass):
5723 seqof.append(Integer(123))
5724 with self.assertRaises(ValueError):
5725 seqof.append(Boolean(False))
5726 with self.assertRaises(ValueError):
5727 seqof[0] = Boolean(False)
5729 @given(data_strategy())
5730 def test_bounds_satisfied(self, d):
5731 class SeqOf(self.base_klass):
5733 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5734 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5735 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5736 SeqOf(value=value, bounds=(bound_min, bound_max))
5738 @given(data_strategy())
5739 def test_bounds_unsatisfied(self, d):
5740 class SeqOf(self.base_klass):
5742 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5743 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5744 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5745 with self.assertRaises(BoundsError) as err:
5746 SeqOf(value=value, bounds=(bound_min, bound_max))
5748 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5749 SeqOf(bounds=(bound_min, bound_max)).decode(
5750 SeqOf(value).encode()
5753 value = [Boolean(True)] * d.draw(integers(
5754 min_value=bound_max + 1,
5755 max_value=bound_max + 10,
5757 with self.assertRaises(BoundsError) as err:
5758 SeqOf(value=value, bounds=(bound_min, bound_max))
5760 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5761 SeqOf(bounds=(bound_min, bound_max)).decode(
5762 SeqOf(value).encode()
5766 @given(integers(min_value=1, max_value=10))
5767 def test_out_of_bounds(self, bound_max):
5768 class SeqOf(self.base_klass):
5770 bounds = (0, bound_max)
5772 for _ in range(bound_max):
5773 seqof.append(Integer(123))
5774 with self.assertRaises(BoundsError):
5775 seqof.append(Integer(123))
5777 @given(data_strategy())
5778 def test_call(self, d):
5788 ) = d.draw(seqof_values_strategy())
5790 class SeqOf(self.base_klass):
5791 schema = schema_initial
5792 obj_initial = SeqOf(
5793 value=value_initial,
5794 bounds=bounds_initial,
5797 default=default_initial,
5798 optional=optional_initial or False,
5799 _decoded=_decoded_initial,
5810 ) = d.draw(seqof_values_strategy(
5811 schema=schema_initial,
5812 do_expl=impl_initial is None,
5814 if (default is None) and (obj_initial.default is not None):
5817 (bounds is None) and
5818 (value is not None) and
5819 (bounds_initial is not None) and
5820 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5824 (bounds is None) and
5825 (default is not None) and
5826 (bounds_initial is not None) and
5827 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5839 value_expected = default if value is None else value
5841 default_initial if value_expected is None
5844 value_expected = () if value_expected is None else value_expected
5845 self.assertEqual(obj, value_expected)
5846 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5847 self.assertEqual(obj.expl_tag, expl or expl_initial)
5850 default_initial if default is None else default,
5852 if obj.default is None:
5853 optional = optional_initial if optional is None else optional
5854 optional = False if optional is None else optional
5857 self.assertEqual(obj.optional, optional)
5859 (obj._bound_min, obj._bound_max),
5860 bounds or bounds_initial or (0, float("+inf")),
5863 @given(seqof_values_strategy())
5864 def test_copy(self, values):
5865 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5867 class SeqOf(self.base_klass):
5869 register_class(SeqOf)
5876 optional=optional or False,
5879 for copy_func in copy_funcs:
5880 obj_copied = copy_func(obj)
5881 self.assert_copied_basic_fields(obj, obj_copied)
5882 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5883 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5884 self.assertEqual(obj._value, obj_copied._value)
5888 integers(min_value=1).map(tag_encode),
5890 def test_stripped(self, values, tag_impl):
5891 class SeqOf(self.base_klass):
5892 schema = OctetString()
5893 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5894 with self.assertRaises(NotEnoughData):
5895 obj.decode(obj.encode()[:-1])
5899 integers(min_value=1).map(tag_ctxc),
5901 def test_stripped_expl(self, values, tag_expl):
5902 class SeqOf(self.base_klass):
5903 schema = OctetString()
5904 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5905 with self.assertRaises(NotEnoughData):
5906 obj.decode(obj.encode()[:-1])
5909 integers(min_value=31),
5910 integers(min_value=0),
5913 def test_bad_tag(self, tag, offset, decode_path):
5914 with self.assertRaises(DecodeError) as err:
5915 self.base_klass().decode(
5916 tag_encode(tag)[:-1],
5918 decode_path=decode_path,
5921 self.assertEqual(err.exception.offset, offset)
5922 self.assertEqual(err.exception.decode_path, decode_path)
5925 integers(min_value=128),
5926 integers(min_value=0),
5929 def test_bad_len(self, l, offset, decode_path):
5930 with self.assertRaises(DecodeError) as err:
5931 self.base_klass().decode(
5932 self.base_klass.tag_default + len_encode(l)[:-1],
5934 decode_path=decode_path,
5937 self.assertEqual(err.exception.offset, offset)
5938 self.assertEqual(err.exception.decode_path, decode_path)
5940 @given(binary(min_size=1))
5941 def test_tag_mismatch(self, impl):
5942 assume(impl != self.base_klass.tag_default)
5943 with self.assertRaises(TagMismatch):
5944 self.base_klass(impl=impl).decode(self.base_klass().encode())
5946 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5948 seqof_values_strategy(schema=Integer()),
5949 lists(integers().map(Integer)),
5950 integers(min_value=1).map(tag_ctxc),
5951 integers(min_value=0),
5954 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5955 _, _, _, _, _, default, optional, _decoded = values
5957 class SeqOf(self.base_klass):
5967 pprint(obj, big_blobs=True, with_decode_path=True)
5968 self.assertFalse(obj.expled)
5969 obj_encoded = obj.encode()
5970 obj_expled = obj(value, expl=tag_expl)
5971 self.assertTrue(obj_expled.expled)
5973 list(obj_expled.pps())
5974 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5975 obj_expled_encoded = obj_expled.encode()
5976 ctx_copied = deepcopy(ctx_dummy)
5977 obj_decoded, tail = obj_expled.decode(
5978 obj_expled_encoded + tail_junk,
5982 self.assertDictEqual(ctx_copied, ctx_dummy)
5984 list(obj_decoded.pps())
5985 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5986 self.assertEqual(tail, tail_junk)
5987 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5988 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5989 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5990 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5992 obj_decoded.expl_llen,
5993 len(len_encode(len(obj_encoded))),
5995 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5996 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5999 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
6001 self.assertEqual(obj_decoded.expl_offset, offset)
6002 for obj_inner in obj_decoded:
6003 self.assertIn(obj_inner, obj_decoded)
6004 self.assertSequenceEqual(
6007 obj_inner.offset - offset:
6008 obj_inner.offset + obj_inner.tlvlen - offset
6012 t, _, lv = tag_strip(obj_encoded)
6013 _, _, v = len_decode(lv)
6014 obj_encoded_lenindef = t + LENINDEF + v + EOC
6015 with self.assertRaises(DecodeError):
6016 obj.decode(obj_encoded_lenindef)
6017 obj_decoded_lenindef, tail_lenindef = obj.decode(
6018 obj_encoded_lenindef + tail_junk,
6019 ctx={"bered": True},
6021 self.assertTrue(obj_decoded_lenindef.lenindef)
6022 self.assertTrue(obj_decoded_lenindef.bered)
6023 obj_decoded_lenindef = copy(obj_decoded_lenindef)
6024 self.assertTrue(obj_decoded_lenindef.lenindef)
6025 self.assertTrue(obj_decoded_lenindef.bered)
6026 repr(obj_decoded_lenindef)
6027 list(obj_decoded_lenindef.pps())
6028 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
6029 self.assertEqual(tail_lenindef, tail_junk)
6030 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
6031 with self.assertRaises(DecodeError):
6032 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
6033 with self.assertRaises(DecodeError):
6034 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
6036 assert_exceeding_data(
6038 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
6042 def test_bered(self):
6043 class SeqOf(self.base_klass):
6045 encoded = Boolean(False).encode()
6046 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
6047 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6048 with self.assertRaises(DecodeError):
6049 SeqOf().decode(encoded)
6050 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6051 self.assertFalse(decoded.ber_encoded)
6052 self.assertFalse(decoded.lenindef)
6053 self.assertTrue(decoded.bered)
6054 decoded = copy(decoded)
6055 self.assertFalse(decoded.ber_encoded)
6056 self.assertFalse(decoded.lenindef)
6057 self.assertTrue(decoded.bered)
6059 class SeqOf(self.base_klass):
6060 schema = OctetString()
6061 encoded = OctetString(b"whatever").encode()
6063 tag_encode(form=TagFormConstructed, num=4) +
6065 OctetString(b"whatever").encode() +
6068 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6069 with self.assertRaises(DecodeError):
6070 SeqOf().decode(encoded)
6071 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6072 self.assertFalse(decoded.ber_encoded)
6073 self.assertFalse(decoded.lenindef)
6074 self.assertTrue(decoded.bered)
6075 decoded = copy(decoded)
6076 self.assertFalse(decoded.ber_encoded)
6077 self.assertFalse(decoded.lenindef)
6078 self.assertTrue(decoded.bered)
6081 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
6082 class SeqOf(SequenceOf):
6086 def _test_symmetric_compare_objs(self, obj1, obj2):
6087 self.assertEqual(obj1, obj2)
6088 self.assertSequenceEqual(list(obj1), list(obj2))
6091 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
6096 def _test_symmetric_compare_objs(self, obj1, obj2):
6097 self.assertSetEqual(
6098 set(int(v) for v in obj1),
6099 set(int(v) for v in obj2),
6102 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6103 @given(data_strategy())
6104 def test_sorted(self, d):
6105 values = [OctetString(v) for v in d.draw(lists(binary()))]
6108 schema = OctetString()
6110 seq_encoded = seq.encode()
6111 seq_decoded, _ = seq.decode(seq_encoded)
6112 self.assertSequenceEqual(
6113 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6114 b"".join(sorted([v.encode() for v in values])),
6117 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6118 @given(data_strategy())
6119 def test_unsorted(self, d):
6120 values = [OctetString(v).encode() for v in d.draw(sets(
6121 binary(min_size=1, max_size=5),
6125 values = d.draw(permutations(values))
6126 assume(values != sorted(values))
6127 encoded = b"".join(values)
6128 seq_encoded = b"".join((
6130 len_encode(len(encoded)),
6135 schema = OctetString()
6137 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6138 seq.decode(seq_encoded)
6140 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6141 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6142 self.assertTrue(seq_decoded.ber_encoded)
6143 self.assertTrue(seq_decoded.bered)
6144 seq_decoded = copy(seq_decoded)
6145 self.assertTrue(seq_decoded.ber_encoded)
6146 self.assertTrue(seq_decoded.bered)
6147 self.assertSequenceEqual(
6148 [obj.encode() for obj in seq_decoded],
6153 class TestGoMarshalVectors(TestCase):
6155 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6156 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6157 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6158 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6159 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6161 class Seq(Sequence):
6163 ("erste", Integer()),
6164 ("zweite", Integer(optional=True))
6167 seq["erste"] = Integer(64)
6168 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6169 seq["erste"] = Integer(0x123456)
6170 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6171 seq["erste"] = Integer(64)
6172 seq["zweite"] = Integer(65)
6173 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6175 class NestedSeq(Sequence):
6179 seq["erste"] = Integer(127)
6180 seq["zweite"] = None
6181 nested = NestedSeq()
6182 nested["nest"] = seq
6183 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6185 self.assertSequenceEqual(
6186 OctetString(b"\x01\x02\x03").encode(),
6187 hexdec("0403010203"),
6190 class Seq(Sequence):
6192 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6195 seq["erste"] = Integer(64)
6196 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6198 class Seq(Sequence):
6200 ("erste", Integer(expl=tag_ctxc(5))),
6203 seq["erste"] = Integer(64)
6204 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6206 class Seq(Sequence):
6209 impl=tag_encode(0, klass=TagClassContext),
6214 seq["erste"] = Null()
6215 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6217 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6219 self.assertSequenceEqual(
6220 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6221 hexdec("170d3730303130313030303030305a"),
6223 self.assertSequenceEqual(
6224 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6225 hexdec("170d3039313131353232353631365a"),
6227 self.assertSequenceEqual(
6228 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6229 hexdec("180f32313030303430353132303130315a"),
6232 class Seq(Sequence):
6234 ("erste", GeneralizedTime()),
6237 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6238 self.assertSequenceEqual(
6240 hexdec("3011180f32303039313131353232353631365a"),
6243 self.assertSequenceEqual(
6244 BitString((1, b"\x80")).encode(),
6247 self.assertSequenceEqual(
6248 BitString((12, b"\x81\xF0")).encode(),
6249 hexdec("03030481f0"),
6252 self.assertSequenceEqual(
6253 ObjectIdentifier("1.2.3.4").encode(),
6254 hexdec("06032a0304"),
6256 self.assertSequenceEqual(
6257 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6258 hexdec("06092a864888932d010105"),
6260 self.assertSequenceEqual(
6261 ObjectIdentifier("2.100.3").encode(),
6262 hexdec("0603813403"),
6265 self.assertSequenceEqual(
6266 PrintableString("test").encode(),
6267 hexdec("130474657374"),
6269 self.assertSequenceEqual(
6270 PrintableString("x" * 127).encode(),
6271 hexdec("137F" + "78" * 127),
6273 self.assertSequenceEqual(
6274 PrintableString("x" * 128).encode(),
6275 hexdec("138180" + "78" * 128),
6277 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6279 class Seq(Sequence):
6281 ("erste", IA5String()),
6284 seq["erste"] = IA5String("test")
6285 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6287 class Seq(Sequence):
6289 ("erste", PrintableString()),
6292 seq["erste"] = PrintableString("test")
6293 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6294 # Asterisk is actually not allowable
6295 PrintableString._allowable_chars |= set(b"*")
6296 seq["erste"] = PrintableString("test*")
6297 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6298 PrintableString._allowable_chars -= set(b"*")
6300 class Seq(Sequence):
6302 ("erste", Any(optional=True)),
6303 ("zweite", Integer()),
6306 seq["zweite"] = Integer(64)
6307 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6312 seq.append(Integer(10))
6313 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6315 class _SeqOf(SequenceOf):
6316 schema = PrintableString()
6318 class SeqOf(SequenceOf):
6321 _seqof.append(PrintableString("1"))
6323 seqof.append(_seqof)
6324 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6326 class Seq(Sequence):
6328 ("erste", Integer(default=1)),
6331 seq["erste"] = Integer(0)
6332 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6333 seq["erste"] = Integer(1)
6334 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6335 seq["erste"] = Integer(2)
6336 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6339 class TestPP(TestCase):
6340 @given(data_strategy())
6341 def test_oid_printing(self, d):
6343 str(ObjectIdentifier(k)): v * 2
6344 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6346 chosen = d.draw(sampled_from(sorted(oids)))
6347 chosen_id = oids[chosen]
6348 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6349 self.assertNotIn(chosen_id, pp_console_row(pp))
6352 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6356 class TestAutoAddSlots(TestCase):
6358 class Inher(Integer):
6361 with self.assertRaises(AttributeError):
6363 inher.unexistent = "whatever"
6366 class TestOIDDefines(TestCase):
6367 @given(data_strategy())
6368 def runTest(self, d):
6369 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6370 value_name_chosen = d.draw(sampled_from(value_names))
6372 ObjectIdentifier(oid)
6373 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6375 oid_chosen = d.draw(sampled_from(oids))
6376 values = d.draw(lists(
6378 min_size=len(value_names),
6379 max_size=len(value_names),
6381 for definable_class in (Any, OctetString, BitString):
6383 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6384 oid: Integer() for oid in oids[:-1]
6387 for i, value_name in enumerate(value_names):
6388 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
6390 class Seq(Sequence):
6393 for value_name, value in zip(value_names, values):
6394 seq[value_name] = definable_class(Integer(value).encode())
6395 seq["type"] = oid_chosen
6396 seq, _ = Seq().decode(seq.encode())
6397 for value_name in value_names:
6398 if value_name == value_name_chosen:
6400 self.assertIsNone(seq[value_name].defined)
6401 if value_name_chosen in oids[:-1]:
6402 self.assertIsNotNone(seq[value_name_chosen].defined)
6403 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6404 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6407 pprint(seq, big_blobs=True, with_decode_path=True)
6410 class TestDefinesByPath(TestCase):
6411 def test_generated(self):
6412 class Seq(Sequence):
6414 ("type", ObjectIdentifier()),
6415 ("value", OctetString(expl=tag_ctxc(123))),
6418 class SeqInner(Sequence):
6420 ("typeInner", ObjectIdentifier()),
6421 ("valueInner", Any()),
6424 class PairValue(SetOf):
6427 class Pair(Sequence):
6429 ("type", ObjectIdentifier()),
6430 ("value", PairValue()),
6433 class Pairs(SequenceOf):
6440 type_octet_stringed,
6442 ObjectIdentifier(oid)
6443 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6445 seq_integered = Seq()
6446 seq_integered["type"] = type_integered
6447 seq_integered["value"] = OctetString(Integer(123).encode())
6448 seq_integered_raw = seq_integered.encode()
6452 (type_octet_stringed, OctetString(b"whatever")),
6453 (type_integered, Integer(123)),
6454 (type_octet_stringed, OctetString(b"whenever")),
6455 (type_integered, Integer(234)),
6457 for t, v in pairs_input:
6460 ("value", PairValue((Any(v),))),
6462 seq_inner = SeqInner()
6463 seq_inner["typeInner"] = type_innered
6464 seq_inner["valueInner"] = Any(pairs)
6465 seq_sequenced = Seq()
6466 seq_sequenced["type"] = type_sequenced
6467 seq_sequenced["value"] = OctetString(seq_inner.encode())
6468 seq_sequenced_raw = seq_sequenced.encode()
6470 list(seq_sequenced.pps())
6471 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6473 defines_by_path = []
6474 ctx_copied = deepcopy(ctx_dummy)
6475 seq_integered, _ = Seq().decode(
6479 self.assertDictEqual(ctx_copied, ctx_dummy)
6480 self.assertIsNone(seq_integered["value"].defined)
6481 defines_by_path.append(
6482 (("type",), ((("value",), {
6483 type_integered: Integer(),
6484 type_sequenced: SeqInner(),
6487 ctx_copied["defines_by_path"] = defines_by_path
6488 seq_integered, _ = Seq().decode(
6492 del ctx_copied["defines_by_path"]
6493 self.assertDictEqual(ctx_copied, ctx_dummy)
6494 self.assertIsNotNone(seq_integered["value"].defined)
6495 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6496 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6497 self.assertTrue(seq_integered_raw[
6498 seq_integered["value"].defined[1].offset:
6499 ].startswith(Integer(123).encode()))
6501 list(seq_integered.pps())
6502 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6504 ctx_copied["defines_by_path"] = defines_by_path
6505 seq_sequenced, _ = Seq().decode(
6509 del ctx_copied["defines_by_path"]
6510 self.assertDictEqual(ctx_copied, ctx_dummy)
6511 self.assertIsNotNone(seq_sequenced["value"].defined)
6512 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6513 seq_inner = seq_sequenced["value"].defined[1]
6514 self.assertIsNone(seq_inner["valueInner"].defined)
6516 list(seq_sequenced.pps())
6517 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6519 defines_by_path.append((
6520 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6521 ((("valueInner",), {type_innered: Pairs()}),),
6523 ctx_copied["defines_by_path"] = defines_by_path
6524 seq_sequenced, _ = Seq().decode(
6528 del ctx_copied["defines_by_path"]
6529 self.assertDictEqual(ctx_copied, ctx_dummy)
6530 self.assertIsNotNone(seq_sequenced["value"].defined)
6531 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6532 seq_inner = seq_sequenced["value"].defined[1]
6533 self.assertIsNotNone(seq_inner["valueInner"].defined)
6534 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6535 pairs = seq_inner["valueInner"].defined[1]
6537 self.assertIsNone(pair["value"][0].defined)
6539 list(seq_sequenced.pps())
6540 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6542 defines_by_path.append((
6545 DecodePathDefBy(type_sequenced),
6547 DecodePathDefBy(type_innered),
6552 type_integered: Integer(),
6553 type_octet_stringed: OctetString(),
6556 ctx_copied["defines_by_path"] = defines_by_path
6557 seq_sequenced, _ = Seq().decode(
6561 del ctx_copied["defines_by_path"]
6562 self.assertDictEqual(ctx_copied, ctx_dummy)
6563 self.assertIsNotNone(seq_sequenced["value"].defined)
6564 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6565 seq_inner = seq_sequenced["value"].defined[1]
6566 self.assertIsNotNone(seq_inner["valueInner"].defined)
6567 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6568 pairs_got = seq_inner["valueInner"].defined[1]
6569 for pair_input, pair_got in zip(pairs_input, pairs_got):
6570 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6571 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6573 list(seq_sequenced.pps())
6574 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6576 @given(oid_strategy(), integers())
6577 def test_simple(self, oid, tgt):
6578 class Inner(Sequence):
6580 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6581 ObjectIdentifier(oid): Integer(),
6585 class Outer(Sequence):
6588 ("tgt", OctetString()),
6592 inner["oid"] = ObjectIdentifier(oid)
6594 outer["inner"] = inner
6595 outer["tgt"] = OctetString(Integer(tgt).encode())
6596 decoded, _ = Outer().decode(outer.encode())
6597 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6599 def test_remaining_data(self):
6600 oid = ObjectIdentifier("1.2.3")
6601 class Seq(Sequence):
6603 ("oid", ObjectIdentifier(defines=((("tgt",), {
6606 ("tgt", OctetString()),
6611 ("tgt", OctetString(Integer(123).encode() + b"junk")),
6613 with assertRaisesRegex(self, DecodeError, "remaining data"):
6614 Seq().decode(seq.encode())
6616 def test_remaining_data_seqof(self):
6617 oid = ObjectIdentifier("1.2.3")
6619 schema = OctetString()
6621 class Seq(Sequence):
6623 ("oid", ObjectIdentifier(defines=((("tgt",), {
6631 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
6633 with assertRaisesRegex(self, DecodeError, "remaining data"):
6634 Seq().decode(seq.encode())
6637 class TestAbsDecodePath(TestCase):
6639 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6640 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6642 def test_concat(self, decode_path, rel_path):
6643 dp = abs_decode_path(decode_path, rel_path)
6644 self.assertSequenceEqual(dp, decode_path + rel_path)
6648 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6649 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6651 def test_abs(self, decode_path, rel_path):
6652 self.assertSequenceEqual(
6653 abs_decode_path(decode_path, ("/",) + rel_path),
6658 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6659 integers(min_value=1, max_value=3),
6660 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6662 def test_dots(self, decode_path, number_of_dots, rel_path):
6663 self.assertSequenceEqual(
6664 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6665 decode_path[:-number_of_dots] + rel_path,
6669 class TestStrictDefaultExistence(TestCase):
6670 @given(data_strategy())
6671 def runTest(self, d):
6672 count = d.draw(integers(min_value=1, max_value=10))
6673 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6675 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6676 for i in range(count)
6678 for klass in (Sequence, Set):
6682 for i in range(count):
6683 seq["int%d" % i] = Integer(123)
6685 chosen_choice = "int%d" % chosen
6686 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6687 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6689 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6690 self.assertTrue(decoded.ber_encoded)
6691 self.assertTrue(decoded.bered)
6692 decoded = copy(decoded)
6693 self.assertTrue(decoded.ber_encoded)
6694 self.assertTrue(decoded.bered)
6695 decoded, _ = seq.decode(raw, ctx={"bered": True})
6696 self.assertTrue(decoded.ber_encoded)
6697 self.assertTrue(decoded.bered)
6698 decoded = copy(decoded)
6699 self.assertTrue(decoded.ber_encoded)
6700 self.assertTrue(decoded.bered)
6703 class TestX690PrefixedType(TestCase):
6705 self.assertSequenceEqual(
6706 VisibleString("Jones").encode(),
6707 hexdec("1A054A6F6E6573"),
6709 self.assertSequenceEqual(
6712 impl=tag_encode(3, klass=TagClassApplication),
6714 hexdec("43054A6F6E6573"),
6716 self.assertSequenceEqual(
6720 impl=tag_encode(3, klass=TagClassApplication),
6724 hexdec("A20743054A6F6E6573"),
6726 self.assertSequenceEqual(
6730 impl=tag_encode(3, klass=TagClassApplication),
6732 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6734 hexdec("670743054A6F6E6573"),
6736 self.assertSequenceEqual(
6737 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6738 hexdec("82054A6F6E6573"),
6742 class TestExplOOB(TestCase):
6744 expl = tag_ctxc(123)
6745 raw = Integer(123).encode() + Integer(234).encode()
6746 raw = b"".join((expl, len_encode(len(raw)), raw))
6747 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6748 Integer(expl=expl).decode(raw)
6749 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
6752 class TestPickleDifferentVersion(TestCase):
6754 pickled = pickle_dumps(Integer(123), pickle_proto)
6756 version_orig = pyderasn.__version__
6757 pyderasn.__version__ += "different"
6758 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
6759 pickle_loads(pickled)
6760 pyderasn.__version__ = version_orig
6761 pickle_loads(pickled)