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")
4058 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4059 base_klass = UTCTime
4061 min_datetime = datetime(2000, 1, 1)
4062 max_datetime = datetime(2049, 12, 31)
4064 def additional_symmetric_check(self, value, obj_encoded):
4067 def test_x690_vector_valid(self):
4075 def test_x690_vector_invalid(self):
4080 with self.assertRaises(DecodeError) as err:
4084 def test_go_vectors_invalid(self):
4110 # These ones are INVALID in *DER*, but accepted
4111 # by Go's encoding/asn1
4112 b"910506164540-0700",
4113 b"910506164540+0730",
4117 with self.assertRaises(DecodeError) as err:
4121 def test_go_vectors_valid(self):
4123 UTCTime(b"910506234540Z").todatetime(),
4124 datetime(1991, 5, 6, 23, 45, 40, 0),
4127 @given(integers(min_value=0, max_value=49))
4128 def test_pre50(self, year):
4130 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4134 @given(integers(min_value=50, max_value=99))
4135 def test_post50(self, year):
4137 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4143 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4144 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4146 binary(min_size=1, max_size=1),
4148 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4149 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4152 def test_junk(self, part0, part1, part2):
4153 junk = part0 + part1 + part2
4154 assume(not (set(junk) <= set(digits.encode("ascii"))))
4155 with self.assertRaises(DecodeError):
4157 UTCTime.tag_default +
4158 len_encode(len(junk)) +
4164 def any_values_strategy(draw, do_expl=False):
4165 value = draw(one_of(none(), binary()))
4168 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4169 optional = draw(one_of(none(), booleans()))
4171 draw(integers(min_value=0)),
4172 draw(integers(min_value=0)),
4173 draw(integers(min_value=0)),
4175 return (value, expl, optional, _decoded)
4178 class AnyInherited(Any):
4182 class TestAny(CommonMixin, TestCase):
4185 def test_invalid_value_type(self):
4186 with self.assertRaises(InvalidValueType) as err:
4191 def test_optional(self, optional):
4192 obj = Any(optional=optional)
4193 self.assertEqual(obj.optional, optional)
4196 def test_ready(self, value):
4198 self.assertFalse(obj.ready)
4201 pprint(obj, big_blobs=True, with_decode_path=True)
4202 with self.assertRaises(ObjNotReady) as err:
4206 self.assertTrue(obj.ready)
4209 pprint(obj, big_blobs=True, with_decode_path=True)
4212 def test_basic(self, value):
4213 integer_encoded = Integer(value).encode()
4215 Any(integer_encoded),
4216 Any(Integer(value)),
4217 Any(Any(Integer(value))),
4219 self.assertSequenceEqual(bytes(obj), integer_encoded)
4221 obj.decode(obj.encode())[0].vlen,
4222 len(integer_encoded),
4226 pprint(obj, big_blobs=True, with_decode_path=True)
4227 self.assertSequenceEqual(obj.encode(), integer_encoded)
4229 @given(binary(), binary())
4230 def test_comparison(self, value1, value2):
4231 for klass in (Any, AnyInherited):
4232 obj1 = klass(value1)
4233 obj2 = klass(value2)
4234 self.assertEqual(obj1 == obj2, value1 == value2)
4235 self.assertEqual(obj1 != obj2, value1 != value2)
4236 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4238 @given(data_strategy())
4239 def test_call(self, d):
4240 for klass in (Any, AnyInherited):
4246 ) = d.draw(any_values_strategy())
4247 obj_initial = klass(
4250 optional_initial or False,
4258 ) = d.draw(any_values_strategy(do_expl=True))
4259 obj = obj_initial(value, expl, optional)
4261 value_expected = None if value is None else value
4262 self.assertEqual(obj, value_expected)
4263 self.assertEqual(obj.expl_tag, expl or expl_initial)
4264 if obj.default is None:
4265 optional = optional_initial if optional is None else optional
4266 optional = False if optional is None else optional
4267 self.assertEqual(obj.optional, optional)
4269 def test_simultaneous_impl_expl(self):
4270 # override it, as Any does not have implicit tag
4273 def test_decoded(self):
4274 # override it, as Any does not have implicit tag
4277 @given(any_values_strategy())
4278 def test_copy(self, values):
4279 for klass in (Any, AnyInherited):
4280 obj = klass(*values)
4281 for copy_func in copy_funcs:
4282 obj_copied = copy_func(obj)
4283 self.assert_copied_basic_fields(obj, obj_copied)
4284 self.assertEqual(obj._value, obj_copied._value)
4286 @given(binary().map(OctetString))
4287 def test_stripped(self, value):
4289 with self.assertRaises(NotEnoughData):
4290 obj.decode(obj.encode()[:-1])
4294 integers(min_value=1).map(tag_ctxc),
4296 def test_stripped_expl(self, value, tag_expl):
4297 obj = Any(value, expl=tag_expl)
4298 with self.assertRaises(NotEnoughData):
4299 obj.decode(obj.encode()[:-1])
4302 integers(min_value=31),
4303 integers(min_value=0),
4306 def test_bad_tag(self, tag, offset, decode_path):
4307 with self.assertRaises(DecodeError) as err:
4309 tag_encode(tag)[:-1],
4311 decode_path=decode_path,
4314 self.assertEqual(err.exception.offset, offset)
4315 self.assertEqual(err.exception.decode_path, decode_path)
4318 integers(min_value=128),
4319 integers(min_value=0),
4322 def test_bad_len(self, l, offset, decode_path):
4323 with self.assertRaises(DecodeError) as err:
4325 Any.tag_default + len_encode(l)[:-1],
4327 decode_path=decode_path,
4330 self.assertEqual(err.exception.offset, offset)
4331 self.assertEqual(err.exception.decode_path, decode_path)
4333 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4335 any_values_strategy(),
4336 integers().map(lambda x: Integer(x).encode()),
4337 integers(min_value=1).map(tag_ctxc),
4338 integers(min_value=0),
4341 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4342 for klass in (Any, AnyInherited):
4343 _, _, optional, _decoded = values
4344 obj = klass(value=value, optional=optional, _decoded=_decoded)
4347 pprint(obj, big_blobs=True, with_decode_path=True)
4348 self.assertFalse(obj.expled)
4349 obj_encoded = obj.encode()
4350 obj_expled = obj(value, expl=tag_expl)
4351 self.assertTrue(obj_expled.expled)
4353 list(obj_expled.pps())
4354 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4355 obj_expled_encoded = obj_expled.encode()
4356 ctx_copied = deepcopy(ctx_dummy)
4357 obj_decoded, tail = obj_expled.decode(
4358 obj_expled_encoded + tail_junk,
4362 self.assertDictEqual(ctx_copied, ctx_dummy)
4364 list(obj_decoded.pps())
4365 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4366 self.assertEqual(tail, tail_junk)
4367 self.assertEqual(obj_decoded, obj_expled)
4368 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4369 self.assertEqual(bytes(obj_decoded), bytes(obj))
4370 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4371 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4372 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4374 obj_decoded.expl_llen,
4375 len(len_encode(len(obj_encoded))),
4377 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4378 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4381 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4383 self.assertEqual(obj_decoded.expl_offset, offset)
4384 self.assertEqual(obj_decoded.tlen, 0)
4385 self.assertEqual(obj_decoded.llen, 0)
4386 self.assertEqual(obj_decoded.vlen, len(value))
4387 assert_exceeding_data(
4389 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4394 integers(min_value=1).map(tag_ctxc),
4395 integers(min_value=0, max_value=3),
4396 integers(min_value=0),
4400 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4401 chunk = Boolean(False, expl=expl).encode()
4403 OctetString.tag_default +
4405 b"".join([chunk] * chunks) +
4408 with self.assertRaises(LenIndefForm):
4412 decode_path=decode_path,
4414 obj, tail = Any().decode(
4417 decode_path=decode_path,
4418 ctx={"bered": True},
4420 self.assertSequenceEqual(tail, junk)
4421 self.assertEqual(obj.offset, offset)
4422 self.assertEqual(obj.tlvlen, len(encoded))
4423 self.assertTrue(obj.lenindef)
4424 self.assertFalse(obj.ber_encoded)
4425 self.assertTrue(obj.bered)
4427 self.assertTrue(obj.lenindef)
4428 self.assertFalse(obj.ber_encoded)
4429 self.assertTrue(obj.bered)
4432 pprint(obj, big_blobs=True, with_decode_path=True)
4433 with self.assertRaises(NotEnoughData) as err:
4437 decode_path=decode_path,
4438 ctx={"bered": True},
4440 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4441 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4443 class SeqOf(SequenceOf):
4444 schema = Boolean(expl=expl)
4446 class Seq(Sequence):
4448 ("type", ObjectIdentifier(defines=((("value",), {
4449 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4454 ("type", ObjectIdentifier("1.2.3")),
4455 ("value", Any(encoded)),
4457 seq_encoded = seq.encode()
4458 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4459 self.assertIsNotNone(seq_decoded["value"].defined)
4461 list(seq_decoded.pps())
4462 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4463 self.assertTrue(seq_decoded.bered)
4464 self.assertFalse(seq_decoded["type"].bered)
4465 self.assertTrue(seq_decoded["value"].bered)
4467 chunk = chunk[:-1] + b"\x01"
4468 chunks = b"".join([chunk] * (chunks + 1))
4469 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4471 ("type", ObjectIdentifier("1.2.3")),
4472 ("value", Any(encoded)),
4474 seq_encoded = seq.encode()
4475 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4476 self.assertIsNotNone(seq_decoded["value"].defined)
4478 list(seq_decoded.pps())
4479 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4480 self.assertTrue(seq_decoded.bered)
4481 self.assertFalse(seq_decoded["type"].bered)
4482 self.assertTrue(seq_decoded["value"].bered)
4486 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4488 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4489 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4491 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4492 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4494 min_size=len(names),
4495 max_size=len(names),
4498 (name, Integer(**tag_kwargs))
4499 for name, tag_kwargs in zip(names, tags)
4502 if value_required or draw(booleans()):
4503 value = draw(tuples(
4504 sampled_from([name for name, _ in schema]),
4505 integers().map(Integer),
4509 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4510 default = draw(one_of(
4512 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4514 optional = draw(one_of(none(), booleans()))
4516 draw(integers(min_value=0)),
4517 draw(integers(min_value=0)),
4518 draw(integers(min_value=0)),
4520 return (schema, value, expl, default, optional, _decoded)
4523 class ChoiceInherited(Choice):
4527 class TestChoice(CommonMixin, TestCase):
4529 schema = (("whatever", Boolean()),)
4532 def test_schema_required(self):
4533 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4536 def test_impl_forbidden(self):
4537 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4538 Choice(impl=b"whatever")
4540 def test_invalid_value_type(self):
4541 with self.assertRaises(InvalidValueType) as err:
4542 self.base_klass(123)
4544 with self.assertRaises(ObjUnknown) as err:
4545 self.base_klass(("whenever", Boolean(False)))
4547 with self.assertRaises(InvalidValueType) as err:
4548 self.base_klass(("whatever", Integer(123)))
4552 def test_optional(self, optional):
4553 obj = self.base_klass(
4554 default=self.base_klass(("whatever", Boolean(False))),
4557 self.assertTrue(obj.optional)
4560 def test_ready(self, value):
4561 obj = self.base_klass()
4562 self.assertFalse(obj.ready)
4565 pprint(obj, big_blobs=True, with_decode_path=True)
4566 self.assertIsNone(obj["whatever"])
4567 with self.assertRaises(ObjNotReady) as err:
4570 obj["whatever"] = Boolean()
4571 self.assertFalse(obj.ready)
4574 pprint(obj, big_blobs=True, with_decode_path=True)
4575 obj["whatever"] = Boolean(value)
4576 self.assertTrue(obj.ready)
4579 pprint(obj, big_blobs=True, with_decode_path=True)
4581 @given(booleans(), booleans())
4582 def test_comparison(self, value1, value2):
4583 class WahlInherited(self.base_klass):
4585 for klass in (self.base_klass, WahlInherited):
4586 obj1 = klass(("whatever", Boolean(value1)))
4587 obj2 = klass(("whatever", Boolean(value2)))
4588 self.assertEqual(obj1 == obj2, value1 == value2)
4589 self.assertEqual(obj1 != obj2, value1 != value2)
4590 self.assertEqual(obj1 == obj2._value, value1 == value2)
4591 self.assertFalse(obj1 == obj2._value[1])
4593 @given(data_strategy())
4594 def test_call(self, d):
4595 for klass in (Choice, ChoiceInherited):
4603 ) = d.draw(choice_values_strategy())
4606 schema = schema_initial
4608 value=value_initial,
4610 default=default_initial,
4611 optional=optional_initial or False,
4612 _decoded=_decoded_initial,
4621 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4622 obj = obj_initial(value, expl, default, optional)
4624 value_expected = default if value is None else value
4626 default_initial if value_expected is None
4629 self.assertEqual(obj.choice, value_expected[0])
4630 self.assertEqual(obj.value, int(value_expected[1]))
4631 self.assertEqual(obj.expl_tag, expl or expl_initial)
4632 default_expect = default_initial if default is None else default
4633 if default_expect is not None:
4634 self.assertEqual(obj.default.choice, default_expect[0])
4635 self.assertEqual(obj.default.value, int(default_expect[1]))
4636 if obj.default is None:
4637 optional = optional_initial if optional is None else optional
4638 optional = False if optional is None else optional
4641 self.assertEqual(obj.optional, optional)
4642 self.assertEqual(obj.specs, obj_initial.specs)
4644 def test_simultaneous_impl_expl(self):
4645 # override it, as Any does not have implicit tag
4648 def test_decoded(self):
4649 # override it, as Any does not have implicit tag
4652 @given(choice_values_strategy())
4653 def test_copy(self, values):
4654 _schema, value, expl, default, optional, _decoded = values
4656 class Wahl(self.base_klass):
4658 register_class(Wahl)
4663 optional=optional or False,
4666 for copy_func in copy_funcs:
4667 obj_copied = copy_func(obj)
4668 self.assertIsNone(obj.tag)
4669 self.assertIsNone(obj_copied.tag)
4670 # hack for assert_copied_basic_fields
4671 obj.tag = "whatever"
4672 obj_copied.tag = "whatever"
4673 self.assert_copied_basic_fields(obj, obj_copied)
4675 self.assertEqual(obj._value, obj_copied._value)
4676 self.assertEqual(obj.specs, obj_copied.specs)
4679 def test_stripped(self, value):
4680 obj = self.base_klass(("whatever", Boolean(value)))
4681 with self.assertRaises(NotEnoughData):
4682 obj.decode(obj.encode()[:-1])
4686 integers(min_value=1).map(tag_ctxc),
4688 def test_stripped_expl(self, value, tag_expl):
4689 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4690 with self.assertRaises(NotEnoughData):
4691 obj.decode(obj.encode()[:-1])
4693 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4694 @given(data_strategy())
4695 def test_symmetric(self, d):
4696 _schema, value, _, default, optional, _decoded = d.draw(
4697 choice_values_strategy(value_required=True)
4699 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4700 offset = d.draw(integers(min_value=0))
4701 tail_junk = d.draw(binary(max_size=5))
4703 class Wahl(self.base_klass):
4713 pprint(obj, big_blobs=True, with_decode_path=True)
4714 self.assertFalse(obj.expled)
4715 obj_encoded = obj.encode()
4716 obj_expled = obj(value, expl=tag_expl)
4717 self.assertTrue(obj_expled.expled)
4719 list(obj_expled.pps())
4720 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4721 obj_expled_encoded = obj_expled.encode()
4722 ctx_copied = deepcopy(ctx_dummy)
4723 obj_decoded, tail = obj_expled.decode(
4724 obj_expled_encoded + tail_junk,
4728 self.assertDictEqual(ctx_copied, ctx_dummy)
4730 list(obj_decoded.pps())
4731 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4732 self.assertEqual(tail, tail_junk)
4733 self.assertEqual(obj_decoded, obj_expled)
4734 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4735 self.assertEqual(obj_decoded.value, obj_expled.value)
4736 self.assertEqual(obj_decoded.choice, obj.choice)
4737 self.assertEqual(obj_decoded.value, obj.value)
4738 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4739 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4740 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4742 obj_decoded.expl_llen,
4743 len(len_encode(len(obj_encoded))),
4745 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4746 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4749 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4751 self.assertEqual(obj_decoded.expl_offset, offset)
4752 self.assertSequenceEqual(
4754 obj_decoded.value.fulloffset - offset:
4755 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4759 assert_exceeding_data(
4761 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4766 def test_set_get(self, value):
4769 ("erste", Boolean()),
4770 ("zweite", Integer()),
4773 with self.assertRaises(ObjUnknown) as err:
4774 obj["whatever"] = "whenever"
4775 with self.assertRaises(InvalidValueType) as err:
4776 obj["zweite"] = Boolean(False)
4777 obj["zweite"] = Integer(value)
4779 with self.assertRaises(ObjUnknown) as err:
4782 self.assertIsNone(obj["erste"])
4783 self.assertEqual(obj["zweite"], Integer(value))
4785 def test_tag_mismatch(self):
4788 ("erste", Boolean()),
4790 int_encoded = Integer(123).encode()
4791 bool_encoded = Boolean(False).encode()
4793 obj.decode(bool_encoded)
4794 with self.assertRaises(TagMismatch):
4795 obj.decode(int_encoded)
4797 def test_tag_mismatch_underlying(self):
4798 class SeqOfBoolean(SequenceOf):
4801 class SeqOfInteger(SequenceOf):
4806 ("erste", SeqOfBoolean()),
4809 int_encoded = SeqOfInteger((Integer(123),)).encode()
4810 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4812 obj.decode(bool_encoded)
4813 with self.assertRaises(TagMismatch) as err:
4814 obj.decode(int_encoded)
4815 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4819 def seq_values_strategy(draw, seq_klass, do_expl=False):
4821 if draw(booleans()):
4823 value._value = draw(dictionaries(
4826 booleans().map(Boolean),
4827 integers().map(Integer),
4831 if draw(booleans()):
4832 schema = list(draw(dictionaries(
4835 booleans().map(Boolean),
4836 integers().map(Integer),
4842 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4844 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4846 if draw(booleans()):
4847 default = seq_klass()
4848 default._value = draw(dictionaries(
4851 booleans().map(Boolean),
4852 integers().map(Integer),
4855 optional = draw(one_of(none(), booleans()))
4857 draw(integers(min_value=0)),
4858 draw(integers(min_value=0)),
4859 draw(integers(min_value=0)),
4861 return (value, schema, impl, expl, default, optional, _decoded)
4865 def sequence_strategy(draw, seq_klass):
4866 inputs = draw(lists(
4868 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4869 tuples(just(Integer), integers(), one_of(none(), integers())),
4874 integers(min_value=1),
4875 min_size=len(inputs),
4876 max_size=len(inputs),
4879 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4880 for tag, expled in zip(tags, draw(lists(
4882 min_size=len(inputs),
4883 max_size=len(inputs),
4887 for i, optional in enumerate(draw(lists(
4888 sampled_from(("required", "optional", "empty")),
4889 min_size=len(inputs),
4890 max_size=len(inputs),
4892 if optional in ("optional", "empty"):
4893 inits[i]["optional"] = True
4894 if optional == "empty":
4896 empties = set(empties)
4897 names = list(draw(sets(
4899 min_size=len(inputs),
4900 max_size=len(inputs),
4903 for i, (klass, value, default) in enumerate(inputs):
4904 schema.append((names[i], klass(default=default, **inits[i])))
4905 seq_name = draw(text_letters())
4906 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4909 for i, (klass, value, default) in enumerate(inputs):
4916 "default_value": None if spec.default is None else default,
4920 expect["optional"] = True
4922 expect["presented"] = True
4923 expect["value"] = value
4925 expect["optional"] = True
4926 if default is not None and default == value:
4927 expect["presented"] = False
4928 seq[name] = klass(value)
4929 expects.append(expect)
4934 def sequences_strategy(draw, seq_klass):
4935 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4937 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4938 for tag, expled in zip(tags, draw(lists(
4945 i for i, is_default in enumerate(draw(lists(
4951 names = list(draw(sets(
4956 seq_expectses = draw(lists(
4957 sequence_strategy(seq_klass=seq_klass),
4961 seqs = [seq for seq, _ in seq_expectses]
4963 for i, (name, seq) in enumerate(zip(names, seqs)):
4966 seq(default=(seq if i in defaulted else None), **inits[i]),
4968 seq_name = draw(text_letters())
4969 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4972 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4975 "expects": expects_inner,
4978 seq_outer[name] = seq_inner
4979 if seq_outer.specs[name].default is None:
4980 expect["presented"] = True
4981 expect_outers.append(expect)
4982 return seq_outer, expect_outers
4985 class SeqMixing(object):
4986 def test_invalid_value_type(self):
4987 with self.assertRaises(InvalidValueType) as err:
4988 self.base_klass(123)
4991 def test_invalid_value_type_set(self):
4992 class Seq(self.base_klass):
4993 schema = (("whatever", Boolean()),)
4995 with self.assertRaises(InvalidValueType) as err:
4996 seq["whatever"] = Integer(123)
5000 def test_optional(self, optional):
5001 obj = self.base_klass(default=self.base_klass(), optional=optional)
5002 self.assertTrue(obj.optional)
5004 @given(data_strategy())
5005 def test_ready(self, d):
5007 str(i): v for i, v in enumerate(d.draw(lists(
5014 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5021 for name in d.draw(permutations(
5022 list(ready.keys()) + list(non_ready.keys()),
5024 schema_input.append((name, Boolean()))
5026 class Seq(self.base_klass):
5027 schema = tuple(schema_input)
5029 for name in ready.keys():
5031 seq[name] = Boolean()
5032 self.assertFalse(seq.ready)
5035 pprint(seq, big_blobs=True, with_decode_path=True)
5036 for name, value in ready.items():
5037 seq[name] = Boolean(value)
5038 self.assertFalse(seq.ready)
5041 pprint(seq, big_blobs=True, with_decode_path=True)
5042 with self.assertRaises(ObjNotReady) as err:
5045 for name, value in non_ready.items():
5046 seq[name] = Boolean(value)
5047 self.assertTrue(seq.ready)
5050 pprint(seq, big_blobs=True, with_decode_path=True)
5052 @given(data_strategy())
5053 def test_call(self, d):
5054 class SeqInherited(self.base_klass):
5056 for klass in (self.base_klass, SeqInherited):
5065 ) = d.draw(seq_values_strategy(seq_klass=klass))
5066 obj_initial = klass(
5072 optional_initial or False,
5083 ) = d.draw(seq_values_strategy(
5085 do_expl=impl_initial is None,
5087 obj = obj_initial(value, impl, expl, default, optional)
5088 value_expected = default if value is None else value
5090 default_initial if value_expected is None
5093 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5094 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5095 self.assertEqual(obj.expl_tag, expl or expl_initial)
5097 {} if obj.default is None else obj.default._value,
5098 getattr(default_initial if default is None else default, "_value", {}),
5100 if obj.default is None:
5101 optional = optional_initial if optional is None else optional
5102 optional = False if optional is None else optional
5105 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5106 self.assertEqual(obj.optional, optional)
5108 @given(data_strategy())
5109 def test_copy(self, d):
5110 class SeqInherited(self.base_klass):
5112 register_class(SeqInherited)
5113 for klass in (self.base_klass, SeqInherited):
5114 values = d.draw(seq_values_strategy(seq_klass=klass))
5115 obj = klass(*values)
5116 for copy_func in copy_funcs:
5117 obj_copied = copy_func(obj)
5118 self.assert_copied_basic_fields(obj, obj_copied)
5119 self.assertEqual(obj.specs, obj_copied.specs)
5120 self.assertEqual(obj._value, obj_copied._value)
5122 @given(data_strategy())
5123 def test_stripped(self, d):
5124 value = d.draw(integers())
5125 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5127 class Seq(self.base_klass):
5129 schema = (("whatever", Integer()),)
5131 seq["whatever"] = Integer(value)
5132 with self.assertRaises(NotEnoughData):
5133 seq.decode(seq.encode()[:-1])
5135 @given(data_strategy())
5136 def test_stripped_expl(self, d):
5137 value = d.draw(integers())
5138 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5140 class Seq(self.base_klass):
5142 schema = (("whatever", Integer()),)
5144 seq["whatever"] = Integer(value)
5145 with self.assertRaises(NotEnoughData):
5146 seq.decode(seq.encode()[:-1])
5148 @given(binary(min_size=2))
5149 def test_non_tag_mismatch_raised(self, junk):
5151 _, _, len_encoded = tag_strip(memoryview(junk))
5152 len_decode(len_encoded)
5158 class Seq(self.base_klass):
5160 ("whatever", Integer()),
5162 ("whenever", Integer()),
5165 seq["whatever"] = Integer(123)
5166 seq["junk"] = Any(junk)
5167 seq["whenever"] = Integer(123)
5168 with self.assertRaises(DecodeError):
5169 seq.decode(seq.encode())
5172 integers(min_value=31),
5173 integers(min_value=0),
5176 def test_bad_tag(self, tag, offset, decode_path):
5177 with self.assertRaises(DecodeError) as err:
5178 self.base_klass().decode(
5179 tag_encode(tag)[:-1],
5181 decode_path=decode_path,
5184 self.assertEqual(err.exception.offset, offset)
5185 self.assertEqual(err.exception.decode_path, decode_path)
5188 integers(min_value=128),
5189 integers(min_value=0),
5192 def test_bad_len(self, l, offset, decode_path):
5193 with self.assertRaises(DecodeError) as err:
5194 self.base_klass().decode(
5195 self.base_klass.tag_default + len_encode(l)[:-1],
5197 decode_path=decode_path,
5200 self.assertEqual(err.exception.offset, offset)
5201 self.assertEqual(err.exception.decode_path, decode_path)
5203 def _assert_expects(self, seq, expects):
5204 for expect in expects:
5206 seq.specs[expect["name"]].optional,
5209 if expect["default_value"] is not None:
5211 seq.specs[expect["name"]].default,
5212 expect["default_value"],
5214 if expect["presented"]:
5215 self.assertIn(expect["name"], seq)
5216 self.assertEqual(seq[expect["name"]], expect["value"])
5218 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5219 @given(data_strategy())
5220 def test_symmetric(self, d):
5221 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5222 tail_junk = d.draw(binary(max_size=5))
5223 self.assertTrue(seq.ready)
5224 self.assertFalse(seq.decoded)
5225 self._assert_expects(seq, expects)
5228 pprint(seq, big_blobs=True, with_decode_path=True)
5229 self.assertTrue(seq.ready)
5230 seq_encoded = seq.encode()
5231 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5232 self.assertFalse(seq_decoded.lenindef)
5233 self.assertFalse(seq_decoded.ber_encoded)
5234 self.assertFalse(seq_decoded.bered)
5236 t, _, lv = tag_strip(seq_encoded)
5237 _, _, v = len_decode(lv)
5238 seq_encoded_lenindef = t + LENINDEF + v + EOC
5239 with self.assertRaises(DecodeError):
5240 seq.decode(seq_encoded_lenindef)
5241 ctx_copied = deepcopy(ctx_dummy)
5242 ctx_copied["bered"] = True
5243 seq_decoded_lenindef, tail_lenindef = seq.decode(
5244 seq_encoded_lenindef + tail_junk,
5247 del ctx_copied["bered"]
5248 self.assertDictEqual(ctx_copied, ctx_dummy)
5249 self.assertTrue(seq_decoded_lenindef.lenindef)
5250 self.assertTrue(seq_decoded_lenindef.bered)
5251 seq_decoded_lenindef = copy(seq_decoded_lenindef)
5252 self.assertTrue(seq_decoded_lenindef.lenindef)
5253 self.assertTrue(seq_decoded_lenindef.bered)
5254 with self.assertRaises(DecodeError):
5255 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5256 with self.assertRaises(DecodeError):
5257 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5258 repr(seq_decoded_lenindef)
5259 list(seq_decoded_lenindef.pps())
5260 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5261 self.assertTrue(seq_decoded_lenindef.ready)
5263 for decoded, decoded_tail, encoded in (
5264 (seq_decoded, tail, seq_encoded),
5265 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5267 self.assertEqual(decoded_tail, tail_junk)
5268 self._assert_expects(decoded, expects)
5269 self.assertEqual(seq, decoded)
5270 self.assertEqual(decoded.encode(), seq_encoded)
5271 self.assertEqual(decoded.tlvlen, len(encoded))
5272 for expect in expects:
5273 if not expect["presented"]:
5274 self.assertNotIn(expect["name"], decoded)
5276 self.assertIn(expect["name"], decoded)
5277 obj = decoded[expect["name"]]
5278 self.assertTrue(obj.decoded)
5279 offset = obj.expl_offset if obj.expled else obj.offset
5280 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5281 self.assertSequenceEqual(
5282 seq_encoded[offset:offset + tlvlen],
5286 assert_exceeding_data(
5288 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
5292 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5293 @given(data_strategy())
5294 def test_symmetric_with_seq(self, d):
5295 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5296 self.assertTrue(seq.ready)
5297 seq_encoded = seq.encode()
5298 seq_decoded, tail = seq.decode(seq_encoded)
5299 self.assertEqual(tail, b"")
5300 self.assertTrue(seq.ready)
5301 self.assertEqual(seq, seq_decoded)
5302 self.assertEqual(seq_decoded.encode(), seq_encoded)
5303 for expect_outer in expect_outers:
5304 if not expect_outer["presented"]:
5305 self.assertNotIn(expect_outer["name"], seq_decoded)
5307 self.assertIn(expect_outer["name"], seq_decoded)
5308 obj = seq_decoded[expect_outer["name"]]
5309 self.assertTrue(obj.decoded)
5310 offset = obj.expl_offset if obj.expled else obj.offset
5311 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5312 self.assertSequenceEqual(
5313 seq_encoded[offset:offset + tlvlen],
5316 self._assert_expects(obj, expect_outer["expects"])
5318 @given(data_strategy())
5319 def test_default_disappears(self, d):
5320 _schema = list(d.draw(dictionaries(
5322 sets(integers(), min_size=2, max_size=2),
5326 class Seq(self.base_klass):
5328 (n, Integer(default=d))
5329 for n, (_, d) in _schema
5332 for name, (value, _) in _schema:
5333 seq[name] = Integer(value)
5334 self.assertEqual(len(seq._value), len(_schema))
5335 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5336 self.assertGreater(len(seq.encode()), len(empty_seq))
5337 for name, (_, default) in _schema:
5338 seq[name] = Integer(default)
5339 self.assertEqual(len(seq._value), 0)
5340 self.assertSequenceEqual(seq.encode(), empty_seq)
5342 @given(data_strategy())
5343 def test_encoded_default_not_accepted(self, d):
5344 _schema = list(d.draw(dictionaries(
5349 tags = [tag_encode(tag) for tag in d.draw(sets(
5350 integers(min_value=0),
5351 min_size=len(_schema),
5352 max_size=len(_schema),
5355 class SeqWithoutDefault(self.base_klass):
5357 (n, Integer(impl=t))
5358 for (n, _), t in zip(_schema, tags)
5360 seq_without_default = SeqWithoutDefault()
5361 for name, value in _schema:
5362 seq_without_default[name] = Integer(value)
5363 seq_encoded = seq_without_default.encode()
5365 class SeqWithDefault(self.base_klass):
5367 (n, Integer(default=v, impl=t))
5368 for (n, v), t in zip(_schema, tags)
5370 seq_with_default = SeqWithDefault()
5371 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5372 seq_with_default.decode(seq_encoded)
5373 for ctx in ({"bered": True}, {"allow_default_values": True}):
5374 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5375 self.assertTrue(seq_decoded.ber_encoded)
5376 self.assertTrue(seq_decoded.bered)
5377 seq_decoded = copy(seq_decoded)
5378 self.assertTrue(seq_decoded.ber_encoded)
5379 self.assertTrue(seq_decoded.bered)
5380 for name, value in _schema:
5381 self.assertEqual(seq_decoded[name], seq_with_default[name])
5382 self.assertEqual(seq_decoded[name], value)
5384 @given(data_strategy())
5385 def test_missing_from_spec(self, d):
5386 names = list(d.draw(sets(text_letters(), min_size=2)))
5387 tags = [tag_encode(tag) for tag in d.draw(sets(
5388 integers(min_value=0),
5389 min_size=len(names),
5390 max_size=len(names),
5392 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5394 class SeqFull(self.base_klass):
5395 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5396 seq_full = SeqFull()
5397 for i, name in enumerate(names):
5398 seq_full[name] = Integer(i)
5399 seq_encoded = seq_full.encode()
5400 altered = names_tags[:-2] + names_tags[-1:]
5402 class SeqMissing(self.base_klass):
5403 schema = [(n, Integer(impl=t)) for n, t in altered]
5404 seq_missing = SeqMissing()
5405 with self.assertRaises(TagMismatch):
5406 seq_missing.decode(seq_encoded)
5408 def test_bered(self):
5409 class Seq(self.base_klass):
5410 schema = (("underlying", Boolean()),)
5411 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5412 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5413 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5414 self.assertFalse(decoded.ber_encoded)
5415 self.assertFalse(decoded.lenindef)
5416 self.assertTrue(decoded.bered)
5417 decoded = copy(decoded)
5418 self.assertFalse(decoded.ber_encoded)
5419 self.assertFalse(decoded.lenindef)
5420 self.assertTrue(decoded.bered)
5422 class Seq(self.base_klass):
5423 schema = (("underlying", OctetString()),)
5425 tag_encode(form=TagFormConstructed, num=4) +
5427 OctetString(b"whatever").encode() +
5430 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5431 with self.assertRaises(DecodeError):
5432 Seq().decode(encoded)
5433 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5434 self.assertFalse(decoded.ber_encoded)
5435 self.assertFalse(decoded.lenindef)
5436 self.assertTrue(decoded.bered)
5437 decoded = copy(decoded)
5438 self.assertFalse(decoded.ber_encoded)
5439 self.assertFalse(decoded.lenindef)
5440 self.assertTrue(decoded.bered)
5443 class TestSequence(SeqMixing, CommonMixin, TestCase):
5444 base_klass = Sequence
5450 def test_remaining(self, value, junk):
5451 class Seq(Sequence):
5453 ("whatever", Integer()),
5455 int_encoded = Integer(value).encode()
5457 Sequence.tag_default,
5458 len_encode(len(int_encoded + junk)),
5461 with assertRaisesRegex(self, DecodeError, "remaining"):
5462 Seq().decode(junked)
5464 @given(sets(text_letters(), min_size=2))
5465 def test_obj_unknown(self, names):
5466 missing = names.pop()
5468 class Seq(Sequence):
5469 schema = [(n, Boolean()) for n in names]
5471 with self.assertRaises(ObjUnknown) as err:
5474 with self.assertRaises(ObjUnknown) as err:
5475 seq[missing] = Boolean()
5478 def test_x690_vector(self):
5479 class Seq(Sequence):
5481 ("name", IA5String()),
5484 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5485 self.assertEqual(seq["name"], "Smith")
5486 self.assertEqual(seq["ok"], True)
5489 class TestSet(SeqMixing, CommonMixin, TestCase):
5492 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5493 @given(data_strategy())
5494 def test_sorted(self, d):
5496 tag_encode(tag) for tag in
5497 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5501 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5503 for name, _ in Seq.schema:
5504 seq[name] = OctetString(b"")
5505 seq_encoded = seq.encode()
5506 seq_decoded, _ = seq.decode(seq_encoded)
5507 self.assertSequenceEqual(
5508 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5509 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5512 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5513 @given(data_strategy())
5514 def test_unsorted(self, d):
5516 tag_encode(tag) for tag in
5517 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5519 tags = d.draw(permutations(tags))
5520 assume(tags != sorted(tags))
5521 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5522 seq_encoded = b"".join((
5524 len_encode(len(encoded)),
5529 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5531 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5532 seq.decode(seq_encoded)
5533 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5534 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5535 self.assertTrue(seq_decoded.ber_encoded)
5536 self.assertTrue(seq_decoded.bered)
5537 seq_decoded = copy(seq_decoded)
5538 self.assertTrue(seq_decoded.ber_encoded)
5539 self.assertTrue(seq_decoded.bered)
5540 self.assertSequenceEqual(
5541 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5547 def seqof_values_strategy(draw, schema=None, do_expl=False):
5549 schema = draw(sampled_from((Boolean(), Integer())))
5550 bound_min, bound_max = sorted(draw(sets(
5551 integers(min_value=0, max_value=10),
5555 if isinstance(schema, Boolean):
5556 values_generator = booleans().map(Boolean)
5557 elif isinstance(schema, Integer):
5558 values_generator = integers().map(Integer)
5559 values_generator = lists(
5564 values = draw(one_of(none(), values_generator))
5568 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5570 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5571 default = draw(one_of(none(), values_generator))
5572 optional = draw(one_of(none(), booleans()))
5574 draw(integers(min_value=0)),
5575 draw(integers(min_value=0)),
5576 draw(integers(min_value=0)),
5581 (bound_min, bound_max),
5590 class SeqOfMixing(object):
5591 def test_invalid_value_type(self):
5592 with self.assertRaises(InvalidValueType) as err:
5593 self.base_klass(123)
5596 def test_invalid_values_type(self):
5597 class SeqOf(self.base_klass):
5599 with self.assertRaises(InvalidValueType) as err:
5600 SeqOf([Integer(123), Boolean(False), Integer(234)])
5603 def test_schema_required(self):
5604 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5605 self.base_klass.__mro__[1]()
5607 @given(booleans(), booleans(), binary(), binary())
5608 def test_comparison(self, value1, value2, tag1, tag2):
5609 class SeqOf(self.base_klass):
5611 obj1 = SeqOf([Boolean(value1)])
5612 obj2 = SeqOf([Boolean(value2)])
5613 self.assertEqual(obj1 == obj2, value1 == value2)
5614 self.assertEqual(obj1 != obj2, value1 != value2)
5615 self.assertEqual(obj1 == list(obj2), value1 == value2)
5616 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5617 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5618 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5619 self.assertEqual(obj1 == obj2, tag1 == tag2)
5620 self.assertEqual(obj1 != obj2, tag1 != tag2)
5622 @given(lists(booleans()))
5623 def test_iter(self, values):
5624 class SeqOf(self.base_klass):
5626 obj = SeqOf([Boolean(value) for value in values])
5627 self.assertEqual(len(obj), len(values))
5628 for i, value in enumerate(obj):
5629 self.assertEqual(value, values[i])
5631 @given(data_strategy())
5632 def test_ready(self, d):
5633 ready = [Integer(v) for v in d.draw(lists(
5640 range(d.draw(integers(min_value=1, max_value=5)))
5643 class SeqOf(self.base_klass):
5645 values = d.draw(permutations(ready + non_ready))
5647 for value in values:
5649 self.assertFalse(seqof.ready)
5652 pprint(seqof, big_blobs=True, with_decode_path=True)
5653 with self.assertRaises(ObjNotReady) as err:
5656 for i, value in enumerate(values):
5657 self.assertEqual(seqof[i], value)
5658 if not seqof[i].ready:
5659 seqof[i] = Integer(i)
5660 self.assertTrue(seqof.ready)
5663 pprint(seqof, big_blobs=True, with_decode_path=True)
5665 def test_spec_mismatch(self):
5666 class SeqOf(self.base_klass):
5669 seqof.append(Integer(123))
5670 with self.assertRaises(ValueError):
5671 seqof.append(Boolean(False))
5672 with self.assertRaises(ValueError):
5673 seqof[0] = Boolean(False)
5675 @given(data_strategy())
5676 def test_bounds_satisfied(self, d):
5677 class SeqOf(self.base_klass):
5679 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5680 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5681 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5682 SeqOf(value=value, bounds=(bound_min, bound_max))
5684 @given(data_strategy())
5685 def test_bounds_unsatisfied(self, d):
5686 class SeqOf(self.base_klass):
5688 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5689 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5690 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5691 with self.assertRaises(BoundsError) as err:
5692 SeqOf(value=value, bounds=(bound_min, bound_max))
5694 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5695 SeqOf(bounds=(bound_min, bound_max)).decode(
5696 SeqOf(value).encode()
5699 value = [Boolean(True)] * d.draw(integers(
5700 min_value=bound_max + 1,
5701 max_value=bound_max + 10,
5703 with self.assertRaises(BoundsError) as err:
5704 SeqOf(value=value, bounds=(bound_min, bound_max))
5706 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5707 SeqOf(bounds=(bound_min, bound_max)).decode(
5708 SeqOf(value).encode()
5712 @given(integers(min_value=1, max_value=10))
5713 def test_out_of_bounds(self, bound_max):
5714 class SeqOf(self.base_klass):
5716 bounds = (0, bound_max)
5718 for _ in range(bound_max):
5719 seqof.append(Integer(123))
5720 with self.assertRaises(BoundsError):
5721 seqof.append(Integer(123))
5723 @given(data_strategy())
5724 def test_call(self, d):
5734 ) = d.draw(seqof_values_strategy())
5736 class SeqOf(self.base_klass):
5737 schema = schema_initial
5738 obj_initial = SeqOf(
5739 value=value_initial,
5740 bounds=bounds_initial,
5743 default=default_initial,
5744 optional=optional_initial or False,
5745 _decoded=_decoded_initial,
5756 ) = d.draw(seqof_values_strategy(
5757 schema=schema_initial,
5758 do_expl=impl_initial is None,
5760 if (default is None) and (obj_initial.default is not None):
5763 (bounds is None) and
5764 (value is not None) and
5765 (bounds_initial is not None) and
5766 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5770 (bounds is None) and
5771 (default is not None) and
5772 (bounds_initial is not None) and
5773 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5785 value_expected = default if value is None else value
5787 default_initial if value_expected is None
5790 value_expected = () if value_expected is None else value_expected
5791 self.assertEqual(obj, value_expected)
5792 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5793 self.assertEqual(obj.expl_tag, expl or expl_initial)
5796 default_initial if default is None else default,
5798 if obj.default is None:
5799 optional = optional_initial if optional is None else optional
5800 optional = False if optional is None else optional
5803 self.assertEqual(obj.optional, optional)
5805 (obj._bound_min, obj._bound_max),
5806 bounds or bounds_initial or (0, float("+inf")),
5809 @given(seqof_values_strategy())
5810 def test_copy(self, values):
5811 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5813 class SeqOf(self.base_klass):
5815 register_class(SeqOf)
5822 optional=optional or False,
5825 for copy_func in copy_funcs:
5826 obj_copied = copy_func(obj)
5827 self.assert_copied_basic_fields(obj, obj_copied)
5828 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5829 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5830 self.assertEqual(obj._value, obj_copied._value)
5834 integers(min_value=1).map(tag_encode),
5836 def test_stripped(self, values, tag_impl):
5837 class SeqOf(self.base_klass):
5838 schema = OctetString()
5839 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5840 with self.assertRaises(NotEnoughData):
5841 obj.decode(obj.encode()[:-1])
5845 integers(min_value=1).map(tag_ctxc),
5847 def test_stripped_expl(self, values, tag_expl):
5848 class SeqOf(self.base_klass):
5849 schema = OctetString()
5850 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5851 with self.assertRaises(NotEnoughData):
5852 obj.decode(obj.encode()[:-1])
5855 integers(min_value=31),
5856 integers(min_value=0),
5859 def test_bad_tag(self, tag, offset, decode_path):
5860 with self.assertRaises(DecodeError) as err:
5861 self.base_klass().decode(
5862 tag_encode(tag)[:-1],
5864 decode_path=decode_path,
5867 self.assertEqual(err.exception.offset, offset)
5868 self.assertEqual(err.exception.decode_path, decode_path)
5871 integers(min_value=128),
5872 integers(min_value=0),
5875 def test_bad_len(self, l, offset, decode_path):
5876 with self.assertRaises(DecodeError) as err:
5877 self.base_klass().decode(
5878 self.base_klass.tag_default + len_encode(l)[:-1],
5880 decode_path=decode_path,
5883 self.assertEqual(err.exception.offset, offset)
5884 self.assertEqual(err.exception.decode_path, decode_path)
5886 @given(binary(min_size=1))
5887 def test_tag_mismatch(self, impl):
5888 assume(impl != self.base_klass.tag_default)
5889 with self.assertRaises(TagMismatch):
5890 self.base_klass(impl=impl).decode(self.base_klass().encode())
5892 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5894 seqof_values_strategy(schema=Integer()),
5895 lists(integers().map(Integer)),
5896 integers(min_value=1).map(tag_ctxc),
5897 integers(min_value=0),
5900 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5901 _, _, _, _, _, default, optional, _decoded = values
5903 class SeqOf(self.base_klass):
5913 pprint(obj, big_blobs=True, with_decode_path=True)
5914 self.assertFalse(obj.expled)
5915 obj_encoded = obj.encode()
5916 obj_expled = obj(value, expl=tag_expl)
5917 self.assertTrue(obj_expled.expled)
5919 list(obj_expled.pps())
5920 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5921 obj_expled_encoded = obj_expled.encode()
5922 ctx_copied = deepcopy(ctx_dummy)
5923 obj_decoded, tail = obj_expled.decode(
5924 obj_expled_encoded + tail_junk,
5928 self.assertDictEqual(ctx_copied, ctx_dummy)
5930 list(obj_decoded.pps())
5931 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5932 self.assertEqual(tail, tail_junk)
5933 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5934 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5935 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5936 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5938 obj_decoded.expl_llen,
5939 len(len_encode(len(obj_encoded))),
5941 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5942 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5945 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5947 self.assertEqual(obj_decoded.expl_offset, offset)
5948 for obj_inner in obj_decoded:
5949 self.assertIn(obj_inner, obj_decoded)
5950 self.assertSequenceEqual(
5953 obj_inner.offset - offset:
5954 obj_inner.offset + obj_inner.tlvlen - offset
5958 t, _, lv = tag_strip(obj_encoded)
5959 _, _, v = len_decode(lv)
5960 obj_encoded_lenindef = t + LENINDEF + v + EOC
5961 with self.assertRaises(DecodeError):
5962 obj.decode(obj_encoded_lenindef)
5963 obj_decoded_lenindef, tail_lenindef = obj.decode(
5964 obj_encoded_lenindef + tail_junk,
5965 ctx={"bered": True},
5967 self.assertTrue(obj_decoded_lenindef.lenindef)
5968 self.assertTrue(obj_decoded_lenindef.bered)
5969 obj_decoded_lenindef = copy(obj_decoded_lenindef)
5970 self.assertTrue(obj_decoded_lenindef.lenindef)
5971 self.assertTrue(obj_decoded_lenindef.bered)
5972 repr(obj_decoded_lenindef)
5973 list(obj_decoded_lenindef.pps())
5974 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5975 self.assertEqual(tail_lenindef, tail_junk)
5976 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5977 with self.assertRaises(DecodeError):
5978 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5979 with self.assertRaises(DecodeError):
5980 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5982 assert_exceeding_data(
5984 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5988 def test_bered(self):
5989 class SeqOf(self.base_klass):
5991 encoded = Boolean(False).encode()
5992 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5993 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5994 with self.assertRaises(DecodeError):
5995 SeqOf().decode(encoded)
5996 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5997 self.assertFalse(decoded.ber_encoded)
5998 self.assertFalse(decoded.lenindef)
5999 self.assertTrue(decoded.bered)
6000 decoded = copy(decoded)
6001 self.assertFalse(decoded.ber_encoded)
6002 self.assertFalse(decoded.lenindef)
6003 self.assertTrue(decoded.bered)
6005 class SeqOf(self.base_klass):
6006 schema = OctetString()
6007 encoded = OctetString(b"whatever").encode()
6009 tag_encode(form=TagFormConstructed, num=4) +
6011 OctetString(b"whatever").encode() +
6014 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6015 with self.assertRaises(DecodeError):
6016 SeqOf().decode(encoded)
6017 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6018 self.assertFalse(decoded.ber_encoded)
6019 self.assertFalse(decoded.lenindef)
6020 self.assertTrue(decoded.bered)
6021 decoded = copy(decoded)
6022 self.assertFalse(decoded.ber_encoded)
6023 self.assertFalse(decoded.lenindef)
6024 self.assertTrue(decoded.bered)
6027 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
6028 class SeqOf(SequenceOf):
6032 def _test_symmetric_compare_objs(self, obj1, obj2):
6033 self.assertEqual(obj1, obj2)
6034 self.assertSequenceEqual(list(obj1), list(obj2))
6037 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
6042 def _test_symmetric_compare_objs(self, obj1, obj2):
6043 self.assertSetEqual(
6044 set(int(v) for v in obj1),
6045 set(int(v) for v in obj2),
6048 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6049 @given(data_strategy())
6050 def test_sorted(self, d):
6051 values = [OctetString(v) for v in d.draw(lists(binary()))]
6054 schema = OctetString()
6056 seq_encoded = seq.encode()
6057 seq_decoded, _ = seq.decode(seq_encoded)
6058 self.assertSequenceEqual(
6059 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6060 b"".join(sorted([v.encode() for v in values])),
6063 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6064 @given(data_strategy())
6065 def test_unsorted(self, d):
6066 values = [OctetString(v).encode() for v in d.draw(sets(
6067 binary(min_size=1, max_size=5),
6071 values = d.draw(permutations(values))
6072 assume(values != sorted(values))
6073 encoded = b"".join(values)
6074 seq_encoded = b"".join((
6076 len_encode(len(encoded)),
6081 schema = OctetString()
6083 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6084 seq.decode(seq_encoded)
6086 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6087 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6088 self.assertTrue(seq_decoded.ber_encoded)
6089 self.assertTrue(seq_decoded.bered)
6090 seq_decoded = copy(seq_decoded)
6091 self.assertTrue(seq_decoded.ber_encoded)
6092 self.assertTrue(seq_decoded.bered)
6093 self.assertSequenceEqual(
6094 [obj.encode() for obj in seq_decoded],
6099 class TestGoMarshalVectors(TestCase):
6101 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6102 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6103 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6104 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6105 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6107 class Seq(Sequence):
6109 ("erste", Integer()),
6110 ("zweite", Integer(optional=True))
6113 seq["erste"] = Integer(64)
6114 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6115 seq["erste"] = Integer(0x123456)
6116 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6117 seq["erste"] = Integer(64)
6118 seq["zweite"] = Integer(65)
6119 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6121 class NestedSeq(Sequence):
6125 seq["erste"] = Integer(127)
6126 seq["zweite"] = None
6127 nested = NestedSeq()
6128 nested["nest"] = seq
6129 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6131 self.assertSequenceEqual(
6132 OctetString(b"\x01\x02\x03").encode(),
6133 hexdec("0403010203"),
6136 class Seq(Sequence):
6138 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6141 seq["erste"] = Integer(64)
6142 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6144 class Seq(Sequence):
6146 ("erste", Integer(expl=tag_ctxc(5))),
6149 seq["erste"] = Integer(64)
6150 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6152 class Seq(Sequence):
6155 impl=tag_encode(0, klass=TagClassContext),
6160 seq["erste"] = Null()
6161 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6163 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6165 self.assertSequenceEqual(
6166 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6167 hexdec("170d3730303130313030303030305a"),
6169 self.assertSequenceEqual(
6170 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6171 hexdec("170d3039313131353232353631365a"),
6173 self.assertSequenceEqual(
6174 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6175 hexdec("180f32313030303430353132303130315a"),
6178 class Seq(Sequence):
6180 ("erste", GeneralizedTime()),
6183 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6184 self.assertSequenceEqual(
6186 hexdec("3011180f32303039313131353232353631365a"),
6189 self.assertSequenceEqual(
6190 BitString((1, b"\x80")).encode(),
6193 self.assertSequenceEqual(
6194 BitString((12, b"\x81\xF0")).encode(),
6195 hexdec("03030481f0"),
6198 self.assertSequenceEqual(
6199 ObjectIdentifier("1.2.3.4").encode(),
6200 hexdec("06032a0304"),
6202 self.assertSequenceEqual(
6203 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6204 hexdec("06092a864888932d010105"),
6206 self.assertSequenceEqual(
6207 ObjectIdentifier("2.100.3").encode(),
6208 hexdec("0603813403"),
6211 self.assertSequenceEqual(
6212 PrintableString("test").encode(),
6213 hexdec("130474657374"),
6215 self.assertSequenceEqual(
6216 PrintableString("x" * 127).encode(),
6217 hexdec("137F" + "78" * 127),
6219 self.assertSequenceEqual(
6220 PrintableString("x" * 128).encode(),
6221 hexdec("138180" + "78" * 128),
6223 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6225 class Seq(Sequence):
6227 ("erste", IA5String()),
6230 seq["erste"] = IA5String("test")
6231 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6233 class Seq(Sequence):
6235 ("erste", PrintableString()),
6238 seq["erste"] = PrintableString("test")
6239 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6240 # Asterisk is actually not allowable
6241 PrintableString._allowable_chars |= set(b"*")
6242 seq["erste"] = PrintableString("test*")
6243 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6244 PrintableString._allowable_chars -= set(b"*")
6246 class Seq(Sequence):
6248 ("erste", Any(optional=True)),
6249 ("zweite", Integer()),
6252 seq["zweite"] = Integer(64)
6253 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6258 seq.append(Integer(10))
6259 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6261 class _SeqOf(SequenceOf):
6262 schema = PrintableString()
6264 class SeqOf(SequenceOf):
6267 _seqof.append(PrintableString("1"))
6269 seqof.append(_seqof)
6270 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6272 class Seq(Sequence):
6274 ("erste", Integer(default=1)),
6277 seq["erste"] = Integer(0)
6278 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6279 seq["erste"] = Integer(1)
6280 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6281 seq["erste"] = Integer(2)
6282 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6285 class TestPP(TestCase):
6286 @given(data_strategy())
6287 def test_oid_printing(self, d):
6289 str(ObjectIdentifier(k)): v * 2
6290 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6292 chosen = d.draw(sampled_from(sorted(oids)))
6293 chosen_id = oids[chosen]
6294 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6295 self.assertNotIn(chosen_id, pp_console_row(pp))
6298 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6302 class TestAutoAddSlots(TestCase):
6304 class Inher(Integer):
6307 with self.assertRaises(AttributeError):
6309 inher.unexistent = "whatever"
6312 class TestOIDDefines(TestCase):
6313 @given(data_strategy())
6314 def runTest(self, d):
6315 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6316 value_name_chosen = d.draw(sampled_from(value_names))
6318 ObjectIdentifier(oid)
6319 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6321 oid_chosen = d.draw(sampled_from(oids))
6322 values = d.draw(lists(
6324 min_size=len(value_names),
6325 max_size=len(value_names),
6327 for definable_class in (Any, OctetString, BitString):
6329 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6330 oid: Integer() for oid in oids[:-1]
6333 for i, value_name in enumerate(value_names):
6334 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
6336 class Seq(Sequence):
6339 for value_name, value in zip(value_names, values):
6340 seq[value_name] = definable_class(Integer(value).encode())
6341 seq["type"] = oid_chosen
6342 seq, _ = Seq().decode(seq.encode())
6343 for value_name in value_names:
6344 if value_name == value_name_chosen:
6346 self.assertIsNone(seq[value_name].defined)
6347 if value_name_chosen in oids[:-1]:
6348 self.assertIsNotNone(seq[value_name_chosen].defined)
6349 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6350 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6353 pprint(seq, big_blobs=True, with_decode_path=True)
6356 class TestDefinesByPath(TestCase):
6357 def test_generated(self):
6358 class Seq(Sequence):
6360 ("type", ObjectIdentifier()),
6361 ("value", OctetString(expl=tag_ctxc(123))),
6364 class SeqInner(Sequence):
6366 ("typeInner", ObjectIdentifier()),
6367 ("valueInner", Any()),
6370 class PairValue(SetOf):
6373 class Pair(Sequence):
6375 ("type", ObjectIdentifier()),
6376 ("value", PairValue()),
6379 class Pairs(SequenceOf):
6386 type_octet_stringed,
6388 ObjectIdentifier(oid)
6389 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6391 seq_integered = Seq()
6392 seq_integered["type"] = type_integered
6393 seq_integered["value"] = OctetString(Integer(123).encode())
6394 seq_integered_raw = seq_integered.encode()
6398 (type_octet_stringed, OctetString(b"whatever")),
6399 (type_integered, Integer(123)),
6400 (type_octet_stringed, OctetString(b"whenever")),
6401 (type_integered, Integer(234)),
6403 for t, v in pairs_input:
6406 ("value", PairValue((Any(v),))),
6408 seq_inner = SeqInner()
6409 seq_inner["typeInner"] = type_innered
6410 seq_inner["valueInner"] = Any(pairs)
6411 seq_sequenced = Seq()
6412 seq_sequenced["type"] = type_sequenced
6413 seq_sequenced["value"] = OctetString(seq_inner.encode())
6414 seq_sequenced_raw = seq_sequenced.encode()
6416 list(seq_sequenced.pps())
6417 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6419 defines_by_path = []
6420 ctx_copied = deepcopy(ctx_dummy)
6421 seq_integered, _ = Seq().decode(
6425 self.assertDictEqual(ctx_copied, ctx_dummy)
6426 self.assertIsNone(seq_integered["value"].defined)
6427 defines_by_path.append(
6428 (("type",), ((("value",), {
6429 type_integered: Integer(),
6430 type_sequenced: SeqInner(),
6433 ctx_copied["defines_by_path"] = defines_by_path
6434 seq_integered, _ = Seq().decode(
6438 del ctx_copied["defines_by_path"]
6439 self.assertDictEqual(ctx_copied, ctx_dummy)
6440 self.assertIsNotNone(seq_integered["value"].defined)
6441 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6442 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6443 self.assertTrue(seq_integered_raw[
6444 seq_integered["value"].defined[1].offset:
6445 ].startswith(Integer(123).encode()))
6447 list(seq_integered.pps())
6448 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6450 ctx_copied["defines_by_path"] = defines_by_path
6451 seq_sequenced, _ = Seq().decode(
6455 del ctx_copied["defines_by_path"]
6456 self.assertDictEqual(ctx_copied, ctx_dummy)
6457 self.assertIsNotNone(seq_sequenced["value"].defined)
6458 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6459 seq_inner = seq_sequenced["value"].defined[1]
6460 self.assertIsNone(seq_inner["valueInner"].defined)
6462 list(seq_sequenced.pps())
6463 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6465 defines_by_path.append((
6466 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6467 ((("valueInner",), {type_innered: Pairs()}),),
6469 ctx_copied["defines_by_path"] = defines_by_path
6470 seq_sequenced, _ = Seq().decode(
6474 del ctx_copied["defines_by_path"]
6475 self.assertDictEqual(ctx_copied, ctx_dummy)
6476 self.assertIsNotNone(seq_sequenced["value"].defined)
6477 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6478 seq_inner = seq_sequenced["value"].defined[1]
6479 self.assertIsNotNone(seq_inner["valueInner"].defined)
6480 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6481 pairs = seq_inner["valueInner"].defined[1]
6483 self.assertIsNone(pair["value"][0].defined)
6485 list(seq_sequenced.pps())
6486 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6488 defines_by_path.append((
6491 DecodePathDefBy(type_sequenced),
6493 DecodePathDefBy(type_innered),
6498 type_integered: Integer(),
6499 type_octet_stringed: OctetString(),
6502 ctx_copied["defines_by_path"] = defines_by_path
6503 seq_sequenced, _ = Seq().decode(
6507 del ctx_copied["defines_by_path"]
6508 self.assertDictEqual(ctx_copied, ctx_dummy)
6509 self.assertIsNotNone(seq_sequenced["value"].defined)
6510 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6511 seq_inner = seq_sequenced["value"].defined[1]
6512 self.assertIsNotNone(seq_inner["valueInner"].defined)
6513 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6514 pairs_got = seq_inner["valueInner"].defined[1]
6515 for pair_input, pair_got in zip(pairs_input, pairs_got):
6516 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6517 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6519 list(seq_sequenced.pps())
6520 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6522 @given(oid_strategy(), integers())
6523 def test_simple(self, oid, tgt):
6524 class Inner(Sequence):
6526 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6527 ObjectIdentifier(oid): Integer(),
6531 class Outer(Sequence):
6534 ("tgt", OctetString()),
6538 inner["oid"] = ObjectIdentifier(oid)
6540 outer["inner"] = inner
6541 outer["tgt"] = OctetString(Integer(tgt).encode())
6542 decoded, _ = Outer().decode(outer.encode())
6543 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6545 def test_remaining_data(self):
6546 oid = ObjectIdentifier("1.2.3")
6547 class Seq(Sequence):
6549 ("oid", ObjectIdentifier(defines=((("tgt",), {
6552 ("tgt", OctetString()),
6557 ("tgt", OctetString(Integer(123).encode() + b"junk")),
6559 with assertRaisesRegex(self, DecodeError, "remaining data"):
6560 Seq().decode(seq.encode())
6562 def test_remaining_data_seqof(self):
6563 oid = ObjectIdentifier("1.2.3")
6565 schema = OctetString()
6567 class Seq(Sequence):
6569 ("oid", ObjectIdentifier(defines=((("tgt",), {
6577 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
6579 with assertRaisesRegex(self, DecodeError, "remaining data"):
6580 Seq().decode(seq.encode())
6583 class TestAbsDecodePath(TestCase):
6585 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6586 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6588 def test_concat(self, decode_path, rel_path):
6589 dp = abs_decode_path(decode_path, rel_path)
6590 self.assertSequenceEqual(dp, decode_path + rel_path)
6594 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6595 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6597 def test_abs(self, decode_path, rel_path):
6598 self.assertSequenceEqual(
6599 abs_decode_path(decode_path, ("/",) + rel_path),
6604 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6605 integers(min_value=1, max_value=3),
6606 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6608 def test_dots(self, decode_path, number_of_dots, rel_path):
6609 self.assertSequenceEqual(
6610 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6611 decode_path[:-number_of_dots] + rel_path,
6615 class TestStrictDefaultExistence(TestCase):
6616 @given(data_strategy())
6617 def runTest(self, d):
6618 count = d.draw(integers(min_value=1, max_value=10))
6619 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6621 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6622 for i in range(count)
6624 for klass in (Sequence, Set):
6628 for i in range(count):
6629 seq["int%d" % i] = Integer(123)
6631 chosen_choice = "int%d" % chosen
6632 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6633 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6635 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6636 self.assertTrue(decoded.ber_encoded)
6637 self.assertTrue(decoded.bered)
6638 decoded = copy(decoded)
6639 self.assertTrue(decoded.ber_encoded)
6640 self.assertTrue(decoded.bered)
6641 decoded, _ = seq.decode(raw, ctx={"bered": True})
6642 self.assertTrue(decoded.ber_encoded)
6643 self.assertTrue(decoded.bered)
6644 decoded = copy(decoded)
6645 self.assertTrue(decoded.ber_encoded)
6646 self.assertTrue(decoded.bered)
6649 class TestX690PrefixedType(TestCase):
6651 self.assertSequenceEqual(
6652 VisibleString("Jones").encode(),
6653 hexdec("1A054A6F6E6573"),
6655 self.assertSequenceEqual(
6658 impl=tag_encode(3, klass=TagClassApplication),
6660 hexdec("43054A6F6E6573"),
6662 self.assertSequenceEqual(
6666 impl=tag_encode(3, klass=TagClassApplication),
6670 hexdec("A20743054A6F6E6573"),
6672 self.assertSequenceEqual(
6676 impl=tag_encode(3, klass=TagClassApplication),
6678 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6680 hexdec("670743054A6F6E6573"),
6682 self.assertSequenceEqual(
6683 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6684 hexdec("82054A6F6E6573"),
6688 class TestExplOOB(TestCase):
6690 expl = tag_ctxc(123)
6691 raw = Integer(123).encode() + Integer(234).encode()
6692 raw = b"".join((expl, len_encode(len(raw)), raw))
6693 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6694 Integer(expl=expl).decode(raw)
6695 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
6698 class TestPickleDifferentVersion(TestCase):
6700 pickled = pickle_dumps(Integer(123), pickle_proto)
6702 version_orig = pyderasn.__version__
6703 pyderasn.__version__ += "different"
6704 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
6705 pickle_loads(pickled)
6706 pyderasn.__version__ = version_orig
6707 pickle_loads(pickled)