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/>.
18 from copy import deepcopy
19 from datetime import datetime
20 from string import ascii_letters
21 from string import digits
22 from string import printable
23 from string import whitespace
24 from unittest import TestCase
26 from hypothesis import assume
27 from hypothesis import given
28 from hypothesis import settings
29 from hypothesis.strategies import binary
30 from hypothesis.strategies import booleans
31 from hypothesis.strategies import composite
32 from hypothesis.strategies import data as data_strategy
33 from hypothesis.strategies import datetimes
34 from hypothesis.strategies import dictionaries
35 from hypothesis.strategies import integers
36 from hypothesis.strategies import just
37 from hypothesis.strategies import lists
38 from hypothesis.strategies import none
39 from hypothesis.strategies import one_of
40 from hypothesis.strategies import permutations
41 from hypothesis.strategies import sampled_from
42 from hypothesis.strategies import sets
43 from hypothesis.strategies import text
44 from hypothesis.strategies import tuples
45 from six import assertRaisesRegex
46 from six import binary_type
47 from six import byte2int
48 from six import indexbytes
49 from six import int2byte
50 from six import iterbytes
52 from six import text_type
53 from six import unichr as six_unichr
55 from pyderasn import _pp
56 from pyderasn import abs_decode_path
57 from pyderasn import Any
58 from pyderasn import BitString
59 from pyderasn import BMPString
60 from pyderasn import Boolean
61 from pyderasn import BoundsError
62 from pyderasn import Choice
63 from pyderasn import DecodeError
64 from pyderasn import DecodePathDefBy
65 from pyderasn import Enumerated
66 from pyderasn import EOC
67 from pyderasn import EOC_LEN
68 from pyderasn import ExceedingData
69 from pyderasn import GeneralizedTime
70 from pyderasn import GeneralString
71 from pyderasn import GraphicString
72 from pyderasn import hexdec
73 from pyderasn import hexenc
74 from pyderasn import IA5String
75 from pyderasn import Integer
76 from pyderasn import InvalidLength
77 from pyderasn import InvalidOID
78 from pyderasn import InvalidValueType
79 from pyderasn import len_decode
80 from pyderasn import len_encode
81 from pyderasn import LEN_YYMMDDHHMMSSZ
82 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
83 from pyderasn import LEN_YYYYMMDDHHMMSSZ
84 from pyderasn import LENINDEF
85 from pyderasn import LenIndefForm
86 from pyderasn import NotEnoughData
87 from pyderasn import Null
88 from pyderasn import NumericString
89 from pyderasn import ObjectIdentifier
90 from pyderasn import ObjNotReady
91 from pyderasn import ObjUnknown
92 from pyderasn import OctetString
93 from pyderasn import pp_console_row
94 from pyderasn import pprint
95 from pyderasn import PrintableString
96 from pyderasn import Sequence
97 from pyderasn import SequenceOf
98 from pyderasn import Set
99 from pyderasn import SetOf
100 from pyderasn import tag_ctxc
101 from pyderasn import tag_ctxp
102 from pyderasn import tag_decode
103 from pyderasn import tag_encode
104 from pyderasn import tag_strip
105 from pyderasn import TagClassApplication
106 from pyderasn import TagClassContext
107 from pyderasn import TagClassPrivate
108 from pyderasn import TagClassUniversal
109 from pyderasn import TagFormConstructed
110 from pyderasn import TagFormPrimitive
111 from pyderasn import TagMismatch
112 from pyderasn import TeletexString
113 from pyderasn import UniversalString
114 from pyderasn import UTCTime
115 from pyderasn import UTF8String
116 from pyderasn import VideotexString
117 from pyderasn import VisibleString
120 settings.register_profile("local", settings(
123 settings.load_profile("local")
124 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
126 tag_classes = sampled_from((
132 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
133 decode_path_strat = lists(integers(), max_size=3).map(
134 lambda decode_path: tuple(str(dp) for dp in decode_path)
136 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
139 def assert_exceeding_data(self, call, junk):
141 with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)):
145 class TestHex(TestCase):
147 def test_symmetric(self, data):
148 self.assertEqual(hexdec(hexenc(data)), data)
151 class TestTagCoder(TestCase):
152 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
156 integers(min_value=0, max_value=30),
159 def test_short(self, klass, form, num, junk):
160 raw = tag_encode(klass=klass, form=form, num=num)
161 self.assertEqual(tag_decode(raw), (klass, form, num))
162 self.assertEqual(len(raw), 1)
164 byte2int(tag_encode(klass=klass, form=form, num=0)),
165 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
167 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
168 self.assertSequenceEqual(stripped.tobytes(), raw)
169 self.assertEqual(tlen, len(raw))
170 self.assertSequenceEqual(tail, junk)
172 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
176 integers(min_value=31),
179 def test_long(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.assertGreater(len(raw), 1)
184 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
187 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
188 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
189 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
190 self.assertSequenceEqual(stripped.tobytes(), raw)
191 self.assertEqual(tlen, len(raw))
192 self.assertSequenceEqual(tail, junk)
194 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
195 @given(integers(min_value=31))
196 def test_unfinished_tag(self, num):
197 raw = bytearray(tag_encode(num=num))
198 for i in range(1, len(raw)):
200 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
201 tag_strip(bytes(raw))
203 def test_go_vectors_valid(self):
204 for data, (eklass, etag, elen, eform) in (
205 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
206 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
207 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
208 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
209 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
210 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
211 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
212 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
213 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
214 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
216 tag, _, len_encoded = tag_strip(memoryview(data))
217 klass, form, num = tag_decode(tag)
218 _len, _, tail = len_decode(len_encoded)
219 self.assertSequenceEqual(tail, b"")
220 self.assertEqual(klass, eklass)
221 self.assertEqual(num, etag)
222 self.assertEqual(_len, elen)
223 self.assertEqual(form, eform)
225 def test_go_vectors_invalid(self):
233 with self.assertRaises(DecodeError):
234 _, _, len_encoded = tag_strip(memoryview(data))
235 len_decode(len_encoded)
238 integers(min_value=0, max_value=127),
239 integers(min_value=0, max_value=2),
241 def test_long_instead_of_short(self, l, dummy_num):
242 octets = (b"\x00" * dummy_num) + int2byte(l)
243 octets = int2byte((dummy_num + 1) | 0x80) + octets
244 with self.assertRaises(DecodeError):
248 class TestLenCoder(TestCase):
249 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
251 integers(min_value=0, max_value=127),
254 def test_short(self, l, junk):
255 raw = len_encode(l) + junk
256 decoded, llen, tail = len_decode(memoryview(raw))
257 self.assertEqual(decoded, l)
258 self.assertEqual(llen, 1)
259 self.assertEqual(len(raw), 1 + len(junk))
260 self.assertEqual(tail.tobytes(), junk)
262 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
264 integers(min_value=128),
267 def test_long(self, l, junk):
268 raw = len_encode(l) + junk
269 decoded, llen, tail = len_decode(memoryview(raw))
270 self.assertEqual(decoded, l)
271 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
272 self.assertEqual(llen, len(raw) - len(junk))
273 self.assertNotEqual(indexbytes(raw, 1), 0)
274 self.assertSequenceEqual(tail.tobytes(), junk)
276 def test_empty(self):
277 with self.assertRaises(NotEnoughData):
280 @given(integers(min_value=128))
281 def test_stripped(self, _len):
282 with self.assertRaises(NotEnoughData):
283 len_decode(len_encode(_len)[:-1])
286 text_printable = text(alphabet=printable, min_size=1)
290 def text_letters(draw):
291 result = draw(text(alphabet=ascii_letters, min_size=1))
293 result = result.encode("ascii")
297 class CommonMixin(object):
298 def test_tag_default(self):
299 obj = self.base_klass()
300 self.assertEqual(obj.tag, obj.tag_default)
302 def test_simultaneous_impl_expl(self):
303 with self.assertRaises(ValueError):
304 self.base_klass(impl=b"whatever", expl=b"whenever")
306 @given(binary(min_size=1), integers(), integers(), integers())
307 def test_decoded(self, impl, offset, llen, vlen):
308 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
309 self.assertEqual(obj.offset, offset)
310 self.assertEqual(obj.llen, llen)
311 self.assertEqual(obj.vlen, vlen)
312 self.assertEqual(obj.tlen, len(impl))
313 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
315 @given(binary(min_size=1))
316 def test_impl_inherited(self, impl_tag):
317 class Inherited(self.base_klass):
320 self.assertSequenceEqual(obj.impl, impl_tag)
321 self.assertFalse(obj.expled)
324 def test_expl_inherited(self, expl_tag):
325 class Inherited(self.base_klass):
328 self.assertSequenceEqual(obj.expl, expl_tag)
329 self.assertTrue(obj.expled)
331 def assert_copied_basic_fields(self, obj, obj_copied):
332 self.assertEqual(obj, obj_copied)
333 self.assertSequenceEqual(obj.tag, obj_copied.tag)
334 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
335 self.assertEqual(obj.default, obj_copied.default)
336 self.assertEqual(obj.optional, obj_copied.optional)
337 self.assertEqual(obj.offset, obj_copied.offset)
338 self.assertEqual(obj.llen, obj_copied.llen)
339 self.assertEqual(obj.vlen, obj_copied.vlen)
343 def boolean_values_strategy(draw, do_expl=False):
344 value = draw(one_of(none(), booleans()))
348 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
350 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
351 default = draw(one_of(none(), booleans()))
352 optional = draw(one_of(none(), booleans()))
354 draw(integers(min_value=0)),
355 draw(integers(min_value=0)),
356 draw(integers(min_value=0)),
358 return (value, impl, expl, default, optional, _decoded)
361 class BooleanInherited(Boolean):
365 class TestBoolean(CommonMixin, TestCase):
368 def test_invalid_value_type(self):
369 with self.assertRaises(InvalidValueType) as err:
374 def test_optional(self, optional):
375 obj = Boolean(default=Boolean(False), optional=optional)
376 self.assertTrue(obj.optional)
379 def test_ready(self, value):
381 self.assertFalse(obj.ready)
384 pprint(obj, big_blobs=True, with_decode_path=True)
385 with self.assertRaises(ObjNotReady) as err:
389 self.assertTrue(obj.ready)
392 pprint(obj, big_blobs=True, with_decode_path=True)
394 @given(booleans(), booleans(), binary(), binary())
395 def test_comparison(self, value1, value2, tag1, tag2):
396 for klass in (Boolean, BooleanInherited):
399 self.assertEqual(obj1 == obj2, value1 == value2)
400 self.assertEqual(obj1 != obj2, value1 != value2)
401 self.assertEqual(obj1 == bool(obj2), value1 == value2)
402 obj1 = klass(value1, impl=tag1)
403 obj2 = klass(value1, impl=tag2)
404 self.assertEqual(obj1 == obj2, tag1 == tag2)
405 self.assertEqual(obj1 != obj2, tag1 != tag2)
407 @given(data_strategy())
408 def test_call(self, d):
409 for klass in (Boolean, BooleanInherited):
417 ) = d.draw(boolean_values_strategy())
423 optional_initial or False,
433 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
434 obj = obj_initial(value, impl, expl, default, optional)
436 value_expected = default if value is None else value
438 default_initial if value_expected is None
441 self.assertEqual(obj, value_expected)
442 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
443 self.assertEqual(obj.expl_tag, expl or expl_initial)
446 default_initial if default is None else default,
448 if obj.default is None:
449 optional = optional_initial if optional is None else optional
450 optional = False if optional is None else optional
453 self.assertEqual(obj.optional, optional)
455 @given(boolean_values_strategy())
456 def test_copy(self, values):
457 for klass in (Boolean, BooleanInherited):
459 obj_copied = obj.copy()
460 self.assert_copied_basic_fields(obj, obj_copied)
464 integers(min_value=1).map(tag_encode),
466 def test_stripped(self, value, tag_impl):
467 obj = Boolean(value, impl=tag_impl)
468 with self.assertRaises(NotEnoughData):
469 obj.decode(obj.encode()[:-1])
473 integers(min_value=1).map(tag_ctxc),
475 def test_stripped_expl(self, value, tag_expl):
476 obj = Boolean(value, expl=tag_expl)
477 with self.assertRaises(NotEnoughData):
478 obj.decode(obj.encode()[:-1])
481 integers(min_value=31),
482 integers(min_value=0),
485 def test_bad_tag(self, tag, offset, decode_path):
486 with self.assertRaises(DecodeError) as err:
488 tag_encode(tag)[:-1],
490 decode_path=decode_path,
493 self.assertEqual(err.exception.offset, offset)
494 self.assertEqual(err.exception.decode_path, decode_path)
497 integers(min_value=31),
498 integers(min_value=0),
501 def test_bad_expl_tag(self, tag, offset, decode_path):
502 with self.assertRaises(DecodeError) as err:
503 Boolean(expl=Boolean.tag_default).decode(
504 tag_encode(tag)[:-1],
506 decode_path=decode_path,
509 self.assertEqual(err.exception.offset, offset)
510 self.assertEqual(err.exception.decode_path, decode_path)
513 integers(min_value=128),
514 integers(min_value=0),
517 def test_bad_len(self, l, offset, decode_path):
518 with self.assertRaises(DecodeError) as err:
520 Boolean.tag_default + len_encode(l)[:-1],
522 decode_path=decode_path,
525 self.assertEqual(err.exception.offset, offset)
526 self.assertEqual(err.exception.decode_path, decode_path)
529 integers(min_value=128),
530 integers(min_value=0),
533 def test_bad_expl_len(self, l, offset, decode_path):
534 with self.assertRaises(DecodeError) as err:
535 Boolean(expl=Boolean.tag_default).decode(
536 Boolean.tag_default + len_encode(l)[:-1],
538 decode_path=decode_path,
541 self.assertEqual(err.exception.offset, offset)
542 self.assertEqual(err.exception.decode_path, decode_path)
544 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
546 boolean_values_strategy(),
548 integers(min_value=1).map(tag_ctxc),
549 integers(min_value=0),
552 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
553 for klass in (Boolean, BooleanInherited):
554 _, _, _, default, optional, _decoded = values
563 pprint(obj, big_blobs=True, with_decode_path=True)
564 self.assertFalse(obj.expled)
565 obj_encoded = obj.encode()
566 obj_expled = obj(value, expl=tag_expl)
567 self.assertTrue(obj_expled.expled)
569 list(obj_expled.pps())
570 pprint(obj_expled, big_blobs=True, with_decode_path=True)
571 obj_expled_encoded = obj_expled.encode()
572 ctx_copied = deepcopy(ctx_dummy)
573 obj_decoded, tail = obj_expled.decode(
574 obj_expled_encoded + tail_junk,
578 self.assertDictEqual(ctx_copied, ctx_dummy)
580 list(obj_decoded.pps())
581 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
582 self.assertEqual(tail, tail_junk)
583 self.assertEqual(obj_decoded, obj_expled)
584 self.assertNotEqual(obj_decoded, obj)
585 self.assertEqual(bool(obj_decoded), bool(obj_expled))
586 self.assertEqual(bool(obj_decoded), bool(obj))
587 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
588 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
589 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
591 obj_decoded.expl_llen,
592 len(len_encode(len(obj_encoded))),
594 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
595 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
598 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
600 self.assertEqual(obj_decoded.expl_offset, offset)
601 assert_exceeding_data(
603 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
607 @given(integers(min_value=2))
608 def test_invalid_len(self, l):
609 with self.assertRaises(InvalidLength):
610 Boolean().decode(b"".join((
616 @given(integers(min_value=0 + 1, max_value=255 - 1))
617 def test_ber_value(self, value):
618 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
619 Boolean().decode(b"".join((
624 obj, _ = Boolean().decode(
632 self.assertTrue(bool(obj))
633 self.assertTrue(obj.ber_encoded)
634 self.assertFalse(obj.lenindef)
635 self.assertTrue(obj.bered)
637 self.assertTrue(obj.ber_encoded)
638 self.assertFalse(obj.lenindef)
639 self.assertTrue(obj.bered)
642 integers(min_value=1).map(tag_ctxc),
643 binary().filter(lambda x: not x.startswith(EOC)),
645 def test_ber_expl_no_eoc(self, expl, junk):
646 encoded = expl + LENINDEF + Boolean(False).encode()
647 with self.assertRaises(LenIndefForm):
648 Boolean(expl=expl).decode(encoded + junk)
649 with assertRaisesRegex(self, DecodeError, "no EOC"):
650 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
651 obj, tail = Boolean(expl=expl).decode(
652 encoded + EOC + junk,
655 self.assertTrue(obj.expl_lenindef)
656 self.assertFalse(obj.lenindef)
657 self.assertFalse(obj.ber_encoded)
658 self.assertTrue(obj.bered)
660 self.assertTrue(obj.expl_lenindef)
661 self.assertFalse(obj.lenindef)
662 self.assertFalse(obj.ber_encoded)
663 self.assertTrue(obj.bered)
664 self.assertSequenceEqual(tail, junk)
667 pprint(obj, big_blobs=True, with_decode_path=True)
670 integers(min_value=1).map(tag_ctxc),
677 def test_ber_expl(self, expl, values):
683 Boolean(value).encode() +
686 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
688 class SeqOf(SequenceOf):
689 schema = Boolean(expl=expl)
690 with self.assertRaises(LenIndefForm):
691 SeqOf().decode(encoded)
692 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
693 self.assertSequenceEqual(tail, b"")
694 self.assertSequenceEqual([bool(v) for v in seqof], values)
710 len(expl) + 1 + 3 + EOC_LEN,
721 pprint(seqof, big_blobs=True, with_decode_path=True)
725 def integer_values_strategy(draw, do_expl=False):
726 bound_min, value, default, bound_max = sorted(draw(sets(
735 _specs = draw(sets(text_letters()))
738 min_size=len(_specs),
739 max_size=len(_specs),
741 _specs = list(zip(_specs, values))
744 bounds = (bound_min, bound_max)
748 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
750 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
753 optional = draw(one_of(none(), booleans()))
755 draw(integers(min_value=0)),
756 draw(integers(min_value=0)),
757 draw(integers(min_value=0)),
759 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
762 class IntegerInherited(Integer):
766 class TestInteger(CommonMixin, TestCase):
769 def test_invalid_value_type(self):
770 with self.assertRaises(InvalidValueType) as err:
774 @given(sets(text_letters(), min_size=2))
775 def test_unknown_name(self, names_input):
776 missing = names_input.pop()
779 schema = [(n, 123) for n in names_input]
780 with self.assertRaises(ObjUnknown) as err:
784 @given(sets(text_letters(), min_size=2))
785 def test_known_name(self, names_input):
787 schema = [(n, 123) for n in names_input]
788 Int(names_input.pop())
791 def test_optional(self, optional):
792 obj = Integer(default=Integer(0), optional=optional)
793 self.assertTrue(obj.optional)
796 def test_ready(self, value):
798 self.assertFalse(obj.ready)
801 pprint(obj, big_blobs=True, with_decode_path=True)
802 with self.assertRaises(ObjNotReady) as err:
806 self.assertTrue(obj.ready)
809 pprint(obj, big_blobs=True, with_decode_path=True)
812 @given(integers(), integers(), binary(), binary())
813 def test_comparison(self, value1, value2, tag1, tag2):
814 for klass in (Integer, IntegerInherited):
817 self.assertEqual(obj1 == obj2, value1 == value2)
818 self.assertEqual(obj1 != obj2, value1 != value2)
819 self.assertEqual(obj1 == int(obj2), value1 == value2)
820 obj1 = klass(value1, impl=tag1)
821 obj2 = klass(value1, impl=tag2)
822 self.assertEqual(obj1 == obj2, tag1 == tag2)
823 self.assertEqual(obj1 != obj2, tag1 != tag2)
825 @given(lists(integers()))
826 def test_sorted_works(self, values):
827 self.assertSequenceEqual(
828 [int(v) for v in sorted(Integer(v) for v in values)],
832 @given(data_strategy())
833 def test_named(self, d):
834 names_input = list(d.draw(sets(text_letters(), min_size=1)))
835 values_input = list(d.draw(sets(
837 min_size=len(names_input),
838 max_size=len(names_input),
840 chosen_name = d.draw(sampled_from(names_input))
841 names_input = dict(zip(names_input, values_input))
845 _int = Int(chosen_name)
846 self.assertEqual(_int.named, chosen_name)
847 self.assertEqual(int(_int), names_input[chosen_name])
849 @given(integers(), integers(min_value=0), integers(min_value=0))
850 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
851 value = bound_min + value_delta
852 bound_max = value + bound_delta
853 Integer(value=value, bounds=(bound_min, bound_max))
855 @given(sets(integers(), min_size=3, max_size=3))
856 def test_bounds_unsatisfied(self, values):
857 values = sorted(values)
858 with self.assertRaises(BoundsError) as err:
859 Integer(value=values[0], bounds=(values[1], values[2]))
861 with assertRaisesRegex(self, DecodeError, "bounds") as err:
862 Integer(bounds=(values[1], values[2])).decode(
863 Integer(values[0]).encode()
866 with self.assertRaises(BoundsError) as err:
867 Integer(value=values[2], bounds=(values[0], values[1]))
869 with assertRaisesRegex(self, DecodeError, "bounds") as err:
870 Integer(bounds=(values[0], values[1])).decode(
871 Integer(values[2]).encode()
875 @given(data_strategy())
876 def test_call(self, d):
877 for klass in (Integer, IntegerInherited):
887 ) = d.draw(integer_values_strategy())
894 optional_initial or False,
907 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
908 if (default is None) and (obj_initial.default is not None):
912 (value is not None) and
913 (bounds_initial is not None) and
914 not (bounds_initial[0] <= value <= bounds_initial[1])
919 (default is not None) and
920 (bounds_initial is not None) and
921 not (bounds_initial[0] <= default <= bounds_initial[1])
924 obj = obj_initial(value, bounds, impl, expl, default, optional)
926 value_expected = default if value is None else value
928 default_initial if value_expected is None
931 self.assertEqual(obj, value_expected)
932 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
933 self.assertEqual(obj.expl_tag, expl or expl_initial)
936 default_initial if default is None else default,
938 if obj.default is None:
939 optional = optional_initial if optional is None else optional
940 optional = False if optional is None else optional
943 self.assertEqual(obj.optional, optional)
945 (obj._bound_min, obj._bound_max),
946 bounds or bounds_initial or (float("-inf"), float("+inf")),
950 {} if _specs_initial is None else dict(_specs_initial),
953 @given(integer_values_strategy())
954 def test_copy(self, values):
955 for klass in (Integer, IntegerInherited):
957 obj_copied = obj.copy()
958 self.assert_copied_basic_fields(obj, obj_copied)
959 self.assertEqual(obj.specs, obj_copied.specs)
960 self.assertEqual(obj._bound_min, obj_copied._bound_min)
961 self.assertEqual(obj._bound_max, obj_copied._bound_max)
962 self.assertEqual(obj._value, obj_copied._value)
966 integers(min_value=1).map(tag_encode),
968 def test_stripped(self, value, tag_impl):
969 obj = Integer(value, impl=tag_impl)
970 with self.assertRaises(NotEnoughData):
971 obj.decode(obj.encode()[:-1])
975 integers(min_value=1).map(tag_ctxc),
977 def test_stripped_expl(self, value, tag_expl):
978 obj = Integer(value, expl=tag_expl)
979 with self.assertRaises(NotEnoughData):
980 obj.decode(obj.encode()[:-1])
982 def test_zero_len(self):
983 with self.assertRaises(NotEnoughData):
984 Integer().decode(b"".join((
990 integers(min_value=31),
991 integers(min_value=0),
994 def test_bad_tag(self, tag, offset, decode_path):
995 with self.assertRaises(DecodeError) as err:
997 tag_encode(tag)[:-1],
999 decode_path=decode_path,
1002 self.assertEqual(err.exception.offset, offset)
1003 self.assertEqual(err.exception.decode_path, decode_path)
1006 integers(min_value=128),
1007 integers(min_value=0),
1010 def test_bad_len(self, l, offset, decode_path):
1011 with self.assertRaises(DecodeError) as err:
1013 Integer.tag_default + len_encode(l)[:-1],
1015 decode_path=decode_path,
1018 self.assertEqual(err.exception.offset, offset)
1019 self.assertEqual(err.exception.decode_path, decode_path)
1022 sets(integers(), min_size=2, max_size=2),
1023 integers(min_value=0),
1026 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1027 value, bound_min = list(sorted(ints))
1030 bounds = (bound_min, bound_min)
1031 with self.assertRaises(DecodeError) as err:
1033 Integer(value).encode(),
1035 decode_path=decode_path,
1038 self.assertEqual(err.exception.offset, offset)
1039 self.assertEqual(err.exception.decode_path, decode_path)
1041 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1043 integer_values_strategy(),
1045 integers(min_value=1).map(tag_ctxc),
1046 integers(min_value=0),
1049 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1050 for klass in (Integer, IntegerInherited):
1051 _, _, _, _, default, optional, _, _decoded = values
1060 pprint(obj, big_blobs=True, with_decode_path=True)
1061 self.assertFalse(obj.expled)
1062 obj_encoded = obj.encode()
1063 obj_expled = obj(value, expl=tag_expl)
1064 self.assertTrue(obj_expled.expled)
1066 list(obj_expled.pps())
1067 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1068 obj_expled_encoded = obj_expled.encode()
1069 ctx_copied = deepcopy(ctx_dummy)
1070 obj_decoded, tail = obj_expled.decode(
1071 obj_expled_encoded + tail_junk,
1075 self.assertDictEqual(ctx_copied, ctx_dummy)
1077 list(obj_decoded.pps())
1078 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1079 self.assertEqual(tail, tail_junk)
1080 self.assertEqual(obj_decoded, obj_expled)
1081 self.assertNotEqual(obj_decoded, obj)
1082 self.assertEqual(int(obj_decoded), int(obj_expled))
1083 self.assertEqual(int(obj_decoded), int(obj))
1084 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1085 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1086 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1088 obj_decoded.expl_llen,
1089 len(len_encode(len(obj_encoded))),
1091 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1092 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1095 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1097 self.assertEqual(obj_decoded.expl_offset, offset)
1098 assert_exceeding_data(
1100 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1104 def test_go_vectors_valid(self):
1105 for data, expect in ((
1109 (b"\xff\x7f", -129),
1113 (b"\xff\x00", -256),
1117 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1118 (b"\x80\x00\x00\x00", -2147483648),
1121 Integer().decode(b"".join((
1122 Integer.tag_default,
1123 len_encode(len(data)),
1129 def test_go_vectors_invalid(self):
1134 with self.assertRaises(DecodeError):
1135 Integer().decode(b"".join((
1136 Integer.tag_default,
1137 len_encode(len(data)),
1143 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1146 if draw(booleans()):
1147 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1149 integers(min_value=0, max_value=255),
1150 min_size=len(schema),
1151 max_size=len(schema),
1153 schema = list(zip(schema, bits))
1155 def _value(value_required):
1156 if not value_required and draw(booleans()):
1158 generation_choice = 0
1160 generation_choice = draw(sampled_from((1, 2, 3)))
1161 if generation_choice == 1 or draw(booleans()):
1162 return "'%s'B" % "".join(draw(lists(
1163 sampled_from(("0", "1")),
1164 max_size=len(schema),
1166 if generation_choice == 2 or draw(booleans()):
1167 return draw(binary(max_size=len(schema) // 8))
1168 if generation_choice == 3 or draw(booleans()):
1169 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1171 value = _value(value_required)
1172 default = _value(value_required=False)
1176 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1178 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1179 optional = draw(one_of(none(), booleans()))
1181 draw(integers(min_value=0)),
1182 draw(integers(min_value=0)),
1183 draw(integers(min_value=0)),
1185 return (schema, value, impl, expl, default, optional, _decoded)
1188 class BitStringInherited(BitString):
1192 class TestBitString(CommonMixin, TestCase):
1193 base_klass = BitString
1195 @given(lists(booleans()))
1196 def test_b_encoding(self, bits):
1197 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1198 self.assertEqual(obj.bit_len, len(bits))
1199 self.assertSequenceEqual(list(obj), bits)
1200 for i, bit in enumerate(bits):
1201 self.assertEqual(obj[i], bit)
1203 @given(lists(booleans()))
1204 def test_out_of_bounds_bits(self, bits):
1205 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1206 for i in range(len(bits), len(bits) * 2):
1207 self.assertFalse(obj[i])
1209 def test_bad_b_encoding(self):
1210 with self.assertRaises(ValueError):
1211 BitString("'010120101'B")
1214 integers(min_value=1, max_value=255),
1215 integers(min_value=1, max_value=255),
1217 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1218 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1219 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1220 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1222 class BS(BitString):
1223 schema = (("whatever", 0),)
1224 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1225 self.assertEqual(obj.bit_len, leading_zeros + 1)
1226 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1228 def test_zero_len(self):
1229 with self.assertRaises(NotEnoughData):
1230 BitString().decode(b"".join((
1231 BitString.tag_default,
1235 def test_invalid_value_type(self):
1236 with self.assertRaises(InvalidValueType) as err:
1239 with self.assertRaises(InvalidValueType) as err:
1243 def test_obj_unknown(self):
1244 with self.assertRaises(ObjUnknown) as err:
1245 BitString(b"whatever")["whenever"]
1248 def test_get_invalid_type(self):
1249 with self.assertRaises(InvalidValueType) as err:
1250 BitString(b"whatever")[(1, 2, 3)]
1253 @given(data_strategy())
1254 def test_unknown_name(self, d):
1255 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1256 missing = _schema.pop()
1258 class BS(BitString):
1259 schema = [(n, i) for i, n in enumerate(_schema)]
1260 with self.assertRaises(ObjUnknown) as err:
1265 def test_optional(self, optional):
1266 obj = BitString(default=BitString(b""), optional=optional)
1267 self.assertTrue(obj.optional)
1270 def test_ready(self, value):
1272 self.assertFalse(obj.ready)
1275 pprint(obj, big_blobs=True, with_decode_path=True)
1276 with self.assertRaises(ObjNotReady) as err:
1279 obj = BitString(value)
1280 self.assertTrue(obj.ready)
1283 pprint(obj, big_blobs=True, with_decode_path=True)
1286 tuples(integers(min_value=0), binary()),
1287 tuples(integers(min_value=0), binary()),
1291 def test_comparison(self, value1, value2, tag1, tag2):
1292 for klass in (BitString, BitStringInherited):
1293 obj1 = klass(value1)
1294 obj2 = klass(value2)
1295 self.assertEqual(obj1 == obj2, value1 == value2)
1296 self.assertEqual(obj1 != obj2, value1 != value2)
1297 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1298 obj1 = klass(value1, impl=tag1)
1299 obj2 = klass(value1, impl=tag2)
1300 self.assertEqual(obj1 == obj2, tag1 == tag2)
1301 self.assertEqual(obj1 != obj2, tag1 != tag2)
1303 @given(data_strategy())
1304 def test_call(self, d):
1305 for klass in (BitString, BitStringInherited):
1314 ) = d.draw(bit_string_values_strategy())
1317 schema = schema_initial
1319 value=value_initial,
1322 default=default_initial,
1323 optional=optional_initial or False,
1324 _decoded=_decoded_initial,
1334 ) = d.draw(bit_string_values_strategy(
1335 schema=schema_initial,
1336 do_expl=impl_initial is None,
1345 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1346 self.assertEqual(obj.expl_tag, expl or expl_initial)
1347 if obj.default is None:
1348 optional = optional_initial if optional is None else optional
1349 optional = False if optional is None else optional
1352 self.assertEqual(obj.optional, optional)
1353 self.assertEqual(obj.specs, obj_initial.specs)
1355 @given(bit_string_values_strategy())
1356 def test_copy(self, values):
1357 for klass in (BitString, BitStringInherited):
1358 _schema, value, impl, expl, default, optional, _decoded = values
1367 optional=optional or False,
1370 obj_copied = obj.copy()
1371 self.assert_copied_basic_fields(obj, obj_copied)
1372 self.assertEqual(obj.specs, obj_copied.specs)
1373 self.assertEqual(obj._value, obj_copied._value)
1377 integers(min_value=1).map(tag_encode),
1379 def test_stripped(self, value, tag_impl):
1380 obj = BitString(value, impl=tag_impl)
1381 with self.assertRaises(NotEnoughData):
1382 obj.decode(obj.encode()[:-1])
1386 integers(min_value=1).map(tag_ctxc),
1388 def test_stripped_expl(self, value, tag_expl):
1389 obj = BitString(value, expl=tag_expl)
1390 with self.assertRaises(NotEnoughData):
1391 obj.decode(obj.encode()[:-1])
1394 integers(min_value=31),
1395 integers(min_value=0),
1398 def test_bad_tag(self, tag, offset, decode_path):
1399 with self.assertRaises(DecodeError) as err:
1401 tag_encode(tag)[:-1],
1403 decode_path=decode_path,
1406 self.assertEqual(err.exception.offset, offset)
1407 self.assertEqual(err.exception.decode_path, decode_path)
1410 integers(min_value=128),
1411 integers(min_value=0),
1414 def test_bad_len(self, l, offset, decode_path):
1415 with self.assertRaises(DecodeError) as err:
1417 BitString.tag_default + len_encode(l)[:-1],
1419 decode_path=decode_path,
1422 self.assertEqual(err.exception.offset, offset)
1423 self.assertEqual(err.exception.decode_path, decode_path)
1425 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1426 @given(data_strategy())
1427 def test_symmetric(self, d):
1436 ) = d.draw(bit_string_values_strategy(value_required=True))
1437 tail_junk = d.draw(binary(max_size=5))
1438 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1439 offset = d.draw(integers(min_value=0))
1440 for klass in (BitString, BitStringInherited):
1451 pprint(obj, big_blobs=True, with_decode_path=True)
1452 self.assertFalse(obj.expled)
1453 obj_encoded = obj.encode()
1454 obj_expled = obj(value, expl=tag_expl)
1455 self.assertTrue(obj_expled.expled)
1457 list(obj_expled.pps())
1458 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1459 obj_expled_encoded = obj_expled.encode()
1460 ctx_copied = deepcopy(ctx_dummy)
1461 obj_decoded, tail = obj_expled.decode(
1462 obj_expled_encoded + tail_junk,
1466 self.assertDictEqual(ctx_copied, ctx_dummy)
1468 list(obj_decoded.pps())
1469 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1470 self.assertEqual(tail, tail_junk)
1471 self.assertEqual(obj_decoded, obj_expled)
1472 self.assertNotEqual(obj_decoded, obj)
1473 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1474 self.assertEqual(bytes(obj_decoded), bytes(obj))
1475 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1476 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1477 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1479 obj_decoded.expl_llen,
1480 len(len_encode(len(obj_encoded))),
1482 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1483 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1486 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1488 self.assertEqual(obj_decoded.expl_offset, offset)
1489 if isinstance(value, tuple):
1490 self.assertSetEqual(set(value), set(obj_decoded.named))
1493 assert_exceeding_data(
1495 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1499 @given(integers(min_value=1, max_value=255))
1500 def test_bad_zero_value(self, pad_size):
1501 with self.assertRaises(DecodeError):
1502 BitString().decode(b"".join((
1503 BitString.tag_default,
1508 def test_go_vectors_invalid(self):
1514 with self.assertRaises(DecodeError):
1515 BitString().decode(b"".join((
1516 BitString.tag_default,
1521 def test_go_vectors_valid(self):
1522 obj, _ = BitString().decode(b"".join((
1523 BitString.tag_default,
1527 self.assertEqual(bytes(obj), b"")
1528 self.assertEqual(obj.bit_len, 0)
1530 obj, _ = BitString().decode(b"".join((
1531 BitString.tag_default,
1535 self.assertEqual(bytes(obj), b"\x00")
1536 self.assertEqual(obj.bit_len, 1)
1538 obj = BitString((16, b"\x82\x40"))
1539 self.assertTrue(obj[0])
1540 self.assertFalse(obj[1])
1541 self.assertTrue(obj[6])
1542 self.assertTrue(obj[9])
1543 self.assertFalse(obj[17])
1546 integers(min_value=1, max_value=30),
1549 binary(min_size=1, max_size=5),
1551 binary(min_size=1, max_size=5),
1559 lists(booleans(), min_size=1),
1562 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1563 def chunk_constructed(contents):
1565 tag_encode(form=TagFormConstructed, num=3) +
1567 b"".join(BitString(content).encode() for content in contents) +
1571 payload_expected = b""
1572 bit_len_expected = 0
1573 for chunk_input in chunk_inputs:
1574 if isinstance(chunk_input, binary_type):
1575 chunks.append(BitString(chunk_input).encode())
1576 payload_expected += chunk_input
1577 bit_len_expected += len(chunk_input) * 8
1579 chunks.append(chunk_constructed(chunk_input))
1580 payload = b"".join(chunk_input)
1581 payload_expected += payload
1582 bit_len_expected += len(payload) * 8
1583 chunk_last = BitString("'%s'B" % "".join(
1584 "1" if bit else "0" for bit in chunk_last_bits
1586 payload_expected += bytes(chunk_last)
1587 bit_len_expected += chunk_last.bit_len
1588 encoded_indefinite = (
1589 tag_encode(form=TagFormConstructed, num=impl) +
1592 chunk_last.encode() +
1595 encoded_definite = (
1596 tag_encode(form=TagFormConstructed, num=impl) +
1597 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1601 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1602 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1603 for lenindef_expected, encoded in (
1604 (True, encoded_indefinite),
1605 (False, encoded_definite),
1607 obj, tail = BitString(impl=tag_encode(impl)).decode(
1609 ctx={"bered": True},
1611 self.assertSequenceEqual(tail, junk)
1612 self.assertEqual(obj.bit_len, bit_len_expected)
1613 self.assertSequenceEqual(bytes(obj), payload_expected)
1614 self.assertTrue(obj.ber_encoded)
1615 self.assertEqual(obj.lenindef, lenindef_expected)
1616 self.assertTrue(obj.bered)
1618 self.assertTrue(obj.ber_encoded)
1619 self.assertEqual(obj.lenindef, lenindef_expected)
1620 self.assertTrue(obj.bered)
1621 self.assertEqual(len(encoded), obj.tlvlen)
1624 integers(min_value=0),
1627 def test_ber_definite_too_short(self, offset, decode_path):
1628 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1630 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1632 decode_path=decode_path,
1633 ctx={"bered": True},
1635 self.assertEqual(err.exception.decode_path, decode_path)
1636 self.assertEqual(err.exception.offset, offset)
1639 integers(min_value=0),
1642 def test_ber_definite_no_data(self, offset, decode_path):
1643 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1645 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1647 decode_path=decode_path,
1648 ctx={"bered": True},
1650 self.assertEqual(err.exception.decode_path, decode_path)
1651 self.assertEqual(err.exception.offset, offset)
1654 integers(min_value=0),
1656 integers(min_value=1, max_value=3),
1658 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1659 bs = BitString(b"data").encode()
1660 with self.assertRaises(NotEnoughData) as err:
1662 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1664 decode_path=decode_path,
1665 ctx={"bered": True},
1667 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1668 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1671 integers(min_value=0),
1673 integers(min_value=1, max_value=3),
1675 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1676 bs = BitString(b"data").encode()
1677 bs_longer = BitString(b"data-longer").encode()
1678 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1681 tag_encode(3, form=TagFormConstructed) +
1682 len_encode((chunks + 1) * len(bs)) +
1687 decode_path=decode_path,
1688 ctx={"bered": True},
1690 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1691 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1694 integers(min_value=0),
1697 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1698 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1700 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1702 decode_path=decode_path,
1703 ctx={"bered": True},
1705 self.assertEqual(err.exception.decode_path, decode_path)
1706 self.assertEqual(err.exception.offset, offset)
1708 @given(data_strategy())
1709 def test_ber_indefinite_not_multiple(self, d):
1710 bs_short = BitString("'A'H").encode()
1711 bs_full = BitString("'AA'H").encode()
1712 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1713 chunks.append(bs_short)
1714 d.draw(permutations(chunks))
1715 chunks.append(bs_short)
1716 offset = d.draw(integers(min_value=0))
1717 decode_path = d.draw(decode_path_strat)
1718 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1721 tag_encode(3, form=TagFormConstructed) +
1727 decode_path=decode_path,
1728 ctx={"bered": True},
1731 err.exception.decode_path,
1732 decode_path + (str(chunks.index(bs_short)),),
1735 err.exception.offset,
1736 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1739 def test_x690_vector(self):
1740 vector = BitString("'0A3B5F291CD'H")
1741 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1742 self.assertSequenceEqual(tail, b"")
1743 self.assertEqual(obj, vector)
1744 obj, tail = BitString().decode(
1745 hexdec("23800303000A3B0305045F291CD00000"),
1746 ctx={"bered": True},
1748 self.assertSequenceEqual(tail, b"")
1749 self.assertEqual(obj, vector)
1750 self.assertTrue(obj.ber_encoded)
1751 self.assertTrue(obj.lenindef)
1752 self.assertTrue(obj.bered)
1754 self.assertTrue(obj.ber_encoded)
1755 self.assertTrue(obj.lenindef)
1756 self.assertTrue(obj.bered)
1760 def octet_string_values_strategy(draw, do_expl=False):
1761 bound_min, bound_max = sorted(draw(sets(
1762 integers(min_value=0, max_value=1 << 7),
1766 value = draw(one_of(
1768 binary(min_size=bound_min, max_size=bound_max),
1770 default = draw(one_of(
1772 binary(min_size=bound_min, max_size=bound_max),
1775 if draw(booleans()):
1776 bounds = (bound_min, bound_max)
1780 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1782 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1783 optional = draw(one_of(none(), booleans()))
1785 draw(integers(min_value=0)),
1786 draw(integers(min_value=0)),
1787 draw(integers(min_value=0)),
1789 return (value, bounds, impl, expl, default, optional, _decoded)
1792 class OctetStringInherited(OctetString):
1796 class TestOctetString(CommonMixin, TestCase):
1797 base_klass = OctetString
1799 def test_invalid_value_type(self):
1800 with self.assertRaises(InvalidValueType) as err:
1801 OctetString(text_type(123))
1805 def test_optional(self, optional):
1806 obj = OctetString(default=OctetString(b""), optional=optional)
1807 self.assertTrue(obj.optional)
1810 def test_ready(self, value):
1812 self.assertFalse(obj.ready)
1815 pprint(obj, big_blobs=True, with_decode_path=True)
1816 with self.assertRaises(ObjNotReady) as err:
1819 obj = OctetString(value)
1820 self.assertTrue(obj.ready)
1823 pprint(obj, big_blobs=True, with_decode_path=True)
1825 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1826 def test_comparison(self, value1, value2, tag1, tag2):
1827 for klass in (OctetString, OctetStringInherited):
1828 obj1 = klass(value1)
1829 obj2 = klass(value2)
1830 self.assertEqual(obj1 == obj2, value1 == value2)
1831 self.assertEqual(obj1 != obj2, value1 != value2)
1832 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1833 obj1 = klass(value1, impl=tag1)
1834 obj2 = klass(value1, impl=tag2)
1835 self.assertEqual(obj1 == obj2, tag1 == tag2)
1836 self.assertEqual(obj1 != obj2, tag1 != tag2)
1838 @given(lists(binary()))
1839 def test_sorted_works(self, values):
1840 self.assertSequenceEqual(
1841 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1845 @given(data_strategy())
1846 def test_bounds_satisfied(self, d):
1847 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1848 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1849 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1850 OctetString(value=value, bounds=(bound_min, bound_max))
1852 @given(data_strategy())
1853 def test_bounds_unsatisfied(self, d):
1854 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1855 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1856 value = d.draw(binary(max_size=bound_min - 1))
1857 with self.assertRaises(BoundsError) as err:
1858 OctetString(value=value, bounds=(bound_min, bound_max))
1860 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1861 OctetString(bounds=(bound_min, bound_max)).decode(
1862 OctetString(value).encode()
1865 value = d.draw(binary(min_size=bound_max + 1))
1866 with self.assertRaises(BoundsError) as err:
1867 OctetString(value=value, bounds=(bound_min, bound_max))
1869 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1870 OctetString(bounds=(bound_min, bound_max)).decode(
1871 OctetString(value).encode()
1875 @given(data_strategy())
1876 def test_call(self, d):
1877 for klass in (OctetString, OctetStringInherited):
1886 ) = d.draw(octet_string_values_strategy())
1887 obj_initial = klass(
1893 optional_initial or False,
1904 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1905 if (default is None) and (obj_initial.default is not None):
1908 (bounds is None) and
1909 (value is not None) and
1910 (bounds_initial is not None) and
1911 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1915 (bounds is None) and
1916 (default is not None) and
1917 (bounds_initial is not None) and
1918 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1921 obj = obj_initial(value, bounds, impl, expl, default, optional)
1923 value_expected = default if value is None else value
1925 default_initial if value_expected is None
1928 self.assertEqual(obj, value_expected)
1929 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1930 self.assertEqual(obj.expl_tag, expl or expl_initial)
1933 default_initial if default is None else default,
1935 if obj.default is None:
1936 optional = optional_initial if optional is None else optional
1937 optional = False if optional is None else optional
1940 self.assertEqual(obj.optional, optional)
1942 (obj._bound_min, obj._bound_max),
1943 bounds or bounds_initial or (0, float("+inf")),
1946 @given(octet_string_values_strategy())
1947 def test_copy(self, values):
1948 for klass in (OctetString, OctetStringInherited):
1949 obj = klass(*values)
1950 obj_copied = obj.copy()
1951 self.assert_copied_basic_fields(obj, obj_copied)
1952 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1953 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1954 self.assertEqual(obj._value, obj_copied._value)
1958 integers(min_value=1).map(tag_encode),
1960 def test_stripped(self, value, tag_impl):
1961 obj = OctetString(value, impl=tag_impl)
1962 with self.assertRaises(NotEnoughData):
1963 obj.decode(obj.encode()[:-1])
1967 integers(min_value=1).map(tag_ctxc),
1969 def test_stripped_expl(self, value, tag_expl):
1970 obj = OctetString(value, expl=tag_expl)
1971 with self.assertRaises(NotEnoughData):
1972 obj.decode(obj.encode()[:-1])
1975 integers(min_value=31),
1976 integers(min_value=0),
1979 def test_bad_tag(self, tag, offset, decode_path):
1980 with self.assertRaises(DecodeError) as err:
1981 OctetString().decode(
1982 tag_encode(tag)[:-1],
1984 decode_path=decode_path,
1987 self.assertEqual(err.exception.offset, offset)
1988 self.assertEqual(err.exception.decode_path, decode_path)
1991 integers(min_value=128),
1992 integers(min_value=0),
1995 def test_bad_len(self, l, offset, decode_path):
1996 with self.assertRaises(DecodeError) as err:
1997 OctetString().decode(
1998 OctetString.tag_default + len_encode(l)[:-1],
2000 decode_path=decode_path,
2003 self.assertEqual(err.exception.offset, offset)
2004 self.assertEqual(err.exception.decode_path, decode_path)
2007 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2008 integers(min_value=0),
2011 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2012 value, bound_min = list(sorted(ints))
2014 class String(OctetString):
2015 bounds = (bound_min, bound_min)
2016 with self.assertRaises(DecodeError) as err:
2018 OctetString(b"\x00" * value).encode(),
2020 decode_path=decode_path,
2023 self.assertEqual(err.exception.offset, offset)
2024 self.assertEqual(err.exception.decode_path, decode_path)
2026 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2028 octet_string_values_strategy(),
2030 integers(min_value=1).map(tag_ctxc),
2031 integers(min_value=0),
2034 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2035 for klass in (OctetString, OctetStringInherited):
2036 _, _, _, _, default, optional, _decoded = values
2045 pprint(obj, big_blobs=True, with_decode_path=True)
2046 self.assertFalse(obj.expled)
2047 obj_encoded = obj.encode()
2048 obj_expled = obj(value, expl=tag_expl)
2049 self.assertTrue(obj_expled.expled)
2051 list(obj_expled.pps())
2052 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2053 obj_expled_encoded = obj_expled.encode()
2054 ctx_copied = deepcopy(ctx_dummy)
2055 obj_decoded, tail = obj_expled.decode(
2056 obj_expled_encoded + tail_junk,
2060 self.assertDictEqual(ctx_copied, ctx_dummy)
2062 list(obj_decoded.pps())
2063 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2064 self.assertEqual(tail, tail_junk)
2065 self.assertEqual(obj_decoded, obj_expled)
2066 self.assertNotEqual(obj_decoded, obj)
2067 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2068 self.assertEqual(bytes(obj_decoded), bytes(obj))
2069 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2070 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2071 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2073 obj_decoded.expl_llen,
2074 len(len_encode(len(obj_encoded))),
2076 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2077 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2080 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2082 self.assertEqual(obj_decoded.expl_offset, offset)
2083 assert_exceeding_data(
2085 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2090 integers(min_value=1, max_value=30),
2093 binary(min_size=1, max_size=5),
2095 binary(min_size=1, max_size=5),
2105 def test_constructed(self, impl, chunk_inputs, junk):
2106 def chunk_constructed(contents):
2108 tag_encode(form=TagFormConstructed, num=4) +
2110 b"".join(OctetString(content).encode() for content in contents) +
2114 payload_expected = b""
2115 for chunk_input in chunk_inputs:
2116 if isinstance(chunk_input, binary_type):
2117 chunks.append(OctetString(chunk_input).encode())
2118 payload_expected += chunk_input
2120 chunks.append(chunk_constructed(chunk_input))
2121 payload = b"".join(chunk_input)
2122 payload_expected += payload
2123 encoded_indefinite = (
2124 tag_encode(form=TagFormConstructed, num=impl) +
2129 encoded_definite = (
2130 tag_encode(form=TagFormConstructed, num=impl) +
2131 len_encode(len(b"".join(chunks))) +
2134 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2135 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2136 for lenindef_expected, encoded in (
2137 (True, encoded_indefinite),
2138 (False, encoded_definite),
2140 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2142 ctx={"bered": True},
2144 self.assertSequenceEqual(tail, junk)
2145 self.assertSequenceEqual(bytes(obj), payload_expected)
2146 self.assertTrue(obj.ber_encoded)
2147 self.assertEqual(obj.lenindef, lenindef_expected)
2148 self.assertTrue(obj.bered)
2150 self.assertTrue(obj.ber_encoded)
2151 self.assertEqual(obj.lenindef, lenindef_expected)
2152 self.assertTrue(obj.bered)
2153 self.assertEqual(len(encoded), obj.tlvlen)
2156 integers(min_value=0),
2159 def test_ber_definite_too_short(self, offset, decode_path):
2160 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2161 OctetString().decode(
2162 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2164 decode_path=decode_path,
2165 ctx={"bered": True},
2167 self.assertEqual(err.exception.decode_path, decode_path)
2168 self.assertEqual(err.exception.offset, offset)
2171 integers(min_value=0),
2173 integers(min_value=1, max_value=3),
2175 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2176 bs = OctetString(b"data").encode()
2177 with self.assertRaises(NotEnoughData) as err:
2178 OctetString().decode(
2179 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2181 decode_path=decode_path,
2182 ctx={"bered": True},
2184 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2185 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2188 integers(min_value=0),
2190 integers(min_value=1, max_value=3),
2192 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2193 bs = OctetString(b"data").encode()
2194 bs_longer = OctetString(b"data-longer").encode()
2195 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2196 OctetString().decode(
2198 tag_encode(4, form=TagFormConstructed) +
2199 len_encode((chunks + 1) * len(bs)) +
2204 decode_path=decode_path,
2205 ctx={"bered": True},
2207 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2208 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2212 def null_values_strategy(draw, do_expl=False):
2216 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2218 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2219 optional = draw(one_of(none(), booleans()))
2221 draw(integers(min_value=0)),
2222 draw(integers(min_value=0)),
2223 draw(integers(min_value=0)),
2225 return (impl, expl, optional, _decoded)
2228 class NullInherited(Null):
2232 class TestNull(CommonMixin, TestCase):
2235 def test_ready(self):
2237 self.assertTrue(obj.ready)
2240 pprint(obj, big_blobs=True, with_decode_path=True)
2242 @given(binary(), binary())
2243 def test_comparison(self, tag1, tag2):
2244 for klass in (Null, NullInherited):
2245 obj1 = klass(impl=tag1)
2246 obj2 = klass(impl=tag2)
2247 self.assertEqual(obj1 == obj2, tag1 == tag2)
2248 self.assertEqual(obj1 != obj2, tag1 != tag2)
2249 self.assertNotEqual(obj1, tag2)
2251 @given(data_strategy())
2252 def test_call(self, d):
2253 for klass in (Null, NullInherited):
2259 ) = d.draw(null_values_strategy())
2260 obj_initial = klass(
2263 optional=optional_initial or False,
2264 _decoded=_decoded_initial,
2271 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2272 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2273 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2274 self.assertEqual(obj.expl_tag, expl or expl_initial)
2275 optional = optional_initial if optional is None else optional
2276 optional = False if optional is None else optional
2277 self.assertEqual(obj.optional, optional)
2279 @given(null_values_strategy())
2280 def test_copy(self, values):
2281 for klass in (Null, NullInherited):
2282 impl, expl, optional, _decoded = values
2286 optional=optional or False,
2289 obj_copied = obj.copy()
2290 self.assert_copied_basic_fields(obj, obj_copied)
2292 @given(integers(min_value=1).map(tag_encode))
2293 def test_stripped(self, tag_impl):
2294 obj = Null(impl=tag_impl)
2295 with self.assertRaises(NotEnoughData):
2296 obj.decode(obj.encode()[:-1])
2298 @given(integers(min_value=1).map(tag_ctxc))
2299 def test_stripped_expl(self, tag_expl):
2300 obj = Null(expl=tag_expl)
2301 with self.assertRaises(NotEnoughData):
2302 obj.decode(obj.encode()[:-1])
2305 integers(min_value=31),
2306 integers(min_value=0),
2309 def test_bad_tag(self, tag, offset, decode_path):
2310 with self.assertRaises(DecodeError) as err:
2312 tag_encode(tag)[:-1],
2314 decode_path=decode_path,
2317 self.assertEqual(err.exception.offset, offset)
2318 self.assertEqual(err.exception.decode_path, decode_path)
2321 integers(min_value=128),
2322 integers(min_value=0),
2325 def test_bad_len(self, l, offset, decode_path):
2326 with self.assertRaises(DecodeError) as err:
2328 Null.tag_default + len_encode(l)[:-1],
2330 decode_path=decode_path,
2333 self.assertEqual(err.exception.offset, offset)
2334 self.assertEqual(err.exception.decode_path, decode_path)
2336 @given(binary(min_size=1))
2337 def test_tag_mismatch(self, impl):
2338 assume(impl != Null.tag_default)
2339 with self.assertRaises(TagMismatch):
2340 Null(impl=impl).decode(Null().encode())
2343 null_values_strategy(),
2344 integers(min_value=1).map(tag_ctxc),
2345 integers(min_value=0),
2348 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2349 for klass in (Null, NullInherited):
2350 _, _, optional, _decoded = values
2351 obj = klass(optional=optional, _decoded=_decoded)
2354 pprint(obj, big_blobs=True, with_decode_path=True)
2355 self.assertFalse(obj.expled)
2356 obj_encoded = obj.encode()
2357 obj_expled = obj(expl=tag_expl)
2358 self.assertTrue(obj_expled.expled)
2360 list(obj_expled.pps())
2361 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2362 obj_expled_encoded = obj_expled.encode()
2363 ctx_copied = deepcopy(ctx_dummy)
2364 obj_decoded, tail = obj_expled.decode(
2365 obj_expled_encoded + tail_junk,
2369 self.assertDictEqual(ctx_copied, ctx_dummy)
2371 list(obj_decoded.pps())
2372 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2373 self.assertEqual(tail, tail_junk)
2374 self.assertEqual(obj_decoded, obj_expled)
2375 self.assertNotEqual(obj_decoded, obj)
2376 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2377 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2378 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2380 obj_decoded.expl_llen,
2381 len(len_encode(len(obj_encoded))),
2383 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2384 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2387 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2389 self.assertEqual(obj_decoded.expl_offset, offset)
2390 assert_exceeding_data(
2392 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2396 @given(integers(min_value=1))
2397 def test_invalid_len(self, l):
2398 with self.assertRaises(InvalidLength):
2399 Null().decode(b"".join((
2406 def oid_strategy(draw):
2407 first_arc = draw(integers(min_value=0, max_value=2))
2409 if first_arc in (0, 1):
2410 second_arc = draw(integers(min_value=0, max_value=39))
2412 second_arc = draw(integers(min_value=0))
2413 other_arcs = draw(lists(integers(min_value=0)))
2414 return tuple([first_arc, second_arc] + other_arcs)
2418 def oid_values_strategy(draw, do_expl=False):
2419 value = draw(one_of(none(), oid_strategy()))
2423 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2425 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2426 default = draw(one_of(none(), oid_strategy()))
2427 optional = draw(one_of(none(), booleans()))
2429 draw(integers(min_value=0)),
2430 draw(integers(min_value=0)),
2431 draw(integers(min_value=0)),
2433 return (value, impl, expl, default, optional, _decoded)
2436 class ObjectIdentifierInherited(ObjectIdentifier):
2440 class TestObjectIdentifier(CommonMixin, TestCase):
2441 base_klass = ObjectIdentifier
2443 def test_invalid_value_type(self):
2444 with self.assertRaises(InvalidValueType) as err:
2445 ObjectIdentifier(123)
2449 def test_optional(self, optional):
2450 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2451 self.assertTrue(obj.optional)
2453 @given(oid_strategy())
2454 def test_ready(self, value):
2455 obj = ObjectIdentifier()
2456 self.assertFalse(obj.ready)
2459 pprint(obj, big_blobs=True, with_decode_path=True)
2460 with self.assertRaises(ObjNotReady) as err:
2463 obj = ObjectIdentifier(value)
2464 self.assertTrue(obj.ready)
2465 self.assertFalse(obj.ber_encoded)
2468 pprint(obj, big_blobs=True, with_decode_path=True)
2471 @given(oid_strategy(), oid_strategy(), binary(), binary())
2472 def test_comparison(self, value1, value2, tag1, tag2):
2473 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2474 obj1 = klass(value1)
2475 obj2 = klass(value2)
2476 self.assertEqual(obj1 == obj2, value1 == value2)
2477 self.assertEqual(obj1 != obj2, value1 != value2)
2478 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2479 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2480 obj1 = klass(value1, impl=tag1)
2481 obj2 = klass(value1, impl=tag2)
2482 self.assertEqual(obj1 == obj2, tag1 == tag2)
2483 self.assertEqual(obj1 != obj2, tag1 != tag2)
2485 @given(lists(oid_strategy()))
2486 def test_sorted_works(self, values):
2487 self.assertSequenceEqual(
2488 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2492 @given(data_strategy())
2493 def test_call(self, d):
2494 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2502 ) = d.draw(oid_values_strategy())
2503 obj_initial = klass(
2504 value=value_initial,
2507 default=default_initial,
2508 optional=optional_initial or False,
2509 _decoded=_decoded_initial,
2518 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2527 value_expected = default if value is None else value
2529 default_initial if value_expected is None
2532 self.assertEqual(obj, value_expected)
2533 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2534 self.assertEqual(obj.expl_tag, expl or expl_initial)
2537 default_initial if default is None else default,
2539 if obj.default is None:
2540 optional = optional_initial if optional is None else optional
2541 optional = False if optional is None else optional
2544 self.assertEqual(obj.optional, optional)
2546 @given(oid_values_strategy())
2547 def test_copy(self, values):
2548 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2565 obj_copied = obj.copy()
2566 self.assert_copied_basic_fields(obj, obj_copied)
2567 self.assertEqual(obj._value, obj_copied._value)
2569 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2572 integers(min_value=1).map(tag_encode),
2574 def test_stripped(self, value, tag_impl):
2575 obj = ObjectIdentifier(value, impl=tag_impl)
2576 with self.assertRaises(NotEnoughData):
2577 obj.decode(obj.encode()[:-1])
2581 integers(min_value=1).map(tag_ctxc),
2583 def test_stripped_expl(self, value, tag_expl):
2584 obj = ObjectIdentifier(value, expl=tag_expl)
2585 with self.assertRaises(NotEnoughData):
2586 obj.decode(obj.encode()[:-1])
2589 integers(min_value=31),
2590 integers(min_value=0),
2593 def test_bad_tag(self, tag, offset, decode_path):
2594 with self.assertRaises(DecodeError) as err:
2595 ObjectIdentifier().decode(
2596 tag_encode(tag)[:-1],
2598 decode_path=decode_path,
2601 self.assertEqual(err.exception.offset, offset)
2602 self.assertEqual(err.exception.decode_path, decode_path)
2605 integers(min_value=128),
2606 integers(min_value=0),
2609 def test_bad_len(self, l, offset, decode_path):
2610 with self.assertRaises(DecodeError) as err:
2611 ObjectIdentifier().decode(
2612 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2614 decode_path=decode_path,
2617 self.assertEqual(err.exception.offset, offset)
2618 self.assertEqual(err.exception.decode_path, decode_path)
2620 def test_zero_oid(self):
2621 with self.assertRaises(NotEnoughData):
2622 ObjectIdentifier().decode(
2623 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2626 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2627 @given(oid_strategy())
2628 def test_unfinished_oid(self, value):
2629 assume(list(value)[-1] > 255)
2630 obj_encoded = ObjectIdentifier(value).encode()
2631 obj, _ = ObjectIdentifier().decode(obj_encoded)
2632 data = obj_encoded[obj.tlen + obj.llen:-1]
2634 ObjectIdentifier.tag_default,
2635 len_encode(len(data)),
2638 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2641 @given(integers(min_value=0))
2642 def test_invalid_short(self, value):
2643 with self.assertRaises(InvalidOID):
2644 ObjectIdentifier((value,))
2645 with self.assertRaises(InvalidOID):
2646 ObjectIdentifier("%d" % value)
2648 @given(integers(min_value=3), integers(min_value=0))
2649 def test_invalid_first_arc(self, first_arc, second_arc):
2650 with self.assertRaises(InvalidOID):
2651 ObjectIdentifier((first_arc, second_arc))
2652 with self.assertRaises(InvalidOID):
2653 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2655 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2656 def test_invalid_second_arc(self, first_arc, second_arc):
2657 with self.assertRaises(InvalidOID):
2658 ObjectIdentifier((first_arc, second_arc))
2659 with self.assertRaises(InvalidOID):
2660 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2662 @given(text(alphabet=ascii_letters + ".", min_size=1))
2663 def test_junk(self, oid):
2664 with self.assertRaises(InvalidOID):
2665 ObjectIdentifier(oid)
2667 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2668 @given(oid_strategy())
2669 def test_validness(self, oid):
2670 obj = ObjectIdentifier(oid)
2671 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2674 pprint(obj, big_blobs=True, with_decode_path=True)
2676 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2678 oid_values_strategy(),
2680 integers(min_value=1).map(tag_ctxc),
2681 integers(min_value=0),
2684 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2685 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2686 _, _, _, default, optional, _decoded = values
2695 pprint(obj, big_blobs=True, with_decode_path=True)
2696 self.assertFalse(obj.expled)
2697 obj_encoded = obj.encode()
2698 obj_expled = obj(value, expl=tag_expl)
2699 self.assertTrue(obj_expled.expled)
2701 list(obj_expled.pps())
2702 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2703 obj_expled_encoded = obj_expled.encode()
2704 ctx_copied = deepcopy(ctx_dummy)
2705 obj_decoded, tail = obj_expled.decode(
2706 obj_expled_encoded + tail_junk,
2710 self.assertDictEqual(ctx_copied, ctx_dummy)
2712 list(obj_decoded.pps())
2713 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2714 self.assertEqual(tail, tail_junk)
2715 self.assertEqual(obj_decoded, obj_expled)
2716 self.assertNotEqual(obj_decoded, obj)
2717 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2718 self.assertEqual(tuple(obj_decoded), tuple(obj))
2719 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2720 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2721 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2723 obj_decoded.expl_llen,
2724 len(len_encode(len(obj_encoded))),
2726 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2727 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2730 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2732 self.assertEqual(obj_decoded.expl_offset, offset)
2733 assert_exceeding_data(
2735 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2740 oid_strategy().map(ObjectIdentifier),
2741 oid_strategy().map(ObjectIdentifier),
2743 def test_add(self, oid1, oid2):
2744 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2745 for oid_to_add in (oid2, tuple(oid2)):
2746 self.assertEqual(oid1 + oid_to_add, oid_expect)
2747 with self.assertRaises(InvalidValueType):
2750 def test_go_vectors_valid(self):
2751 for data, expect in (
2753 (b"\x55\x02", (2, 5, 2)),
2754 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2755 (b"\x81\x34\x03", (2, 100, 3)),
2758 ObjectIdentifier().decode(b"".join((
2759 ObjectIdentifier.tag_default,
2760 len_encode(len(data)),
2766 def test_go_vectors_invalid(self):
2767 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2768 with self.assertRaises(DecodeError):
2769 ObjectIdentifier().decode(b"".join((
2770 Integer.tag_default,
2771 len_encode(len(data)),
2775 def test_x690_vector(self):
2777 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2778 ObjectIdentifier((2, 999, 3)),
2781 def test_nonnormalized_first_arc(self):
2783 ObjectIdentifier.tag_default +
2786 ObjectIdentifier((1, 0)).encode()[-1:]
2788 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2789 self.assertTrue(obj.ber_encoded)
2790 self.assertTrue(obj.bered)
2792 self.assertTrue(obj.ber_encoded)
2793 self.assertTrue(obj.bered)
2794 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2795 ObjectIdentifier().decode(tampered)
2797 @given(data_strategy())
2798 def test_nonnormalized_arcs(self, d):
2799 arcs = d.draw(lists(
2800 integers(min_value=0, max_value=100),
2804 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2805 _, _, lv = tag_strip(dered)
2806 _, _, v = len_decode(lv)
2807 v_no_first_arc = v[1:]
2808 idx_for_tamper = d.draw(integers(
2810 max_value=len(v_no_first_arc) - 1,
2812 tampered = list(bytearray(v_no_first_arc))
2813 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2814 tampered.insert(idx_for_tamper, 0x80)
2815 tampered = bytes(bytearray(tampered))
2817 ObjectIdentifier.tag_default +
2818 len_encode(len(tampered)) +
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)
2832 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2834 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2835 values = list(draw(sets(
2837 min_size=len(schema),
2838 max_size=len(schema),
2840 schema = list(zip(schema, values))
2841 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2845 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2847 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2848 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2849 optional = draw(one_of(none(), booleans()))
2851 draw(integers(min_value=0)),
2852 draw(integers(min_value=0)),
2853 draw(integers(min_value=0)),
2855 return (schema, value, impl, expl, default, optional, _decoded)
2858 class TestEnumerated(CommonMixin, TestCase):
2859 class EWhatever(Enumerated):
2860 schema = (("whatever", 0),)
2862 base_klass = EWhatever
2864 def test_schema_required(self):
2865 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2868 def test_invalid_value_type(self):
2869 with self.assertRaises(InvalidValueType) as err:
2870 self.base_klass((1, 2))
2873 @given(sets(text_letters(), min_size=2))
2874 def test_unknown_name(self, schema_input):
2875 missing = schema_input.pop()
2877 class E(Enumerated):
2878 schema = [(n, 123) for n in schema_input]
2879 with self.assertRaises(ObjUnknown) as err:
2884 sets(text_letters(), min_size=2),
2885 sets(integers(), min_size=2),
2887 def test_unknown_value(self, schema_input, values_input):
2889 missing_value = values_input.pop()
2890 _input = list(zip(schema_input, values_input))
2892 class E(Enumerated):
2894 with self.assertRaises(DecodeError) as err:
2899 def test_optional(self, optional):
2900 obj = self.base_klass(default="whatever", optional=optional)
2901 self.assertTrue(obj.optional)
2903 def test_ready(self):
2904 obj = self.base_klass()
2905 self.assertFalse(obj.ready)
2908 pprint(obj, big_blobs=True, with_decode_path=True)
2909 with self.assertRaises(ObjNotReady) as err:
2912 obj = self.base_klass("whatever")
2913 self.assertTrue(obj.ready)
2916 pprint(obj, big_blobs=True, with_decode_path=True)
2918 @given(integers(), integers(), binary(), binary())
2919 def test_comparison(self, value1, value2, tag1, tag2):
2920 class E(Enumerated):
2922 ("whatever0", value1),
2923 ("whatever1", value2),
2926 class EInherited(E):
2928 for klass in (E, EInherited):
2929 obj1 = klass(value1)
2930 obj2 = klass(value2)
2931 self.assertEqual(obj1 == obj2, value1 == value2)
2932 self.assertEqual(obj1 != obj2, value1 != value2)
2933 self.assertEqual(obj1 == int(obj2), value1 == value2)
2934 obj1 = klass(value1, impl=tag1)
2935 obj2 = klass(value1, impl=tag2)
2936 self.assertEqual(obj1 == obj2, tag1 == tag2)
2937 self.assertEqual(obj1 != obj2, tag1 != tag2)
2939 @given(data_strategy())
2940 def test_call(self, d):
2949 ) = d.draw(enumerated_values_strategy())
2951 class E(Enumerated):
2952 schema = schema_initial
2954 value=value_initial,
2957 default=default_initial,
2958 optional=optional_initial or False,
2959 _decoded=_decoded_initial,
2969 ) = d.draw(enumerated_values_strategy(
2970 schema=schema_initial,
2971 do_expl=impl_initial is None,
2981 value_expected = default if value is None else value
2983 default_initial if value_expected is None
2988 dict(schema_initial).get(value_expected, value_expected),
2990 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2991 self.assertEqual(obj.expl_tag, expl or expl_initial)
2994 default_initial if default is None else default,
2996 if obj.default is None:
2997 optional = optional_initial if optional is None else optional
2998 optional = False if optional is None else optional
3001 self.assertEqual(obj.optional, optional)
3002 self.assertEqual(obj.specs, dict(schema_initial))
3004 @given(enumerated_values_strategy())
3005 def test_copy(self, values):
3006 schema_input, value, impl, expl, default, optional, _decoded = values
3008 class E(Enumerated):
3009 schema = schema_input
3018 obj_copied = obj.copy()
3019 self.assert_copied_basic_fields(obj, obj_copied)
3020 self.assertEqual(obj.specs, obj_copied.specs)
3022 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3023 @given(data_strategy())
3024 def test_symmetric(self, d):
3025 schema_input, _, _, _, default, optional, _decoded = d.draw(
3026 enumerated_values_strategy(),
3028 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3029 offset = d.draw(integers(min_value=0))
3030 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3031 tail_junk = d.draw(binary(max_size=5))
3033 class E(Enumerated):
3034 schema = schema_input
3043 pprint(obj, big_blobs=True, with_decode_path=True)
3044 self.assertFalse(obj.expled)
3045 obj_encoded = obj.encode()
3046 obj_expled = obj(value, expl=tag_expl)
3047 self.assertTrue(obj_expled.expled)
3049 list(obj_expled.pps())
3050 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3051 obj_expled_encoded = obj_expled.encode()
3052 ctx_copied = deepcopy(ctx_dummy)
3053 obj_decoded, tail = obj_expled.decode(
3054 obj_expled_encoded + tail_junk,
3058 self.assertDictEqual(ctx_copied, ctx_dummy)
3060 list(obj_decoded.pps())
3061 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3062 self.assertEqual(tail, tail_junk)
3063 self.assertEqual(obj_decoded, obj_expled)
3064 self.assertNotEqual(obj_decoded, obj)
3065 self.assertEqual(int(obj_decoded), int(obj_expled))
3066 self.assertEqual(int(obj_decoded), int(obj))
3067 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3068 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3069 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3071 obj_decoded.expl_llen,
3072 len(len_encode(len(obj_encoded))),
3074 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3075 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3078 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3080 self.assertEqual(obj_decoded.expl_offset, offset)
3081 assert_exceeding_data(
3083 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3089 def string_values_strategy(draw, alphabet, do_expl=False):
3090 bound_min, bound_max = sorted(draw(sets(
3091 integers(min_value=0, max_value=1 << 7),
3095 value = draw(one_of(
3097 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3099 default = draw(one_of(
3101 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3104 if draw(booleans()):
3105 bounds = (bound_min, bound_max)
3109 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3111 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3112 optional = draw(one_of(none(), booleans()))
3114 draw(integers(min_value=0)),
3115 draw(integers(min_value=0)),
3116 draw(integers(min_value=0)),
3118 return (value, bounds, impl, expl, default, optional, _decoded)
3121 class StringMixin(object):
3122 def test_invalid_value_type(self):
3123 with self.assertRaises(InvalidValueType) as err:
3124 self.base_klass((1, 2))
3127 def text_alphabet(self):
3128 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3129 return printable + whitespace
3133 def test_optional(self, optional):
3134 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3135 self.assertTrue(obj.optional)
3137 @given(data_strategy())
3138 def test_ready(self, d):
3139 obj = self.base_klass()
3140 self.assertFalse(obj.ready)
3143 pprint(obj, big_blobs=True, with_decode_path=True)
3145 with self.assertRaises(ObjNotReady) as err:
3148 value = d.draw(text(alphabet=self.text_alphabet()))
3149 obj = self.base_klass(value)
3150 self.assertTrue(obj.ready)
3153 pprint(obj, big_blobs=True, with_decode_path=True)
3156 @given(data_strategy())
3157 def test_comparison(self, d):
3158 value1 = d.draw(text(alphabet=self.text_alphabet()))
3159 value2 = d.draw(text(alphabet=self.text_alphabet()))
3160 tag1 = d.draw(binary(min_size=1))
3161 tag2 = d.draw(binary(min_size=1))
3162 obj1 = self.base_klass(value1)
3163 obj2 = self.base_klass(value2)
3164 self.assertEqual(obj1 == obj2, value1 == value2)
3165 self.assertEqual(obj1 != obj2, value1 != value2)
3166 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3167 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3168 obj1 = self.base_klass(value1, impl=tag1)
3169 obj2 = self.base_klass(value1, impl=tag2)
3170 self.assertEqual(obj1 == obj2, tag1 == tag2)
3171 self.assertEqual(obj1 != obj2, tag1 != tag2)
3173 @given(data_strategy())
3174 def test_bounds_satisfied(self, d):
3175 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3176 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3177 value = d.draw(text(
3178 alphabet=self.text_alphabet(),
3182 self.base_klass(value=value, bounds=(bound_min, bound_max))
3184 @given(data_strategy())
3185 def test_bounds_unsatisfied(self, d):
3186 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3187 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3188 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3189 with self.assertRaises(BoundsError) as err:
3190 self.base_klass(value=value, bounds=(bound_min, bound_max))
3192 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3193 self.base_klass(bounds=(bound_min, bound_max)).decode(
3194 self.base_klass(value).encode()
3197 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3198 with self.assertRaises(BoundsError) as err:
3199 self.base_klass(value=value, bounds=(bound_min, bound_max))
3201 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3202 self.base_klass(bounds=(bound_min, bound_max)).decode(
3203 self.base_klass(value).encode()
3207 @given(data_strategy())
3208 def test_call(self, d):
3217 ) = d.draw(string_values_strategy(self.text_alphabet()))
3218 obj_initial = self.base_klass(
3224 optional_initial or False,
3235 ) = d.draw(string_values_strategy(
3236 self.text_alphabet(),
3237 do_expl=impl_initial is None,
3239 if (default is None) and (obj_initial.default is not None):
3242 (bounds is None) and
3243 (value is not None) and
3244 (bounds_initial is not None) and
3245 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3249 (bounds is None) and
3250 (default is not None) and
3251 (bounds_initial is not None) and
3252 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3255 obj = obj_initial(value, bounds, impl, expl, default, optional)
3257 value_expected = default if value is None else value
3259 default_initial if value_expected is None
3262 self.assertEqual(obj, value_expected)
3263 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3264 self.assertEqual(obj.expl_tag, expl or expl_initial)
3267 default_initial if default is None else default,
3269 if obj.default is None:
3270 optional = optional_initial if optional is None else optional
3271 optional = False if optional is None else optional
3274 self.assertEqual(obj.optional, optional)
3276 (obj._bound_min, obj._bound_max),
3277 bounds or bounds_initial or (0, float("+inf")),
3280 @given(data_strategy())
3281 def test_copy(self, d):
3282 values = d.draw(string_values_strategy(self.text_alphabet()))
3283 obj = self.base_klass(*values)
3284 obj_copied = obj.copy()
3285 self.assert_copied_basic_fields(obj, obj_copied)
3286 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3287 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3288 self.assertEqual(obj._value, obj_copied._value)
3290 @given(data_strategy())
3291 def test_stripped(self, d):
3292 value = d.draw(text(alphabet=self.text_alphabet()))
3293 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3294 obj = self.base_klass(value, impl=tag_impl)
3295 with self.assertRaises(NotEnoughData):
3296 obj.decode(obj.encode()[:-1])
3298 @given(data_strategy())
3299 def test_stripped_expl(self, d):
3300 value = d.draw(text(alphabet=self.text_alphabet()))
3301 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3302 obj = self.base_klass(value, expl=tag_expl)
3303 with self.assertRaises(NotEnoughData):
3304 obj.decode(obj.encode()[:-1])
3307 integers(min_value=31),
3308 integers(min_value=0),
3311 def test_bad_tag(self, tag, offset, decode_path):
3312 with self.assertRaises(DecodeError) as err:
3313 self.base_klass().decode(
3314 tag_encode(tag)[:-1],
3316 decode_path=decode_path,
3319 self.assertEqual(err.exception.offset, offset)
3320 self.assertEqual(err.exception.decode_path, decode_path)
3323 integers(min_value=128),
3324 integers(min_value=0),
3327 def test_bad_len(self, l, offset, decode_path):
3328 with self.assertRaises(DecodeError) as err:
3329 self.base_klass().decode(
3330 self.base_klass.tag_default + len_encode(l)[:-1],
3332 decode_path=decode_path,
3335 self.assertEqual(err.exception.offset, offset)
3336 self.assertEqual(err.exception.decode_path, decode_path)
3339 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3340 integers(min_value=0),
3343 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3344 value, bound_min = list(sorted(ints))
3346 class String(self.base_klass):
3347 # Multiply this value by four, to satisfy UTF-32 bounds
3348 # (4 bytes per character) validation
3349 bounds = (bound_min * 4, bound_min * 4)
3350 with self.assertRaises(DecodeError) as err:
3352 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3354 decode_path=decode_path,
3357 self.assertEqual(err.exception.offset, offset)
3358 self.assertEqual(err.exception.decode_path, decode_path)
3360 @given(data_strategy())
3361 def test_symmetric(self, d):
3362 values = d.draw(string_values_strategy(self.text_alphabet()))
3363 value = d.draw(text(alphabet=self.text_alphabet()))
3364 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3365 offset = d.draw(integers(min_value=0))
3366 tail_junk = d.draw(binary(max_size=5))
3367 _, _, _, _, default, optional, _decoded = values
3368 obj = self.base_klass(
3376 pprint(obj, big_blobs=True, with_decode_path=True)
3377 self.assertFalse(obj.expled)
3378 obj_encoded = obj.encode()
3379 obj_expled = obj(value, expl=tag_expl)
3380 self.assertTrue(obj_expled.expled)
3382 list(obj_expled.pps())
3383 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3384 obj_expled_encoded = obj_expled.encode()
3385 ctx_copied = deepcopy(ctx_dummy)
3386 obj_decoded, tail = obj_expled.decode(
3387 obj_expled_encoded + tail_junk,
3391 self.assertDictEqual(ctx_copied, ctx_dummy)
3393 list(obj_decoded.pps())
3394 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3395 self.assertEqual(tail, tail_junk)
3396 self.assertEqual(obj_decoded, obj_expled)
3397 self.assertNotEqual(obj_decoded, obj)
3398 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3399 self.assertEqual(bytes(obj_decoded), bytes(obj))
3400 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3401 self.assertEqual(text_type(obj_decoded), text_type(obj))
3402 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3403 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3404 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3406 obj_decoded.expl_llen,
3407 len(len_encode(len(obj_encoded))),
3409 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3410 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3413 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3415 self.assertEqual(obj_decoded.expl_offset, offset)
3416 assert_exceeding_data(
3418 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3423 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3424 base_klass = UTF8String
3427 cyrillic_letters = text(
3428 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3434 class UnicodeDecodeErrorMixin(object):
3435 @given(cyrillic_letters)
3436 def test_unicode_decode_error(self, cyrillic_text):
3437 with self.assertRaises(DecodeError):
3438 self.base_klass(cyrillic_text)
3441 class TestNumericString(StringMixin, CommonMixin, TestCase):
3442 base_klass = NumericString
3444 def text_alphabet(self):
3447 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3448 def test_non_numeric(self, non_numeric_text):
3449 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3450 self.base_klass(non_numeric_text)
3453 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3454 integers(min_value=0),
3457 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3458 value, bound_min = list(sorted(ints))
3460 class String(self.base_klass):
3461 bounds = (bound_min, bound_min)
3462 with self.assertRaises(DecodeError) as err:
3464 self.base_klass(b"1" * value).encode(),
3466 decode_path=decode_path,
3469 self.assertEqual(err.exception.offset, offset)
3470 self.assertEqual(err.exception.decode_path, decode_path)
3473 class TestPrintableString(
3474 UnicodeDecodeErrorMixin,
3479 base_klass = PrintableString
3481 def text_alphabet(self):
3482 return ascii_letters + digits + " '()+,-./:=?"
3484 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3485 def test_non_printable(self, non_printable_text):
3486 with assertRaisesRegex(self, DecodeError, "non-printable"):
3487 self.base_klass(non_printable_text)
3490 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3491 integers(min_value=0),
3494 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3495 value, bound_min = list(sorted(ints))
3497 class String(self.base_klass):
3498 bounds = (bound_min, bound_min)
3499 with self.assertRaises(DecodeError) as err:
3501 self.base_klass(b"1" * value).encode(),
3503 decode_path=decode_path,
3506 self.assertEqual(err.exception.offset, offset)
3507 self.assertEqual(err.exception.decode_path, decode_path)
3509 def test_allowable_invalid_chars(self):
3511 ("*", {"allow_asterisk": True}),
3512 ("&", {"allow_ampersand": True}),
3513 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3515 s = "hello invalid " + c
3516 with assertRaisesRegex(self, DecodeError, "non-printable"):
3518 self.base_klass(s, **kwargs)
3519 klass = self.base_klass(**kwargs)
3525 class TestTeletexString(
3526 UnicodeDecodeErrorMixin,
3531 base_klass = TeletexString
3534 class TestVideotexString(
3535 UnicodeDecodeErrorMixin,
3540 base_klass = VideotexString
3543 class TestIA5String(
3544 UnicodeDecodeErrorMixin,
3549 base_klass = IA5String
3552 class TestGraphicString(
3553 UnicodeDecodeErrorMixin,
3558 base_klass = GraphicString
3561 class TestVisibleString(
3562 UnicodeDecodeErrorMixin,
3567 base_klass = VisibleString
3569 def test_x690_vector(self):
3570 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3571 self.assertSequenceEqual(tail, b"")
3572 self.assertEqual(str(obj), "Jones")
3573 self.assertFalse(obj.ber_encoded)
3574 self.assertFalse(obj.lenindef)
3575 self.assertFalse(obj.bered)
3577 obj, tail = VisibleString().decode(
3578 hexdec("3A0904034A6F6E04026573"),
3579 ctx={"bered": True},
3581 self.assertSequenceEqual(tail, b"")
3582 self.assertEqual(str(obj), "Jones")
3583 self.assertTrue(obj.ber_encoded)
3584 self.assertFalse(obj.lenindef)
3585 self.assertTrue(obj.bered)
3587 self.assertTrue(obj.ber_encoded)
3588 self.assertFalse(obj.lenindef)
3589 self.assertTrue(obj.bered)
3591 obj, tail = VisibleString().decode(
3592 hexdec("3A8004034A6F6E040265730000"),
3593 ctx={"bered": True},
3595 self.assertSequenceEqual(tail, b"")
3596 self.assertEqual(str(obj), "Jones")
3597 self.assertTrue(obj.ber_encoded)
3598 self.assertTrue(obj.lenindef)
3599 self.assertTrue(obj.bered)
3601 self.assertTrue(obj.ber_encoded)
3602 self.assertTrue(obj.lenindef)
3603 self.assertTrue(obj.bered)
3606 class TestGeneralString(
3607 UnicodeDecodeErrorMixin,
3612 base_klass = GeneralString
3615 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3616 base_klass = UniversalString
3619 class TestBMPString(StringMixin, CommonMixin, TestCase):
3620 base_klass = BMPString
3624 def generalized_time_values_strategy(
3632 if draw(booleans()):
3633 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3635 value = value.replace(microsecond=0)
3637 if draw(booleans()):
3638 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3640 default = default.replace(microsecond=0)
3644 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3646 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3647 optional = draw(one_of(none(), booleans()))
3649 draw(integers(min_value=0)),
3650 draw(integers(min_value=0)),
3651 draw(integers(min_value=0)),
3653 return (value, impl, expl, default, optional, _decoded)
3656 class TimeMixin(object):
3657 def test_invalid_value_type(self):
3658 with self.assertRaises(InvalidValueType) as err:
3659 self.base_klass(datetime.now().timetuple())
3662 @given(data_strategy())
3663 def test_optional(self, d):
3664 default = d.draw(datetimes(
3665 min_value=self.min_datetime,
3666 max_value=self.max_datetime,
3668 optional = d.draw(booleans())
3669 obj = self.base_klass(default=default, optional=optional)
3670 self.assertTrue(obj.optional)
3672 @given(data_strategy())
3673 def test_ready(self, d):
3674 obj = self.base_klass()
3675 self.assertFalse(obj.ready)
3678 pprint(obj, big_blobs=True, with_decode_path=True)
3679 with self.assertRaises(ObjNotReady) as err:
3682 value = d.draw(datetimes(min_value=self.min_datetime))
3683 obj = self.base_klass(value)
3684 self.assertTrue(obj.ready)
3687 pprint(obj, big_blobs=True, with_decode_path=True)
3689 @given(data_strategy())
3690 def test_comparison(self, d):
3691 value1 = d.draw(datetimes(
3692 min_value=self.min_datetime,
3693 max_value=self.max_datetime,
3695 value2 = d.draw(datetimes(
3696 min_value=self.min_datetime,
3697 max_value=self.max_datetime,
3699 tag1 = d.draw(binary(min_size=1))
3700 tag2 = d.draw(binary(min_size=1))
3702 value1 = value1.replace(microsecond=0)
3703 value2 = value2.replace(microsecond=0)
3704 obj1 = self.base_klass(value1)
3705 obj2 = self.base_klass(value2)
3706 self.assertEqual(obj1 == obj2, value1 == value2)
3707 self.assertEqual(obj1 != obj2, value1 != value2)
3708 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3709 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3710 obj1 = self.base_klass(value1, impl=tag1)
3711 obj2 = self.base_klass(value1, impl=tag2)
3712 self.assertEqual(obj1 == obj2, tag1 == tag2)
3713 self.assertEqual(obj1 != obj2, tag1 != tag2)
3715 @given(data_strategy())
3716 def test_call(self, d):
3724 ) = d.draw(generalized_time_values_strategy(
3725 min_datetime=self.min_datetime,
3726 max_datetime=self.max_datetime,
3727 omit_ms=self.omit_ms,
3729 obj_initial = self.base_klass(
3730 value=value_initial,
3733 default=default_initial,
3734 optional=optional_initial or False,
3735 _decoded=_decoded_initial,
3744 ) = d.draw(generalized_time_values_strategy(
3745 min_datetime=self.min_datetime,
3746 max_datetime=self.max_datetime,
3747 omit_ms=self.omit_ms,
3748 do_expl=impl_initial is None,
3758 value_expected = default if value is None else value
3760 default_initial if value_expected is None
3763 self.assertEqual(obj, value_expected)
3764 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3765 self.assertEqual(obj.expl_tag, expl or expl_initial)
3768 default_initial if default is None else default,
3770 if obj.default is None:
3771 optional = optional_initial if optional is None else optional
3772 optional = False if optional is None else optional
3775 self.assertEqual(obj.optional, optional)
3777 @given(data_strategy())
3778 def test_copy(self, d):
3779 values = d.draw(generalized_time_values_strategy(
3780 min_datetime=self.min_datetime,
3781 max_datetime=self.max_datetime,
3783 obj = self.base_klass(*values)
3784 obj_copied = obj.copy()
3785 self.assert_copied_basic_fields(obj, obj_copied)
3786 self.assertEqual(obj._value, obj_copied._value)
3788 @given(data_strategy())
3789 def test_stripped(self, d):
3790 value = d.draw(datetimes(
3791 min_value=self.min_datetime,
3792 max_value=self.max_datetime,
3794 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3795 obj = self.base_klass(value, impl=tag_impl)
3796 with self.assertRaises(NotEnoughData):
3797 obj.decode(obj.encode()[:-1])
3799 @given(data_strategy())
3800 def test_stripped_expl(self, d):
3801 value = d.draw(datetimes(
3802 min_value=self.min_datetime,
3803 max_value=self.max_datetime,
3805 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3806 obj = self.base_klass(value, expl=tag_expl)
3807 with self.assertRaises(NotEnoughData):
3808 obj.decode(obj.encode()[:-1])
3810 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3811 @given(data_strategy())
3812 def test_symmetric(self, d):
3813 values = d.draw(generalized_time_values_strategy(
3814 min_datetime=self.min_datetime,
3815 max_datetime=self.max_datetime,
3817 value = d.draw(datetimes(
3818 min_value=self.min_datetime,
3819 max_value=self.max_datetime,
3821 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3822 offset = d.draw(integers(min_value=0))
3823 tail_junk = d.draw(binary(max_size=5))
3824 _, _, _, default, optional, _decoded = values
3825 obj = self.base_klass(
3833 pprint(obj, big_blobs=True, with_decode_path=True)
3834 self.assertFalse(obj.expled)
3835 obj_encoded = obj.encode()
3836 self.additional_symmetric_check(value, obj_encoded)
3837 obj_expled = obj(value, expl=tag_expl)
3838 self.assertTrue(obj_expled.expled)
3840 list(obj_expled.pps())
3841 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3842 obj_expled_encoded = obj_expled.encode()
3843 ctx_copied = deepcopy(ctx_dummy)
3844 obj_decoded, tail = obj_expled.decode(
3845 obj_expled_encoded + tail_junk,
3849 self.assertDictEqual(ctx_copied, ctx_dummy)
3851 list(obj_decoded.pps())
3852 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3853 self.assertEqual(tail, tail_junk)
3854 self.assertEqual(obj_decoded, obj_expled)
3855 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3856 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3857 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3858 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3859 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3861 obj_decoded.expl_llen,
3862 len(len_encode(len(obj_encoded))),
3864 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3865 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3868 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3870 self.assertEqual(obj_decoded.expl_offset, offset)
3871 assert_exceeding_data(
3873 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3878 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3879 base_klass = GeneralizedTime
3881 min_datetime = datetime(1900, 1, 1)
3882 max_datetime = datetime(9999, 12, 31)
3884 def additional_symmetric_check(self, value, obj_encoded):
3885 if value.microsecond > 0:
3886 self.assertFalse(obj_encoded.endswith(b"0Z"))
3888 def test_x690_vector_valid(self):
3892 b"19920722132100.3Z",
3894 GeneralizedTime(data)
3896 def test_x690_vector_invalid(self):
3899 b"19920622123421.0Z",
3900 b"19920722132100.30Z",
3902 with self.assertRaises(DecodeError) as err:
3903 GeneralizedTime(data)
3906 def test_go_vectors_invalid(self):
3918 b"-20100102030410Z",
3919 b"2010-0102030410Z",
3920 b"2010-0002030410Z",
3921 b"201001-02030410Z",
3922 b"20100102-030410Z",
3923 b"2010010203-0410Z",
3924 b"201001020304-10Z",
3925 # These ones are INVALID in *DER*, but accepted
3926 # by Go's encoding/asn1
3927 b"20100102030405+0607",
3928 b"20100102030405-0607",
3930 with self.assertRaises(DecodeError) as err:
3931 GeneralizedTime(data)
3934 def test_go_vectors_valid(self):
3936 GeneralizedTime(b"20100102030405Z").todatetime(),
3937 datetime(2010, 1, 2, 3, 4, 5, 0),
3942 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3943 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3945 binary(min_size=1, max_size=1),
3947 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3948 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3951 def test_junk(self, part0, part1, part2):
3952 junk = part0 + part1 + part2
3953 assume(not (set(junk) <= set(digits.encode("ascii"))))
3954 with self.assertRaises(DecodeError):
3955 GeneralizedTime().decode(
3956 GeneralizedTime.tag_default +
3957 len_encode(len(junk)) +
3963 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3964 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3966 binary(min_size=1, max_size=1),
3968 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3969 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3972 def test_junk_dm(self, part0, part1, part2):
3973 junk = part0 + part1 + part2
3974 assume(not (set(junk) <= set(digits.encode("ascii"))))
3975 with self.assertRaises(DecodeError):
3976 GeneralizedTime().decode(
3977 GeneralizedTime.tag_default +
3978 len_encode(len(junk)) +
3982 def test_ns_fractions(self):
3983 GeneralizedTime(b"20010101000000.000001Z")
3984 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
3985 GeneralizedTime(b"20010101000000.0000001Z")
3988 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3989 base_klass = UTCTime
3991 min_datetime = datetime(2000, 1, 1)
3992 max_datetime = datetime(2049, 12, 31)
3994 def additional_symmetric_check(self, value, obj_encoded):
3997 def test_x690_vector_valid(self):
4005 def test_x690_vector_invalid(self):
4010 with self.assertRaises(DecodeError) as err:
4014 def test_go_vectors_invalid(self):
4040 # These ones are INVALID in *DER*, but accepted
4041 # by Go's encoding/asn1
4042 b"910506164540-0700",
4043 b"910506164540+0730",
4047 with self.assertRaises(DecodeError) as err:
4051 def test_go_vectors_valid(self):
4053 UTCTime(b"910506234540Z").todatetime(),
4054 datetime(1991, 5, 6, 23, 45, 40, 0),
4057 @given(integers(min_value=0, max_value=49))
4058 def test_pre50(self, year):
4060 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4064 @given(integers(min_value=50, max_value=99))
4065 def test_post50(self, year):
4067 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4073 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4074 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4076 binary(min_size=1, max_size=1),
4078 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4079 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4082 def test_junk(self, part0, part1, part2):
4083 junk = part0 + part1 + part2
4084 assume(not (set(junk) <= set(digits.encode("ascii"))))
4085 with self.assertRaises(DecodeError):
4087 UTCTime.tag_default +
4088 len_encode(len(junk)) +
4094 def any_values_strategy(draw, do_expl=False):
4095 value = draw(one_of(none(), binary()))
4098 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4099 optional = draw(one_of(none(), booleans()))
4101 draw(integers(min_value=0)),
4102 draw(integers(min_value=0)),
4103 draw(integers(min_value=0)),
4105 return (value, expl, optional, _decoded)
4108 class AnyInherited(Any):
4112 class TestAny(CommonMixin, TestCase):
4115 def test_invalid_value_type(self):
4116 with self.assertRaises(InvalidValueType) as err:
4121 def test_optional(self, optional):
4122 obj = Any(optional=optional)
4123 self.assertEqual(obj.optional, optional)
4126 def test_ready(self, value):
4128 self.assertFalse(obj.ready)
4131 pprint(obj, big_blobs=True, with_decode_path=True)
4132 with self.assertRaises(ObjNotReady) as err:
4136 self.assertTrue(obj.ready)
4139 pprint(obj, big_blobs=True, with_decode_path=True)
4142 def test_basic(self, value):
4143 integer_encoded = Integer(value).encode()
4145 Any(integer_encoded),
4146 Any(Integer(value)),
4147 Any(Any(Integer(value))),
4149 self.assertSequenceEqual(bytes(obj), integer_encoded)
4151 obj.decode(obj.encode())[0].vlen,
4152 len(integer_encoded),
4156 pprint(obj, big_blobs=True, with_decode_path=True)
4157 self.assertSequenceEqual(obj.encode(), integer_encoded)
4159 @given(binary(), binary())
4160 def test_comparison(self, value1, value2):
4161 for klass in (Any, AnyInherited):
4162 obj1 = klass(value1)
4163 obj2 = klass(value2)
4164 self.assertEqual(obj1 == obj2, value1 == value2)
4165 self.assertEqual(obj1 != obj2, value1 != value2)
4166 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4168 @given(data_strategy())
4169 def test_call(self, d):
4170 for klass in (Any, AnyInherited):
4176 ) = d.draw(any_values_strategy())
4177 obj_initial = klass(
4180 optional_initial or False,
4188 ) = d.draw(any_values_strategy(do_expl=True))
4189 obj = obj_initial(value, expl, optional)
4191 value_expected = None if value is None else value
4192 self.assertEqual(obj, value_expected)
4193 self.assertEqual(obj.expl_tag, expl or expl_initial)
4194 if obj.default is None:
4195 optional = optional_initial if optional is None else optional
4196 optional = False if optional is None else optional
4197 self.assertEqual(obj.optional, optional)
4199 def test_simultaneous_impl_expl(self):
4200 # override it, as Any does not have implicit tag
4203 def test_decoded(self):
4204 # override it, as Any does not have implicit tag
4207 @given(any_values_strategy())
4208 def test_copy(self, values):
4209 for klass in (Any, AnyInherited):
4210 obj = klass(*values)
4211 obj_copied = obj.copy()
4212 self.assert_copied_basic_fields(obj, obj_copied)
4213 self.assertEqual(obj._value, obj_copied._value)
4215 @given(binary().map(OctetString))
4216 def test_stripped(self, value):
4218 with self.assertRaises(NotEnoughData):
4219 obj.decode(obj.encode()[:-1])
4223 integers(min_value=1).map(tag_ctxc),
4225 def test_stripped_expl(self, value, tag_expl):
4226 obj = Any(value, expl=tag_expl)
4227 with self.assertRaises(NotEnoughData):
4228 obj.decode(obj.encode()[:-1])
4231 integers(min_value=31),
4232 integers(min_value=0),
4235 def test_bad_tag(self, tag, offset, decode_path):
4236 with self.assertRaises(DecodeError) as err:
4238 tag_encode(tag)[:-1],
4240 decode_path=decode_path,
4243 self.assertEqual(err.exception.offset, offset)
4244 self.assertEqual(err.exception.decode_path, decode_path)
4247 integers(min_value=128),
4248 integers(min_value=0),
4251 def test_bad_len(self, l, offset, decode_path):
4252 with self.assertRaises(DecodeError) as err:
4254 Any.tag_default + len_encode(l)[:-1],
4256 decode_path=decode_path,
4259 self.assertEqual(err.exception.offset, offset)
4260 self.assertEqual(err.exception.decode_path, decode_path)
4262 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4264 any_values_strategy(),
4265 integers().map(lambda x: Integer(x).encode()),
4266 integers(min_value=1).map(tag_ctxc),
4267 integers(min_value=0),
4270 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4271 for klass in (Any, AnyInherited):
4272 _, _, optional, _decoded = values
4273 obj = klass(value=value, optional=optional, _decoded=_decoded)
4276 pprint(obj, big_blobs=True, with_decode_path=True)
4277 self.assertFalse(obj.expled)
4278 obj_encoded = obj.encode()
4279 obj_expled = obj(value, expl=tag_expl)
4280 self.assertTrue(obj_expled.expled)
4282 list(obj_expled.pps())
4283 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4284 obj_expled_encoded = obj_expled.encode()
4285 ctx_copied = deepcopy(ctx_dummy)
4286 obj_decoded, tail = obj_expled.decode(
4287 obj_expled_encoded + tail_junk,
4291 self.assertDictEqual(ctx_copied, ctx_dummy)
4293 list(obj_decoded.pps())
4294 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4295 self.assertEqual(tail, tail_junk)
4296 self.assertEqual(obj_decoded, obj_expled)
4297 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4298 self.assertEqual(bytes(obj_decoded), bytes(obj))
4299 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4300 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4301 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4303 obj_decoded.expl_llen,
4304 len(len_encode(len(obj_encoded))),
4306 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4307 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4310 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4312 self.assertEqual(obj_decoded.expl_offset, offset)
4313 self.assertEqual(obj_decoded.tlen, 0)
4314 self.assertEqual(obj_decoded.llen, 0)
4315 self.assertEqual(obj_decoded.vlen, len(value))
4316 assert_exceeding_data(
4318 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4323 integers(min_value=1).map(tag_ctxc),
4324 integers(min_value=0, max_value=3),
4325 integers(min_value=0),
4329 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4330 chunk = Boolean(False, expl=expl).encode()
4332 OctetString.tag_default +
4334 b"".join([chunk] * chunks) +
4337 with self.assertRaises(LenIndefForm):
4341 decode_path=decode_path,
4343 obj, tail = Any().decode(
4346 decode_path=decode_path,
4347 ctx={"bered": True},
4349 self.assertSequenceEqual(tail, junk)
4350 self.assertEqual(obj.offset, offset)
4351 self.assertEqual(obj.tlvlen, len(encoded))
4352 self.assertTrue(obj.lenindef)
4353 self.assertFalse(obj.ber_encoded)
4354 self.assertTrue(obj.bered)
4356 self.assertTrue(obj.lenindef)
4357 self.assertFalse(obj.ber_encoded)
4358 self.assertTrue(obj.bered)
4361 pprint(obj, big_blobs=True, with_decode_path=True)
4362 with self.assertRaises(NotEnoughData) as err:
4366 decode_path=decode_path,
4367 ctx={"bered": True},
4369 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4370 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4372 class SeqOf(SequenceOf):
4373 schema = Boolean(expl=expl)
4375 class Seq(Sequence):
4377 ("type", ObjectIdentifier(defines=((("value",), {
4378 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4383 ("type", ObjectIdentifier("1.2.3")),
4384 ("value", Any(encoded)),
4386 seq_encoded = seq.encode()
4387 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4388 self.assertIsNotNone(seq_decoded["value"].defined)
4390 list(seq_decoded.pps())
4391 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4392 self.assertTrue(seq_decoded.bered)
4393 self.assertFalse(seq_decoded["type"].bered)
4394 self.assertTrue(seq_decoded["value"].bered)
4396 chunk = chunk[:-1] + b"\x01"
4397 chunks = b"".join([chunk] * (chunks + 1))
4398 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4400 ("type", ObjectIdentifier("1.2.3")),
4401 ("value", Any(encoded)),
4403 seq_encoded = seq.encode()
4404 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4405 self.assertIsNotNone(seq_decoded["value"].defined)
4407 list(seq_decoded.pps())
4408 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4409 self.assertTrue(seq_decoded.bered)
4410 self.assertFalse(seq_decoded["type"].bered)
4411 self.assertTrue(seq_decoded["value"].bered)
4415 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4417 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4418 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4420 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4421 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4423 min_size=len(names),
4424 max_size=len(names),
4427 (name, Integer(**tag_kwargs))
4428 for name, tag_kwargs in zip(names, tags)
4431 if value_required or draw(booleans()):
4432 value = draw(tuples(
4433 sampled_from([name for name, _ in schema]),
4434 integers().map(Integer),
4438 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4439 default = draw(one_of(
4441 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4443 optional = draw(one_of(none(), booleans()))
4445 draw(integers(min_value=0)),
4446 draw(integers(min_value=0)),
4447 draw(integers(min_value=0)),
4449 return (schema, value, expl, default, optional, _decoded)
4452 class ChoiceInherited(Choice):
4456 class TestChoice(CommonMixin, TestCase):
4458 schema = (("whatever", Boolean()),)
4461 def test_schema_required(self):
4462 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4465 def test_impl_forbidden(self):
4466 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4467 Choice(impl=b"whatever")
4469 def test_invalid_value_type(self):
4470 with self.assertRaises(InvalidValueType) as err:
4471 self.base_klass(123)
4473 with self.assertRaises(ObjUnknown) as err:
4474 self.base_klass(("whenever", Boolean(False)))
4476 with self.assertRaises(InvalidValueType) as err:
4477 self.base_klass(("whatever", Integer(123)))
4481 def test_optional(self, optional):
4482 obj = self.base_klass(
4483 default=self.base_klass(("whatever", Boolean(False))),
4486 self.assertTrue(obj.optional)
4489 def test_ready(self, value):
4490 obj = self.base_klass()
4491 self.assertFalse(obj.ready)
4494 pprint(obj, big_blobs=True, with_decode_path=True)
4495 self.assertIsNone(obj["whatever"])
4496 with self.assertRaises(ObjNotReady) as err:
4499 obj["whatever"] = Boolean()
4500 self.assertFalse(obj.ready)
4503 pprint(obj, big_blobs=True, with_decode_path=True)
4504 obj["whatever"] = Boolean(value)
4505 self.assertTrue(obj.ready)
4508 pprint(obj, big_blobs=True, with_decode_path=True)
4510 @given(booleans(), booleans())
4511 def test_comparison(self, value1, value2):
4512 class WahlInherited(self.base_klass):
4514 for klass in (self.base_klass, WahlInherited):
4515 obj1 = klass(("whatever", Boolean(value1)))
4516 obj2 = klass(("whatever", Boolean(value2)))
4517 self.assertEqual(obj1 == obj2, value1 == value2)
4518 self.assertEqual(obj1 != obj2, value1 != value2)
4519 self.assertEqual(obj1 == obj2._value, value1 == value2)
4520 self.assertFalse(obj1 == obj2._value[1])
4522 @given(data_strategy())
4523 def test_call(self, d):
4524 for klass in (Choice, ChoiceInherited):
4532 ) = d.draw(choice_values_strategy())
4535 schema = schema_initial
4537 value=value_initial,
4539 default=default_initial,
4540 optional=optional_initial or False,
4541 _decoded=_decoded_initial,
4550 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4551 obj = obj_initial(value, expl, default, optional)
4553 value_expected = default if value is None else value
4555 default_initial if value_expected is None
4558 self.assertEqual(obj.choice, value_expected[0])
4559 self.assertEqual(obj.value, int(value_expected[1]))
4560 self.assertEqual(obj.expl_tag, expl or expl_initial)
4561 default_expect = default_initial if default is None else default
4562 if default_expect is not None:
4563 self.assertEqual(obj.default.choice, default_expect[0])
4564 self.assertEqual(obj.default.value, int(default_expect[1]))
4565 if obj.default is None:
4566 optional = optional_initial if optional is None else optional
4567 optional = False if optional is None else optional
4570 self.assertEqual(obj.optional, optional)
4571 self.assertEqual(obj.specs, obj_initial.specs)
4573 def test_simultaneous_impl_expl(self):
4574 # override it, as Any does not have implicit tag
4577 def test_decoded(self):
4578 # override it, as Any does not have implicit tag
4581 @given(choice_values_strategy())
4582 def test_copy(self, values):
4583 _schema, value, expl, default, optional, _decoded = values
4585 class Wahl(self.base_klass):
4591 optional=optional or False,
4594 obj_copied = obj.copy()
4595 self.assertIsNone(obj.tag)
4596 self.assertIsNone(obj_copied.tag)
4597 # hack for assert_copied_basic_fields
4598 obj.tag = "whatever"
4599 obj_copied.tag = "whatever"
4600 self.assert_copied_basic_fields(obj, obj_copied)
4601 self.assertEqual(obj._value, obj_copied._value)
4602 self.assertEqual(obj.specs, obj_copied.specs)
4605 def test_stripped(self, value):
4606 obj = self.base_klass(("whatever", Boolean(value)))
4607 with self.assertRaises(NotEnoughData):
4608 obj.decode(obj.encode()[:-1])
4612 integers(min_value=1).map(tag_ctxc),
4614 def test_stripped_expl(self, value, tag_expl):
4615 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4616 with self.assertRaises(NotEnoughData):
4617 obj.decode(obj.encode()[:-1])
4619 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4620 @given(data_strategy())
4621 def test_symmetric(self, d):
4622 _schema, value, _, default, optional, _decoded = d.draw(
4623 choice_values_strategy(value_required=True)
4625 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4626 offset = d.draw(integers(min_value=0))
4627 tail_junk = d.draw(binary(max_size=5))
4629 class Wahl(self.base_klass):
4639 pprint(obj, big_blobs=True, with_decode_path=True)
4640 self.assertFalse(obj.expled)
4641 obj_encoded = obj.encode()
4642 obj_expled = obj(value, expl=tag_expl)
4643 self.assertTrue(obj_expled.expled)
4645 list(obj_expled.pps())
4646 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4647 obj_expled_encoded = obj_expled.encode()
4648 ctx_copied = deepcopy(ctx_dummy)
4649 obj_decoded, tail = obj_expled.decode(
4650 obj_expled_encoded + tail_junk,
4654 self.assertDictEqual(ctx_copied, ctx_dummy)
4656 list(obj_decoded.pps())
4657 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4658 self.assertEqual(tail, tail_junk)
4659 self.assertEqual(obj_decoded, obj_expled)
4660 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4661 self.assertEqual(obj_decoded.value, obj_expled.value)
4662 self.assertEqual(obj_decoded.choice, obj.choice)
4663 self.assertEqual(obj_decoded.value, obj.value)
4664 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4665 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4666 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4668 obj_decoded.expl_llen,
4669 len(len_encode(len(obj_encoded))),
4671 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4672 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4675 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4677 self.assertEqual(obj_decoded.expl_offset, offset)
4678 self.assertSequenceEqual(
4680 obj_decoded.value.fulloffset - offset:
4681 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4685 assert_exceeding_data(
4687 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4692 def test_set_get(self, value):
4695 ("erste", Boolean()),
4696 ("zweite", Integer()),
4699 with self.assertRaises(ObjUnknown) as err:
4700 obj["whatever"] = "whenever"
4701 with self.assertRaises(InvalidValueType) as err:
4702 obj["zweite"] = Boolean(False)
4703 obj["zweite"] = Integer(value)
4705 with self.assertRaises(ObjUnknown) as err:
4708 self.assertIsNone(obj["erste"])
4709 self.assertEqual(obj["zweite"], Integer(value))
4711 def test_tag_mismatch(self):
4714 ("erste", Boolean()),
4716 int_encoded = Integer(123).encode()
4717 bool_encoded = Boolean(False).encode()
4719 obj.decode(bool_encoded)
4720 with self.assertRaises(TagMismatch):
4721 obj.decode(int_encoded)
4723 def test_tag_mismatch_underlying(self):
4724 class SeqOfBoolean(SequenceOf):
4727 class SeqOfInteger(SequenceOf):
4732 ("erste", SeqOfBoolean()),
4735 int_encoded = SeqOfInteger((Integer(123),)).encode()
4736 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4738 obj.decode(bool_encoded)
4739 with self.assertRaises(TagMismatch) as err:
4740 obj.decode(int_encoded)
4741 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4745 def seq_values_strategy(draw, seq_klass, do_expl=False):
4747 if draw(booleans()):
4749 value._value = draw(dictionaries(
4752 booleans().map(Boolean),
4753 integers().map(Integer),
4757 if draw(booleans()):
4758 schema = list(draw(dictionaries(
4761 booleans().map(Boolean),
4762 integers().map(Integer),
4768 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4770 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4772 if draw(booleans()):
4773 default = seq_klass()
4774 default._value = draw(dictionaries(
4777 booleans().map(Boolean),
4778 integers().map(Integer),
4781 optional = draw(one_of(none(), booleans()))
4783 draw(integers(min_value=0)),
4784 draw(integers(min_value=0)),
4785 draw(integers(min_value=0)),
4787 return (value, schema, impl, expl, default, optional, _decoded)
4791 def sequence_strategy(draw, seq_klass):
4792 inputs = draw(lists(
4794 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4795 tuples(just(Integer), integers(), one_of(none(), integers())),
4800 integers(min_value=1),
4801 min_size=len(inputs),
4802 max_size=len(inputs),
4805 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4806 for tag, expled in zip(tags, draw(lists(
4808 min_size=len(inputs),
4809 max_size=len(inputs),
4813 for i, optional in enumerate(draw(lists(
4814 sampled_from(("required", "optional", "empty")),
4815 min_size=len(inputs),
4816 max_size=len(inputs),
4818 if optional in ("optional", "empty"):
4819 inits[i]["optional"] = True
4820 if optional == "empty":
4822 empties = set(empties)
4823 names = list(draw(sets(
4825 min_size=len(inputs),
4826 max_size=len(inputs),
4829 for i, (klass, value, default) in enumerate(inputs):
4830 schema.append((names[i], klass(default=default, **inits[i])))
4831 seq_name = draw(text_letters())
4832 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4835 for i, (klass, value, default) in enumerate(inputs):
4842 "default_value": None if spec.default is None else default,
4846 expect["optional"] = True
4848 expect["presented"] = True
4849 expect["value"] = value
4851 expect["optional"] = True
4852 if default is not None and default == value:
4853 expect["presented"] = False
4854 seq[name] = klass(value)
4855 expects.append(expect)
4860 def sequences_strategy(draw, seq_klass):
4861 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4863 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4864 for tag, expled in zip(tags, draw(lists(
4871 i for i, is_default in enumerate(draw(lists(
4877 names = list(draw(sets(
4882 seq_expectses = draw(lists(
4883 sequence_strategy(seq_klass=seq_klass),
4887 seqs = [seq for seq, _ in seq_expectses]
4889 for i, (name, seq) in enumerate(zip(names, seqs)):
4892 seq(default=(seq if i in defaulted else None), **inits[i]),
4894 seq_name = draw(text_letters())
4895 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4898 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4901 "expects": expects_inner,
4904 seq_outer[name] = seq_inner
4905 if seq_outer.specs[name].default is None:
4906 expect["presented"] = True
4907 expect_outers.append(expect)
4908 return seq_outer, expect_outers
4911 class SeqMixing(object):
4912 def test_invalid_value_type(self):
4913 with self.assertRaises(InvalidValueType) as err:
4914 self.base_klass(123)
4917 def test_invalid_value_type_set(self):
4918 class Seq(self.base_klass):
4919 schema = (("whatever", Boolean()),)
4921 with self.assertRaises(InvalidValueType) as err:
4922 seq["whatever"] = Integer(123)
4926 def test_optional(self, optional):
4927 obj = self.base_klass(default=self.base_klass(), optional=optional)
4928 self.assertTrue(obj.optional)
4930 @given(data_strategy())
4931 def test_ready(self, d):
4933 str(i): v for i, v in enumerate(d.draw(lists(
4940 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4947 for name in d.draw(permutations(
4948 list(ready.keys()) + list(non_ready.keys()),
4950 schema_input.append((name, Boolean()))
4952 class Seq(self.base_klass):
4953 schema = tuple(schema_input)
4955 for name in ready.keys():
4957 seq[name] = Boolean()
4958 self.assertFalse(seq.ready)
4961 pprint(seq, big_blobs=True, with_decode_path=True)
4962 for name, value in ready.items():
4963 seq[name] = Boolean(value)
4964 self.assertFalse(seq.ready)
4967 pprint(seq, big_blobs=True, with_decode_path=True)
4968 with self.assertRaises(ObjNotReady) as err:
4971 for name, value in non_ready.items():
4972 seq[name] = Boolean(value)
4973 self.assertTrue(seq.ready)
4976 pprint(seq, big_blobs=True, with_decode_path=True)
4978 @given(data_strategy())
4979 def test_call(self, d):
4980 class SeqInherited(self.base_klass):
4982 for klass in (self.base_klass, SeqInherited):
4991 ) = d.draw(seq_values_strategy(seq_klass=klass))
4992 obj_initial = klass(
4998 optional_initial or False,
5009 ) = d.draw(seq_values_strategy(
5011 do_expl=impl_initial is None,
5013 obj = obj_initial(value, impl, expl, default, optional)
5014 value_expected = default if value is None else value
5016 default_initial if value_expected is None
5019 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5020 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5021 self.assertEqual(obj.expl_tag, expl or expl_initial)
5023 {} if obj.default is None else obj.default._value,
5024 getattr(default_initial if default is None else default, "_value", {}),
5026 if obj.default is None:
5027 optional = optional_initial if optional is None else optional
5028 optional = False if optional is None else optional
5031 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5032 self.assertEqual(obj.optional, optional)
5034 @given(data_strategy())
5035 def test_copy(self, d):
5036 class SeqInherited(self.base_klass):
5038 for klass in (self.base_klass, SeqInherited):
5039 values = d.draw(seq_values_strategy(seq_klass=klass))
5040 obj = klass(*values)
5041 obj_copied = obj.copy()
5042 self.assert_copied_basic_fields(obj, obj_copied)
5043 self.assertEqual(obj.specs, obj_copied.specs)
5044 self.assertEqual(obj._value, obj_copied._value)
5046 @given(data_strategy())
5047 def test_stripped(self, d):
5048 value = d.draw(integers())
5049 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5051 class Seq(self.base_klass):
5053 schema = (("whatever", Integer()),)
5055 seq["whatever"] = Integer(value)
5056 with self.assertRaises(NotEnoughData):
5057 seq.decode(seq.encode()[:-1])
5059 @given(data_strategy())
5060 def test_stripped_expl(self, d):
5061 value = d.draw(integers())
5062 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5064 class Seq(self.base_klass):
5066 schema = (("whatever", Integer()),)
5068 seq["whatever"] = Integer(value)
5069 with self.assertRaises(NotEnoughData):
5070 seq.decode(seq.encode()[:-1])
5072 @given(binary(min_size=2))
5073 def test_non_tag_mismatch_raised(self, junk):
5075 _, _, len_encoded = tag_strip(memoryview(junk))
5076 len_decode(len_encoded)
5082 class Seq(self.base_klass):
5084 ("whatever", Integer()),
5086 ("whenever", Integer()),
5089 seq["whatever"] = Integer(123)
5090 seq["junk"] = Any(junk)
5091 seq["whenever"] = Integer(123)
5092 with self.assertRaises(DecodeError):
5093 seq.decode(seq.encode())
5096 integers(min_value=31),
5097 integers(min_value=0),
5100 def test_bad_tag(self, tag, offset, decode_path):
5101 with self.assertRaises(DecodeError) as err:
5102 self.base_klass().decode(
5103 tag_encode(tag)[:-1],
5105 decode_path=decode_path,
5108 self.assertEqual(err.exception.offset, offset)
5109 self.assertEqual(err.exception.decode_path, decode_path)
5112 integers(min_value=128),
5113 integers(min_value=0),
5116 def test_bad_len(self, l, offset, decode_path):
5117 with self.assertRaises(DecodeError) as err:
5118 self.base_klass().decode(
5119 self.base_klass.tag_default + len_encode(l)[:-1],
5121 decode_path=decode_path,
5124 self.assertEqual(err.exception.offset, offset)
5125 self.assertEqual(err.exception.decode_path, decode_path)
5127 def _assert_expects(self, seq, expects):
5128 for expect in expects:
5130 seq.specs[expect["name"]].optional,
5133 if expect["default_value"] is not None:
5135 seq.specs[expect["name"]].default,
5136 expect["default_value"],
5138 if expect["presented"]:
5139 self.assertIn(expect["name"], seq)
5140 self.assertEqual(seq[expect["name"]], expect["value"])
5142 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5143 @given(data_strategy())
5144 def test_symmetric(self, d):
5145 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5146 tail_junk = d.draw(binary(max_size=5))
5147 self.assertTrue(seq.ready)
5148 self.assertFalse(seq.decoded)
5149 self._assert_expects(seq, expects)
5152 pprint(seq, big_blobs=True, with_decode_path=True)
5153 self.assertTrue(seq.ready)
5154 seq_encoded = seq.encode()
5155 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5156 self.assertFalse(seq_decoded.lenindef)
5157 self.assertFalse(seq_decoded.ber_encoded)
5158 self.assertFalse(seq_decoded.bered)
5160 t, _, lv = tag_strip(seq_encoded)
5161 _, _, v = len_decode(lv)
5162 seq_encoded_lenindef = t + LENINDEF + v + EOC
5163 ctx_copied = deepcopy(ctx_dummy)
5164 ctx_copied["bered"] = True
5165 seq_decoded_lenindef, tail_lenindef = seq.decode(
5166 seq_encoded_lenindef + tail_junk,
5169 del ctx_copied["bered"]
5170 self.assertDictEqual(ctx_copied, ctx_dummy)
5171 self.assertTrue(seq_decoded_lenindef.lenindef)
5172 self.assertTrue(seq_decoded_lenindef.bered)
5173 seq_decoded_lenindef = seq_decoded_lenindef.copy()
5174 self.assertTrue(seq_decoded_lenindef.lenindef)
5175 self.assertTrue(seq_decoded_lenindef.bered)
5176 with self.assertRaises(DecodeError):
5177 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5178 with self.assertRaises(DecodeError):
5179 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5180 repr(seq_decoded_lenindef)
5181 list(seq_decoded_lenindef.pps())
5182 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5183 self.assertTrue(seq_decoded_lenindef.ready)
5185 for decoded, decoded_tail, encoded in (
5186 (seq_decoded, tail, seq_encoded),
5187 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5189 self.assertEqual(decoded_tail, tail_junk)
5190 self._assert_expects(decoded, expects)
5191 self.assertEqual(seq, decoded)
5192 self.assertEqual(decoded.encode(), seq_encoded)
5193 self.assertEqual(decoded.tlvlen, len(encoded))
5194 for expect in expects:
5195 if not expect["presented"]:
5196 self.assertNotIn(expect["name"], decoded)
5198 self.assertIn(expect["name"], decoded)
5199 obj = decoded[expect["name"]]
5200 self.assertTrue(obj.decoded)
5201 offset = obj.expl_offset if obj.expled else obj.offset
5202 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5203 self.assertSequenceEqual(
5204 seq_encoded[offset:offset + tlvlen],
5208 assert_exceeding_data(
5210 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
5214 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5215 @given(data_strategy())
5216 def test_symmetric_with_seq(self, d):
5217 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5218 self.assertTrue(seq.ready)
5219 seq_encoded = seq.encode()
5220 seq_decoded, tail = seq.decode(seq_encoded)
5221 self.assertEqual(tail, b"")
5222 self.assertTrue(seq.ready)
5223 self.assertEqual(seq, seq_decoded)
5224 self.assertEqual(seq_decoded.encode(), seq_encoded)
5225 for expect_outer in expect_outers:
5226 if not expect_outer["presented"]:
5227 self.assertNotIn(expect_outer["name"], seq_decoded)
5229 self.assertIn(expect_outer["name"], seq_decoded)
5230 obj = seq_decoded[expect_outer["name"]]
5231 self.assertTrue(obj.decoded)
5232 offset = obj.expl_offset if obj.expled else obj.offset
5233 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5234 self.assertSequenceEqual(
5235 seq_encoded[offset:offset + tlvlen],
5238 self._assert_expects(obj, expect_outer["expects"])
5240 @given(data_strategy())
5241 def test_default_disappears(self, d):
5242 _schema = list(d.draw(dictionaries(
5244 sets(integers(), min_size=2, max_size=2),
5248 class Seq(self.base_klass):
5250 (n, Integer(default=d))
5251 for n, (_, d) in _schema
5254 for name, (value, _) in _schema:
5255 seq[name] = Integer(value)
5256 self.assertEqual(len(seq._value), len(_schema))
5257 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5258 self.assertGreater(len(seq.encode()), len(empty_seq))
5259 for name, (_, default) in _schema:
5260 seq[name] = Integer(default)
5261 self.assertEqual(len(seq._value), 0)
5262 self.assertSequenceEqual(seq.encode(), empty_seq)
5264 @given(data_strategy())
5265 def test_encoded_default_not_accepted(self, d):
5266 _schema = list(d.draw(dictionaries(
5271 tags = [tag_encode(tag) for tag in d.draw(sets(
5272 integers(min_value=0),
5273 min_size=len(_schema),
5274 max_size=len(_schema),
5277 class SeqWithoutDefault(self.base_klass):
5279 (n, Integer(impl=t))
5280 for (n, _), t in zip(_schema, tags)
5282 seq_without_default = SeqWithoutDefault()
5283 for name, value in _schema:
5284 seq_without_default[name] = Integer(value)
5285 seq_encoded = seq_without_default.encode()
5287 class SeqWithDefault(self.base_klass):
5289 (n, Integer(default=v, impl=t))
5290 for (n, v), t in zip(_schema, tags)
5292 seq_with_default = SeqWithDefault()
5293 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5294 seq_with_default.decode(seq_encoded)
5295 for ctx in ({"bered": True}, {"allow_default_values": True}):
5296 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5297 self.assertTrue(seq_decoded.ber_encoded)
5298 self.assertTrue(seq_decoded.bered)
5299 seq_decoded = seq_decoded.copy()
5300 self.assertTrue(seq_decoded.ber_encoded)
5301 self.assertTrue(seq_decoded.bered)
5302 for name, value in _schema:
5303 self.assertEqual(seq_decoded[name], seq_with_default[name])
5304 self.assertEqual(seq_decoded[name], value)
5306 @given(data_strategy())
5307 def test_missing_from_spec(self, d):
5308 names = list(d.draw(sets(text_letters(), min_size=2)))
5309 tags = [tag_encode(tag) for tag in d.draw(sets(
5310 integers(min_value=0),
5311 min_size=len(names),
5312 max_size=len(names),
5314 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5316 class SeqFull(self.base_klass):
5317 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5318 seq_full = SeqFull()
5319 for i, name in enumerate(names):
5320 seq_full[name] = Integer(i)
5321 seq_encoded = seq_full.encode()
5322 altered = names_tags[:-2] + names_tags[-1:]
5324 class SeqMissing(self.base_klass):
5325 schema = [(n, Integer(impl=t)) for n, t in altered]
5326 seq_missing = SeqMissing()
5327 with self.assertRaises(TagMismatch):
5328 seq_missing.decode(seq_encoded)
5330 def test_bered(self):
5331 class Seq(self.base_klass):
5332 schema = (("underlying", Boolean()),)
5333 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5334 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5335 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5336 self.assertFalse(decoded.ber_encoded)
5337 self.assertFalse(decoded.lenindef)
5338 self.assertTrue(decoded.bered)
5339 decoded = decoded.copy()
5340 self.assertFalse(decoded.ber_encoded)
5341 self.assertFalse(decoded.lenindef)
5342 self.assertTrue(decoded.bered)
5344 class Seq(self.base_klass):
5345 schema = (("underlying", OctetString()),)
5347 tag_encode(form=TagFormConstructed, num=4) +
5349 OctetString(b"whatever").encode() +
5352 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5353 with self.assertRaises(DecodeError):
5354 Seq().decode(encoded)
5355 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5356 self.assertFalse(decoded.ber_encoded)
5357 self.assertFalse(decoded.lenindef)
5358 self.assertTrue(decoded.bered)
5359 decoded = decoded.copy()
5360 self.assertFalse(decoded.ber_encoded)
5361 self.assertFalse(decoded.lenindef)
5362 self.assertTrue(decoded.bered)
5365 class TestSequence(SeqMixing, CommonMixin, TestCase):
5366 base_klass = Sequence
5372 def test_remaining(self, value, junk):
5373 class Seq(Sequence):
5375 ("whatever", Integer()),
5377 int_encoded = Integer(value).encode()
5379 Sequence.tag_default,
5380 len_encode(len(int_encoded + junk)),
5383 with assertRaisesRegex(self, DecodeError, "remaining"):
5384 Seq().decode(junked)
5386 @given(sets(text_letters(), min_size=2))
5387 def test_obj_unknown(self, names):
5388 missing = names.pop()
5390 class Seq(Sequence):
5391 schema = [(n, Boolean()) for n in names]
5393 with self.assertRaises(ObjUnknown) as err:
5396 with self.assertRaises(ObjUnknown) as err:
5397 seq[missing] = Boolean()
5400 def test_x690_vector(self):
5401 class Seq(Sequence):
5403 ("name", IA5String()),
5406 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5407 self.assertEqual(seq["name"], "Smith")
5408 self.assertEqual(seq["ok"], True)
5411 class TestSet(SeqMixing, CommonMixin, TestCase):
5414 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5415 @given(data_strategy())
5416 def test_sorted(self, d):
5418 tag_encode(tag) for tag in
5419 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5423 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5425 for name, _ in Seq.schema:
5426 seq[name] = OctetString(b"")
5427 seq_encoded = seq.encode()
5428 seq_decoded, _ = seq.decode(seq_encoded)
5429 self.assertSequenceEqual(
5430 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5431 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5434 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5435 @given(data_strategy())
5436 def test_unsorted(self, d):
5438 tag_encode(tag) for tag in
5439 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5441 tags = d.draw(permutations(tags))
5442 assume(tags != sorted(tags))
5443 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5444 seq_encoded = b"".join((
5446 len_encode(len(encoded)),
5451 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5453 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5454 seq.decode(seq_encoded)
5455 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5456 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5457 self.assertTrue(seq_decoded.ber_encoded)
5458 self.assertTrue(seq_decoded.bered)
5459 seq_decoded = seq_decoded.copy()
5460 self.assertTrue(seq_decoded.ber_encoded)
5461 self.assertTrue(seq_decoded.bered)
5462 self.assertSequenceEqual(
5463 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5469 def seqof_values_strategy(draw, schema=None, do_expl=False):
5471 schema = draw(sampled_from((Boolean(), Integer())))
5472 bound_min, bound_max = sorted(draw(sets(
5473 integers(min_value=0, max_value=10),
5477 if isinstance(schema, Boolean):
5478 values_generator = booleans().map(Boolean)
5479 elif isinstance(schema, Integer):
5480 values_generator = integers().map(Integer)
5481 values_generator = lists(
5486 values = draw(one_of(none(), values_generator))
5490 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5492 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5493 default = draw(one_of(none(), values_generator))
5494 optional = draw(one_of(none(), booleans()))
5496 draw(integers(min_value=0)),
5497 draw(integers(min_value=0)),
5498 draw(integers(min_value=0)),
5503 (bound_min, bound_max),
5512 class SeqOfMixing(object):
5513 def test_invalid_value_type(self):
5514 with self.assertRaises(InvalidValueType) as err:
5515 self.base_klass(123)
5518 def test_invalid_values_type(self):
5519 class SeqOf(self.base_klass):
5521 with self.assertRaises(InvalidValueType) as err:
5522 SeqOf([Integer(123), Boolean(False), Integer(234)])
5525 def test_schema_required(self):
5526 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5527 self.base_klass.__mro__[1]()
5529 @given(booleans(), booleans(), binary(), binary())
5530 def test_comparison(self, value1, value2, tag1, tag2):
5531 class SeqOf(self.base_klass):
5533 obj1 = SeqOf([Boolean(value1)])
5534 obj2 = SeqOf([Boolean(value2)])
5535 self.assertEqual(obj1 == obj2, value1 == value2)
5536 self.assertEqual(obj1 != obj2, value1 != value2)
5537 self.assertEqual(obj1 == list(obj2), value1 == value2)
5538 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5539 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5540 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5541 self.assertEqual(obj1 == obj2, tag1 == tag2)
5542 self.assertEqual(obj1 != obj2, tag1 != tag2)
5544 @given(lists(booleans()))
5545 def test_iter(self, values):
5546 class SeqOf(self.base_klass):
5548 obj = SeqOf([Boolean(value) for value in values])
5549 self.assertEqual(len(obj), len(values))
5550 for i, value in enumerate(obj):
5551 self.assertEqual(value, values[i])
5553 @given(data_strategy())
5554 def test_ready(self, d):
5555 ready = [Integer(v) for v in d.draw(lists(
5562 range(d.draw(integers(min_value=1, max_value=5)))
5565 class SeqOf(self.base_klass):
5567 values = d.draw(permutations(ready + non_ready))
5569 for value in values:
5571 self.assertFalse(seqof.ready)
5574 pprint(seqof, big_blobs=True, with_decode_path=True)
5575 with self.assertRaises(ObjNotReady) as err:
5578 for i, value in enumerate(values):
5579 self.assertEqual(seqof[i], value)
5580 if not seqof[i].ready:
5581 seqof[i] = Integer(i)
5582 self.assertTrue(seqof.ready)
5585 pprint(seqof, big_blobs=True, with_decode_path=True)
5587 def test_spec_mismatch(self):
5588 class SeqOf(self.base_klass):
5591 seqof.append(Integer(123))
5592 with self.assertRaises(ValueError):
5593 seqof.append(Boolean(False))
5594 with self.assertRaises(ValueError):
5595 seqof[0] = Boolean(False)
5597 @given(data_strategy())
5598 def test_bounds_satisfied(self, d):
5599 class SeqOf(self.base_klass):
5601 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5602 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5603 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5604 SeqOf(value=value, bounds=(bound_min, bound_max))
5606 @given(data_strategy())
5607 def test_bounds_unsatisfied(self, d):
5608 class SeqOf(self.base_klass):
5610 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5611 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5612 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5613 with self.assertRaises(BoundsError) as err:
5614 SeqOf(value=value, bounds=(bound_min, bound_max))
5616 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5617 SeqOf(bounds=(bound_min, bound_max)).decode(
5618 SeqOf(value).encode()
5621 value = [Boolean(True)] * d.draw(integers(
5622 min_value=bound_max + 1,
5623 max_value=bound_max + 10,
5625 with self.assertRaises(BoundsError) as err:
5626 SeqOf(value=value, bounds=(bound_min, bound_max))
5628 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5629 SeqOf(bounds=(bound_min, bound_max)).decode(
5630 SeqOf(value).encode()
5634 @given(integers(min_value=1, max_value=10))
5635 def test_out_of_bounds(self, bound_max):
5636 class SeqOf(self.base_klass):
5638 bounds = (0, bound_max)
5640 for _ in range(bound_max):
5641 seqof.append(Integer(123))
5642 with self.assertRaises(BoundsError):
5643 seqof.append(Integer(123))
5645 @given(data_strategy())
5646 def test_call(self, d):
5656 ) = d.draw(seqof_values_strategy())
5658 class SeqOf(self.base_klass):
5659 schema = schema_initial
5660 obj_initial = SeqOf(
5661 value=value_initial,
5662 bounds=bounds_initial,
5665 default=default_initial,
5666 optional=optional_initial or False,
5667 _decoded=_decoded_initial,
5678 ) = d.draw(seqof_values_strategy(
5679 schema=schema_initial,
5680 do_expl=impl_initial is None,
5682 if (default is None) and (obj_initial.default is not None):
5685 (bounds is None) and
5686 (value is not None) and
5687 (bounds_initial is not None) and
5688 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5692 (bounds is None) and
5693 (default is not None) and
5694 (bounds_initial is not None) and
5695 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5707 value_expected = default if value is None else value
5709 default_initial if value_expected is None
5712 value_expected = () if value_expected is None else value_expected
5713 self.assertEqual(obj, value_expected)
5714 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5715 self.assertEqual(obj.expl_tag, expl or expl_initial)
5718 default_initial if default is None else default,
5720 if obj.default is None:
5721 optional = optional_initial if optional is None else optional
5722 optional = False if optional is None else optional
5725 self.assertEqual(obj.optional, optional)
5727 (obj._bound_min, obj._bound_max),
5728 bounds or bounds_initial or (0, float("+inf")),
5731 @given(seqof_values_strategy())
5732 def test_copy(self, values):
5733 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5735 class SeqOf(self.base_klass):
5743 optional=optional or False,
5746 obj_copied = obj.copy()
5747 self.assert_copied_basic_fields(obj, obj_copied)
5748 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5749 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5750 self.assertEqual(obj._value, obj_copied._value)
5754 integers(min_value=1).map(tag_encode),
5756 def test_stripped(self, values, tag_impl):
5757 class SeqOf(self.base_klass):
5758 schema = OctetString()
5759 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5760 with self.assertRaises(NotEnoughData):
5761 obj.decode(obj.encode()[:-1])
5765 integers(min_value=1).map(tag_ctxc),
5767 def test_stripped_expl(self, values, tag_expl):
5768 class SeqOf(self.base_klass):
5769 schema = OctetString()
5770 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5771 with self.assertRaises(NotEnoughData):
5772 obj.decode(obj.encode()[:-1])
5775 integers(min_value=31),
5776 integers(min_value=0),
5779 def test_bad_tag(self, tag, offset, decode_path):
5780 with self.assertRaises(DecodeError) as err:
5781 self.base_klass().decode(
5782 tag_encode(tag)[:-1],
5784 decode_path=decode_path,
5787 self.assertEqual(err.exception.offset, offset)
5788 self.assertEqual(err.exception.decode_path, decode_path)
5791 integers(min_value=128),
5792 integers(min_value=0),
5795 def test_bad_len(self, l, offset, decode_path):
5796 with self.assertRaises(DecodeError) as err:
5797 self.base_klass().decode(
5798 self.base_klass.tag_default + len_encode(l)[:-1],
5800 decode_path=decode_path,
5803 self.assertEqual(err.exception.offset, offset)
5804 self.assertEqual(err.exception.decode_path, decode_path)
5806 @given(binary(min_size=1))
5807 def test_tag_mismatch(self, impl):
5808 assume(impl != self.base_klass.tag_default)
5809 with self.assertRaises(TagMismatch):
5810 self.base_klass(impl=impl).decode(self.base_klass().encode())
5812 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5814 seqof_values_strategy(schema=Integer()),
5815 lists(integers().map(Integer)),
5816 integers(min_value=1).map(tag_ctxc),
5817 integers(min_value=0),
5820 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5821 _, _, _, _, _, default, optional, _decoded = values
5823 class SeqOf(self.base_klass):
5833 pprint(obj, big_blobs=True, with_decode_path=True)
5834 self.assertFalse(obj.expled)
5835 obj_encoded = obj.encode()
5836 obj_expled = obj(value, expl=tag_expl)
5837 self.assertTrue(obj_expled.expled)
5839 list(obj_expled.pps())
5840 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5841 obj_expled_encoded = obj_expled.encode()
5842 ctx_copied = deepcopy(ctx_dummy)
5843 obj_decoded, tail = obj_expled.decode(
5844 obj_expled_encoded + tail_junk,
5848 self.assertDictEqual(ctx_copied, ctx_dummy)
5850 list(obj_decoded.pps())
5851 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5852 self.assertEqual(tail, tail_junk)
5853 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5854 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5855 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5856 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5858 obj_decoded.expl_llen,
5859 len(len_encode(len(obj_encoded))),
5861 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5862 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5865 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5867 self.assertEqual(obj_decoded.expl_offset, offset)
5868 for obj_inner in obj_decoded:
5869 self.assertIn(obj_inner, obj_decoded)
5870 self.assertSequenceEqual(
5873 obj_inner.offset - offset:
5874 obj_inner.offset + obj_inner.tlvlen - offset
5878 t, _, lv = tag_strip(obj_encoded)
5879 _, _, v = len_decode(lv)
5880 obj_encoded_lenindef = t + LENINDEF + v + EOC
5881 obj_decoded_lenindef, tail_lenindef = obj.decode(
5882 obj_encoded_lenindef + tail_junk,
5883 ctx={"bered": True},
5885 self.assertTrue(obj_decoded_lenindef.lenindef)
5886 self.assertTrue(obj_decoded_lenindef.bered)
5887 obj_decoded_lenindef = obj_decoded_lenindef.copy()
5888 self.assertTrue(obj_decoded_lenindef.lenindef)
5889 self.assertTrue(obj_decoded_lenindef.bered)
5890 repr(obj_decoded_lenindef)
5891 list(obj_decoded_lenindef.pps())
5892 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5893 self.assertEqual(tail_lenindef, tail_junk)
5894 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5895 with self.assertRaises(DecodeError):
5896 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5897 with self.assertRaises(DecodeError):
5898 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5900 assert_exceeding_data(
5902 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5906 def test_bered(self):
5907 class SeqOf(self.base_klass):
5909 encoded = Boolean(False).encode()
5910 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5911 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5912 with self.assertRaises(DecodeError):
5913 SeqOf().decode(encoded)
5914 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5915 self.assertFalse(decoded.ber_encoded)
5916 self.assertFalse(decoded.lenindef)
5917 self.assertTrue(decoded.bered)
5918 decoded = decoded.copy()
5919 self.assertFalse(decoded.ber_encoded)
5920 self.assertFalse(decoded.lenindef)
5921 self.assertTrue(decoded.bered)
5923 class SeqOf(self.base_klass):
5924 schema = OctetString()
5925 encoded = OctetString(b"whatever").encode()
5927 tag_encode(form=TagFormConstructed, num=4) +
5929 OctetString(b"whatever").encode() +
5932 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5933 with self.assertRaises(DecodeError):
5934 SeqOf().decode(encoded)
5935 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5936 self.assertFalse(decoded.ber_encoded)
5937 self.assertFalse(decoded.lenindef)
5938 self.assertTrue(decoded.bered)
5939 decoded = decoded.copy()
5940 self.assertFalse(decoded.ber_encoded)
5941 self.assertFalse(decoded.lenindef)
5942 self.assertTrue(decoded.bered)
5945 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5946 class SeqOf(SequenceOf):
5950 def _test_symmetric_compare_objs(self, obj1, obj2):
5951 self.assertEqual(obj1, obj2)
5952 self.assertSequenceEqual(list(obj1), list(obj2))
5955 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5960 def _test_symmetric_compare_objs(self, obj1, obj2):
5961 self.assertSetEqual(
5962 set(int(v) for v in obj1),
5963 set(int(v) for v in obj2),
5966 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5967 @given(data_strategy())
5968 def test_sorted(self, d):
5969 values = [OctetString(v) for v in d.draw(lists(binary()))]
5972 schema = OctetString()
5974 seq_encoded = seq.encode()
5975 seq_decoded, _ = seq.decode(seq_encoded)
5976 self.assertSequenceEqual(
5977 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5978 b"".join(sorted([v.encode() for v in values])),
5981 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5982 @given(data_strategy())
5983 def test_unsorted(self, d):
5984 values = [OctetString(v).encode() for v in d.draw(sets(
5985 binary(min_size=1, max_size=5),
5989 values = d.draw(permutations(values))
5990 assume(values != sorted(values))
5991 encoded = b"".join(values)
5992 seq_encoded = b"".join((
5994 len_encode(len(encoded)),
5999 schema = OctetString()
6001 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6002 seq.decode(seq_encoded)
6004 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6005 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6006 self.assertTrue(seq_decoded.ber_encoded)
6007 self.assertTrue(seq_decoded.bered)
6008 seq_decoded = seq_decoded.copy()
6009 self.assertTrue(seq_decoded.ber_encoded)
6010 self.assertTrue(seq_decoded.bered)
6011 self.assertSequenceEqual(
6012 [obj.encode() for obj in seq_decoded],
6017 class TestGoMarshalVectors(TestCase):
6019 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6020 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6021 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6022 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6023 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6025 class Seq(Sequence):
6027 ("erste", Integer()),
6028 ("zweite", Integer(optional=True))
6031 seq["erste"] = Integer(64)
6032 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6033 seq["erste"] = Integer(0x123456)
6034 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6035 seq["erste"] = Integer(64)
6036 seq["zweite"] = Integer(65)
6037 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6039 class NestedSeq(Sequence):
6043 seq["erste"] = Integer(127)
6044 seq["zweite"] = None
6045 nested = NestedSeq()
6046 nested["nest"] = seq
6047 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6049 self.assertSequenceEqual(
6050 OctetString(b"\x01\x02\x03").encode(),
6051 hexdec("0403010203"),
6054 class Seq(Sequence):
6056 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6059 seq["erste"] = Integer(64)
6060 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6062 class Seq(Sequence):
6064 ("erste", Integer(expl=tag_ctxc(5))),
6067 seq["erste"] = Integer(64)
6068 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6070 class Seq(Sequence):
6073 impl=tag_encode(0, klass=TagClassContext),
6078 seq["erste"] = Null()
6079 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6081 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6083 self.assertSequenceEqual(
6084 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6085 hexdec("170d3730303130313030303030305a"),
6087 self.assertSequenceEqual(
6088 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6089 hexdec("170d3039313131353232353631365a"),
6091 self.assertSequenceEqual(
6092 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6093 hexdec("180f32313030303430353132303130315a"),
6096 class Seq(Sequence):
6098 ("erste", GeneralizedTime()),
6101 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6102 self.assertSequenceEqual(
6104 hexdec("3011180f32303039313131353232353631365a"),
6107 self.assertSequenceEqual(
6108 BitString((1, b"\x80")).encode(),
6111 self.assertSequenceEqual(
6112 BitString((12, b"\x81\xF0")).encode(),
6113 hexdec("03030481f0"),
6116 self.assertSequenceEqual(
6117 ObjectIdentifier("1.2.3.4").encode(),
6118 hexdec("06032a0304"),
6120 self.assertSequenceEqual(
6121 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6122 hexdec("06092a864888932d010105"),
6124 self.assertSequenceEqual(
6125 ObjectIdentifier("2.100.3").encode(),
6126 hexdec("0603813403"),
6129 self.assertSequenceEqual(
6130 PrintableString("test").encode(),
6131 hexdec("130474657374"),
6133 self.assertSequenceEqual(
6134 PrintableString("x" * 127).encode(),
6135 hexdec("137F" + "78" * 127),
6137 self.assertSequenceEqual(
6138 PrintableString("x" * 128).encode(),
6139 hexdec("138180" + "78" * 128),
6141 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6143 class Seq(Sequence):
6145 ("erste", IA5String()),
6148 seq["erste"] = IA5String("test")
6149 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6151 class Seq(Sequence):
6153 ("erste", PrintableString()),
6156 seq["erste"] = PrintableString("test")
6157 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6158 # Asterisk is actually not allowable
6159 PrintableString._allowable_chars |= set(b"*")
6160 seq["erste"] = PrintableString("test*")
6161 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6162 PrintableString._allowable_chars -= set(b"*")
6164 class Seq(Sequence):
6166 ("erste", Any(optional=True)),
6167 ("zweite", Integer()),
6170 seq["zweite"] = Integer(64)
6171 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6176 seq.append(Integer(10))
6177 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6179 class _SeqOf(SequenceOf):
6180 schema = PrintableString()
6182 class SeqOf(SequenceOf):
6185 _seqof.append(PrintableString("1"))
6187 seqof.append(_seqof)
6188 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6190 class Seq(Sequence):
6192 ("erste", Integer(default=1)),
6195 seq["erste"] = Integer(0)
6196 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6197 seq["erste"] = Integer(1)
6198 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6199 seq["erste"] = Integer(2)
6200 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6203 class TestPP(TestCase):
6204 @given(data_strategy())
6205 def test_oid_printing(self, d):
6207 str(ObjectIdentifier(k)): v * 2
6208 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6210 chosen = d.draw(sampled_from(sorted(oids)))
6211 chosen_id = oids[chosen]
6212 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6213 self.assertNotIn(chosen_id, pp_console_row(pp))
6216 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6220 class TestAutoAddSlots(TestCase):
6222 class Inher(Integer):
6225 with self.assertRaises(AttributeError):
6227 inher.unexistent = "whatever"
6230 class TestOIDDefines(TestCase):
6231 @given(data_strategy())
6232 def runTest(self, d):
6233 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6234 value_name_chosen = d.draw(sampled_from(value_names))
6236 ObjectIdentifier(oid)
6237 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6239 oid_chosen = d.draw(sampled_from(oids))
6240 values = d.draw(lists(
6242 min_size=len(value_names),
6243 max_size=len(value_names),
6246 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6247 oid: Integer() for oid in oids[:-1]
6250 for i, value_name in enumerate(value_names):
6251 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6253 class Seq(Sequence):
6256 for value_name, value in zip(value_names, values):
6257 seq[value_name] = Any(Integer(value).encode())
6258 seq["type"] = oid_chosen
6259 seq, _ = Seq().decode(seq.encode())
6260 for value_name in value_names:
6261 if value_name == value_name_chosen:
6263 self.assertIsNone(seq[value_name].defined)
6264 if value_name_chosen in oids[:-1]:
6265 self.assertIsNotNone(seq[value_name_chosen].defined)
6266 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6267 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6270 pprint(seq, big_blobs=True, with_decode_path=True)
6273 class TestDefinesByPath(TestCase):
6274 def test_generated(self):
6275 class Seq(Sequence):
6277 ("type", ObjectIdentifier()),
6278 ("value", OctetString(expl=tag_ctxc(123))),
6281 class SeqInner(Sequence):
6283 ("typeInner", ObjectIdentifier()),
6284 ("valueInner", Any()),
6287 class PairValue(SetOf):
6290 class Pair(Sequence):
6292 ("type", ObjectIdentifier()),
6293 ("value", PairValue()),
6296 class Pairs(SequenceOf):
6303 type_octet_stringed,
6305 ObjectIdentifier(oid)
6306 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6308 seq_integered = Seq()
6309 seq_integered["type"] = type_integered
6310 seq_integered["value"] = OctetString(Integer(123).encode())
6311 seq_integered_raw = seq_integered.encode()
6315 (type_octet_stringed, OctetString(b"whatever")),
6316 (type_integered, Integer(123)),
6317 (type_octet_stringed, OctetString(b"whenever")),
6318 (type_integered, Integer(234)),
6320 for t, v in pairs_input:
6323 pair["value"] = PairValue((Any(v),))
6325 seq_inner = SeqInner()
6326 seq_inner["typeInner"] = type_innered
6327 seq_inner["valueInner"] = Any(pairs)
6328 seq_sequenced = Seq()
6329 seq_sequenced["type"] = type_sequenced
6330 seq_sequenced["value"] = OctetString(seq_inner.encode())
6331 seq_sequenced_raw = seq_sequenced.encode()
6333 list(seq_sequenced.pps())
6334 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6336 defines_by_path = []
6337 ctx_copied = deepcopy(ctx_dummy)
6338 seq_integered, _ = Seq().decode(
6342 self.assertDictEqual(ctx_copied, ctx_dummy)
6343 self.assertIsNone(seq_integered["value"].defined)
6344 defines_by_path.append(
6345 (("type",), ((("value",), {
6346 type_integered: Integer(),
6347 type_sequenced: SeqInner(),
6350 ctx_copied["defines_by_path"] = defines_by_path
6351 seq_integered, _ = Seq().decode(
6355 del ctx_copied["defines_by_path"]
6356 self.assertDictEqual(ctx_copied, ctx_dummy)
6357 self.assertIsNotNone(seq_integered["value"].defined)
6358 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6359 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6360 self.assertTrue(seq_integered_raw[
6361 seq_integered["value"].defined[1].offset:
6362 ].startswith(Integer(123).encode()))
6364 list(seq_integered.pps())
6365 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6367 ctx_copied["defines_by_path"] = defines_by_path
6368 seq_sequenced, _ = Seq().decode(
6372 del ctx_copied["defines_by_path"]
6373 self.assertDictEqual(ctx_copied, ctx_dummy)
6374 self.assertIsNotNone(seq_sequenced["value"].defined)
6375 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6376 seq_inner = seq_sequenced["value"].defined[1]
6377 self.assertIsNone(seq_inner["valueInner"].defined)
6379 list(seq_sequenced.pps())
6380 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6382 defines_by_path.append((
6383 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6384 ((("valueInner",), {type_innered: Pairs()}),),
6386 ctx_copied["defines_by_path"] = defines_by_path
6387 seq_sequenced, _ = Seq().decode(
6391 del ctx_copied["defines_by_path"]
6392 self.assertDictEqual(ctx_copied, ctx_dummy)
6393 self.assertIsNotNone(seq_sequenced["value"].defined)
6394 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6395 seq_inner = seq_sequenced["value"].defined[1]
6396 self.assertIsNotNone(seq_inner["valueInner"].defined)
6397 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6398 pairs = seq_inner["valueInner"].defined[1]
6400 self.assertIsNone(pair["value"][0].defined)
6402 list(seq_sequenced.pps())
6403 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6405 defines_by_path.append((
6408 DecodePathDefBy(type_sequenced),
6410 DecodePathDefBy(type_innered),
6415 type_integered: Integer(),
6416 type_octet_stringed: OctetString(),
6419 ctx_copied["defines_by_path"] = defines_by_path
6420 seq_sequenced, _ = Seq().decode(
6424 del ctx_copied["defines_by_path"]
6425 self.assertDictEqual(ctx_copied, ctx_dummy)
6426 self.assertIsNotNone(seq_sequenced["value"].defined)
6427 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6428 seq_inner = seq_sequenced["value"].defined[1]
6429 self.assertIsNotNone(seq_inner["valueInner"].defined)
6430 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6431 pairs_got = seq_inner["valueInner"].defined[1]
6432 for pair_input, pair_got in zip(pairs_input, pairs_got):
6433 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6434 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6436 list(seq_sequenced.pps())
6437 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6439 @given(oid_strategy(), integers())
6440 def test_simple(self, oid, tgt):
6441 class Inner(Sequence):
6443 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6444 ObjectIdentifier(oid): Integer(),
6448 class Outer(Sequence):
6451 ("tgt", OctetString()),
6455 inner["oid"] = ObjectIdentifier(oid)
6457 outer["inner"] = inner
6458 outer["tgt"] = OctetString(Integer(tgt).encode())
6459 decoded, _ = Outer().decode(outer.encode())
6460 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6463 class TestAbsDecodePath(TestCase):
6465 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6466 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6468 def test_concat(self, decode_path, rel_path):
6469 self.assertSequenceEqual(
6470 abs_decode_path(decode_path, rel_path),
6471 decode_path + rel_path,
6475 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6476 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6478 def test_abs(self, decode_path, rel_path):
6479 self.assertSequenceEqual(
6480 abs_decode_path(decode_path, ("/",) + rel_path),
6485 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6486 integers(min_value=1, max_value=3),
6487 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6489 def test_dots(self, decode_path, number_of_dots, rel_path):
6490 self.assertSequenceEqual(
6491 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6492 decode_path[:-number_of_dots] + rel_path,
6496 class TestStrictDefaultExistence(TestCase):
6497 @given(data_strategy())
6498 def runTest(self, d):
6499 count = d.draw(integers(min_value=1, max_value=10))
6500 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6502 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6503 for i in range(count)
6505 for klass in (Sequence, Set):
6509 for i in range(count):
6510 seq["int%d" % i] = Integer(123)
6512 chosen_choice = "int%d" % chosen
6513 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6514 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6516 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6517 self.assertTrue(decoded.ber_encoded)
6518 self.assertTrue(decoded.bered)
6519 decoded = decoded.copy()
6520 self.assertTrue(decoded.ber_encoded)
6521 self.assertTrue(decoded.bered)
6522 decoded, _ = seq.decode(raw, ctx={"bered": True})
6523 self.assertTrue(decoded.ber_encoded)
6524 self.assertTrue(decoded.bered)
6525 decoded = decoded.copy()
6526 self.assertTrue(decoded.ber_encoded)
6527 self.assertTrue(decoded.bered)
6530 class TestX690PrefixedType(TestCase):
6532 self.assertSequenceEqual(
6533 VisibleString("Jones").encode(),
6534 hexdec("1A054A6F6E6573"),
6536 self.assertSequenceEqual(
6539 impl=tag_encode(3, klass=TagClassApplication),
6541 hexdec("43054A6F6E6573"),
6543 self.assertSequenceEqual(
6547 impl=tag_encode(3, klass=TagClassApplication),
6551 hexdec("A20743054A6F6E6573"),
6553 self.assertSequenceEqual(
6557 impl=tag_encode(3, klass=TagClassApplication),
6559 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6561 hexdec("670743054A6F6E6573"),
6563 self.assertSequenceEqual(
6564 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6565 hexdec("82054A6F6E6573"),
6569 class TestExplOOB(TestCase):
6571 expl = tag_ctxc(123)
6572 raw = Integer(123).encode() + Integer(234).encode()
6573 raw = b"".join((expl, len_encode(len(raw)), raw))
6574 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6575 Integer(expl=expl).decode(raw)
6576 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})