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)
3510 class TestTeletexString(
3511 UnicodeDecodeErrorMixin,
3516 base_klass = TeletexString
3519 class TestVideotexString(
3520 UnicodeDecodeErrorMixin,
3525 base_klass = VideotexString
3528 class TestIA5String(
3529 UnicodeDecodeErrorMixin,
3534 base_klass = IA5String
3537 class TestGraphicString(
3538 UnicodeDecodeErrorMixin,
3543 base_klass = GraphicString
3546 class TestVisibleString(
3547 UnicodeDecodeErrorMixin,
3552 base_klass = VisibleString
3554 def test_x690_vector(self):
3555 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3556 self.assertSequenceEqual(tail, b"")
3557 self.assertEqual(str(obj), "Jones")
3558 self.assertFalse(obj.ber_encoded)
3559 self.assertFalse(obj.lenindef)
3560 self.assertFalse(obj.bered)
3562 obj, tail = VisibleString().decode(
3563 hexdec("3A0904034A6F6E04026573"),
3564 ctx={"bered": True},
3566 self.assertSequenceEqual(tail, b"")
3567 self.assertEqual(str(obj), "Jones")
3568 self.assertTrue(obj.ber_encoded)
3569 self.assertFalse(obj.lenindef)
3570 self.assertTrue(obj.bered)
3572 self.assertTrue(obj.ber_encoded)
3573 self.assertFalse(obj.lenindef)
3574 self.assertTrue(obj.bered)
3576 obj, tail = VisibleString().decode(
3577 hexdec("3A8004034A6F6E040265730000"),
3578 ctx={"bered": True},
3580 self.assertSequenceEqual(tail, b"")
3581 self.assertEqual(str(obj), "Jones")
3582 self.assertTrue(obj.ber_encoded)
3583 self.assertTrue(obj.lenindef)
3584 self.assertTrue(obj.bered)
3586 self.assertTrue(obj.ber_encoded)
3587 self.assertTrue(obj.lenindef)
3588 self.assertTrue(obj.bered)
3591 class TestGeneralString(
3592 UnicodeDecodeErrorMixin,
3597 base_klass = GeneralString
3600 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3601 base_klass = UniversalString
3604 class TestBMPString(StringMixin, CommonMixin, TestCase):
3605 base_klass = BMPString
3609 def generalized_time_values_strategy(
3617 if draw(booleans()):
3618 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3620 value = value.replace(microsecond=0)
3622 if draw(booleans()):
3623 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3625 default = default.replace(microsecond=0)
3629 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3631 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3632 optional = draw(one_of(none(), booleans()))
3634 draw(integers(min_value=0)),
3635 draw(integers(min_value=0)),
3636 draw(integers(min_value=0)),
3638 return (value, impl, expl, default, optional, _decoded)
3641 class TimeMixin(object):
3642 def test_invalid_value_type(self):
3643 with self.assertRaises(InvalidValueType) as err:
3644 self.base_klass(datetime.now().timetuple())
3647 @given(data_strategy())
3648 def test_optional(self, d):
3649 default = d.draw(datetimes(
3650 min_value=self.min_datetime,
3651 max_value=self.max_datetime,
3653 optional = d.draw(booleans())
3654 obj = self.base_klass(default=default, optional=optional)
3655 self.assertTrue(obj.optional)
3657 @given(data_strategy())
3658 def test_ready(self, d):
3659 obj = self.base_klass()
3660 self.assertFalse(obj.ready)
3663 pprint(obj, big_blobs=True, with_decode_path=True)
3664 with self.assertRaises(ObjNotReady) as err:
3667 value = d.draw(datetimes(min_value=self.min_datetime))
3668 obj = self.base_klass(value)
3669 self.assertTrue(obj.ready)
3672 pprint(obj, big_blobs=True, with_decode_path=True)
3674 @given(data_strategy())
3675 def test_comparison(self, d):
3676 value1 = d.draw(datetimes(
3677 min_value=self.min_datetime,
3678 max_value=self.max_datetime,
3680 value2 = d.draw(datetimes(
3681 min_value=self.min_datetime,
3682 max_value=self.max_datetime,
3684 tag1 = d.draw(binary(min_size=1))
3685 tag2 = d.draw(binary(min_size=1))
3687 value1 = value1.replace(microsecond=0)
3688 value2 = value2.replace(microsecond=0)
3689 obj1 = self.base_klass(value1)
3690 obj2 = self.base_klass(value2)
3691 self.assertEqual(obj1 == obj2, value1 == value2)
3692 self.assertEqual(obj1 != obj2, value1 != value2)
3693 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3694 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3695 obj1 = self.base_klass(value1, impl=tag1)
3696 obj2 = self.base_klass(value1, impl=tag2)
3697 self.assertEqual(obj1 == obj2, tag1 == tag2)
3698 self.assertEqual(obj1 != obj2, tag1 != tag2)
3700 @given(data_strategy())
3701 def test_call(self, d):
3709 ) = d.draw(generalized_time_values_strategy(
3710 min_datetime=self.min_datetime,
3711 max_datetime=self.max_datetime,
3712 omit_ms=self.omit_ms,
3714 obj_initial = self.base_klass(
3715 value=value_initial,
3718 default=default_initial,
3719 optional=optional_initial or False,
3720 _decoded=_decoded_initial,
3729 ) = d.draw(generalized_time_values_strategy(
3730 min_datetime=self.min_datetime,
3731 max_datetime=self.max_datetime,
3732 omit_ms=self.omit_ms,
3733 do_expl=impl_initial is None,
3743 value_expected = default if value is None else value
3745 default_initial if value_expected is None
3748 self.assertEqual(obj, value_expected)
3749 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3750 self.assertEqual(obj.expl_tag, expl or expl_initial)
3753 default_initial if default is None else default,
3755 if obj.default is None:
3756 optional = optional_initial if optional is None else optional
3757 optional = False if optional is None else optional
3760 self.assertEqual(obj.optional, optional)
3762 @given(data_strategy())
3763 def test_copy(self, d):
3764 values = d.draw(generalized_time_values_strategy(
3765 min_datetime=self.min_datetime,
3766 max_datetime=self.max_datetime,
3768 obj = self.base_klass(*values)
3769 obj_copied = obj.copy()
3770 self.assert_copied_basic_fields(obj, obj_copied)
3771 self.assertEqual(obj._value, obj_copied._value)
3773 @given(data_strategy())
3774 def test_stripped(self, d):
3775 value = d.draw(datetimes(
3776 min_value=self.min_datetime,
3777 max_value=self.max_datetime,
3779 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3780 obj = self.base_klass(value, impl=tag_impl)
3781 with self.assertRaises(NotEnoughData):
3782 obj.decode(obj.encode()[:-1])
3784 @given(data_strategy())
3785 def test_stripped_expl(self, d):
3786 value = d.draw(datetimes(
3787 min_value=self.min_datetime,
3788 max_value=self.max_datetime,
3790 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3791 obj = self.base_klass(value, expl=tag_expl)
3792 with self.assertRaises(NotEnoughData):
3793 obj.decode(obj.encode()[:-1])
3795 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3796 @given(data_strategy())
3797 def test_symmetric(self, d):
3798 values = d.draw(generalized_time_values_strategy(
3799 min_datetime=self.min_datetime,
3800 max_datetime=self.max_datetime,
3802 value = d.draw(datetimes(
3803 min_value=self.min_datetime,
3804 max_value=self.max_datetime,
3806 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3807 offset = d.draw(integers(min_value=0))
3808 tail_junk = d.draw(binary(max_size=5))
3809 _, _, _, default, optional, _decoded = values
3810 obj = self.base_klass(
3818 pprint(obj, big_blobs=True, with_decode_path=True)
3819 self.assertFalse(obj.expled)
3820 obj_encoded = obj.encode()
3821 self.additional_symmetric_check(value, obj_encoded)
3822 obj_expled = obj(value, expl=tag_expl)
3823 self.assertTrue(obj_expled.expled)
3825 list(obj_expled.pps())
3826 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3827 obj_expled_encoded = obj_expled.encode()
3828 ctx_copied = deepcopy(ctx_dummy)
3829 obj_decoded, tail = obj_expled.decode(
3830 obj_expled_encoded + tail_junk,
3834 self.assertDictEqual(ctx_copied, ctx_dummy)
3836 list(obj_decoded.pps())
3837 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3838 self.assertEqual(tail, tail_junk)
3839 self.assertEqual(obj_decoded, obj_expled)
3840 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3841 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3842 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3843 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3844 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3846 obj_decoded.expl_llen,
3847 len(len_encode(len(obj_encoded))),
3849 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3850 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3853 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3855 self.assertEqual(obj_decoded.expl_offset, offset)
3856 assert_exceeding_data(
3858 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3863 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3864 base_klass = GeneralizedTime
3866 min_datetime = datetime(1900, 1, 1)
3867 max_datetime = datetime(9999, 12, 31)
3869 def additional_symmetric_check(self, value, obj_encoded):
3870 if value.microsecond > 0:
3871 self.assertFalse(obj_encoded.endswith(b"0Z"))
3873 def test_x690_vector_valid(self):
3877 b"19920722132100.3Z",
3879 GeneralizedTime(data)
3881 def test_x690_vector_invalid(self):
3884 b"19920622123421.0Z",
3885 b"19920722132100.30Z",
3887 with self.assertRaises(DecodeError) as err:
3888 GeneralizedTime(data)
3891 def test_go_vectors_invalid(self):
3903 b"-20100102030410Z",
3904 b"2010-0102030410Z",
3905 b"2010-0002030410Z",
3906 b"201001-02030410Z",
3907 b"20100102-030410Z",
3908 b"2010010203-0410Z",
3909 b"201001020304-10Z",
3910 # These ones are INVALID in *DER*, but accepted
3911 # by Go's encoding/asn1
3912 b"20100102030405+0607",
3913 b"20100102030405-0607",
3915 with self.assertRaises(DecodeError) as err:
3916 GeneralizedTime(data)
3919 def test_go_vectors_valid(self):
3921 GeneralizedTime(b"20100102030405Z").todatetime(),
3922 datetime(2010, 1, 2, 3, 4, 5, 0),
3927 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3928 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3930 binary(min_size=1, max_size=1),
3932 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3933 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3936 def test_junk(self, part0, part1, part2):
3937 junk = part0 + part1 + part2
3938 assume(not (set(junk) <= set(digits.encode("ascii"))))
3939 with self.assertRaises(DecodeError):
3940 GeneralizedTime().decode(
3941 GeneralizedTime.tag_default +
3942 len_encode(len(junk)) +
3948 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3949 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3951 binary(min_size=1, max_size=1),
3953 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3954 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3957 def test_junk_dm(self, part0, part1, part2):
3958 junk = part0 + part1 + part2
3959 assume(not (set(junk) <= set(digits.encode("ascii"))))
3960 with self.assertRaises(DecodeError):
3961 GeneralizedTime().decode(
3962 GeneralizedTime.tag_default +
3963 len_encode(len(junk)) +
3967 def test_ns_fractions(self):
3968 GeneralizedTime(b"20010101000000.000001Z")
3969 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
3970 GeneralizedTime(b"20010101000000.0000001Z")
3973 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3974 base_klass = UTCTime
3976 min_datetime = datetime(2000, 1, 1)
3977 max_datetime = datetime(2049, 12, 31)
3979 def additional_symmetric_check(self, value, obj_encoded):
3982 def test_x690_vector_valid(self):
3990 def test_x690_vector_invalid(self):
3995 with self.assertRaises(DecodeError) as err:
3999 def test_go_vectors_invalid(self):
4025 # These ones are INVALID in *DER*, but accepted
4026 # by Go's encoding/asn1
4027 b"910506164540-0700",
4028 b"910506164540+0730",
4032 with self.assertRaises(DecodeError) as err:
4036 def test_go_vectors_valid(self):
4038 UTCTime(b"910506234540Z").todatetime(),
4039 datetime(1991, 5, 6, 23, 45, 40, 0),
4042 @given(integers(min_value=0, max_value=49))
4043 def test_pre50(self, year):
4045 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4049 @given(integers(min_value=50, max_value=99))
4050 def test_post50(self, year):
4052 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4058 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4059 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4061 binary(min_size=1, max_size=1),
4063 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4064 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4067 def test_junk(self, part0, part1, part2):
4068 junk = part0 + part1 + part2
4069 assume(not (set(junk) <= set(digits.encode("ascii"))))
4070 with self.assertRaises(DecodeError):
4072 UTCTime.tag_default +
4073 len_encode(len(junk)) +
4079 def any_values_strategy(draw, do_expl=False):
4080 value = draw(one_of(none(), binary()))
4083 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4084 optional = draw(one_of(none(), booleans()))
4086 draw(integers(min_value=0)),
4087 draw(integers(min_value=0)),
4088 draw(integers(min_value=0)),
4090 return (value, expl, optional, _decoded)
4093 class AnyInherited(Any):
4097 class TestAny(CommonMixin, TestCase):
4100 def test_invalid_value_type(self):
4101 with self.assertRaises(InvalidValueType) as err:
4106 def test_optional(self, optional):
4107 obj = Any(optional=optional)
4108 self.assertEqual(obj.optional, optional)
4111 def test_ready(self, value):
4113 self.assertFalse(obj.ready)
4116 pprint(obj, big_blobs=True, with_decode_path=True)
4117 with self.assertRaises(ObjNotReady) as err:
4121 self.assertTrue(obj.ready)
4124 pprint(obj, big_blobs=True, with_decode_path=True)
4127 def test_basic(self, value):
4128 integer_encoded = Integer(value).encode()
4130 Any(integer_encoded),
4131 Any(Integer(value)),
4132 Any(Any(Integer(value))),
4134 self.assertSequenceEqual(bytes(obj), integer_encoded)
4136 obj.decode(obj.encode())[0].vlen,
4137 len(integer_encoded),
4141 pprint(obj, big_blobs=True, with_decode_path=True)
4142 self.assertSequenceEqual(obj.encode(), integer_encoded)
4144 @given(binary(), binary())
4145 def test_comparison(self, value1, value2):
4146 for klass in (Any, AnyInherited):
4147 obj1 = klass(value1)
4148 obj2 = klass(value2)
4149 self.assertEqual(obj1 == obj2, value1 == value2)
4150 self.assertEqual(obj1 != obj2, value1 != value2)
4151 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4153 @given(data_strategy())
4154 def test_call(self, d):
4155 for klass in (Any, AnyInherited):
4161 ) = d.draw(any_values_strategy())
4162 obj_initial = klass(
4165 optional_initial or False,
4173 ) = d.draw(any_values_strategy(do_expl=True))
4174 obj = obj_initial(value, expl, optional)
4176 value_expected = None if value is None else value
4177 self.assertEqual(obj, value_expected)
4178 self.assertEqual(obj.expl_tag, expl or expl_initial)
4179 if obj.default is None:
4180 optional = optional_initial if optional is None else optional
4181 optional = False if optional is None else optional
4182 self.assertEqual(obj.optional, optional)
4184 def test_simultaneous_impl_expl(self):
4185 # override it, as Any does not have implicit tag
4188 def test_decoded(self):
4189 # override it, as Any does not have implicit tag
4192 @given(any_values_strategy())
4193 def test_copy(self, values):
4194 for klass in (Any, AnyInherited):
4195 obj = klass(*values)
4196 obj_copied = obj.copy()
4197 self.assert_copied_basic_fields(obj, obj_copied)
4198 self.assertEqual(obj._value, obj_copied._value)
4200 @given(binary().map(OctetString))
4201 def test_stripped(self, value):
4203 with self.assertRaises(NotEnoughData):
4204 obj.decode(obj.encode()[:-1])
4208 integers(min_value=1).map(tag_ctxc),
4210 def test_stripped_expl(self, value, tag_expl):
4211 obj = Any(value, expl=tag_expl)
4212 with self.assertRaises(NotEnoughData):
4213 obj.decode(obj.encode()[:-1])
4216 integers(min_value=31),
4217 integers(min_value=0),
4220 def test_bad_tag(self, tag, offset, decode_path):
4221 with self.assertRaises(DecodeError) as err:
4223 tag_encode(tag)[:-1],
4225 decode_path=decode_path,
4228 self.assertEqual(err.exception.offset, offset)
4229 self.assertEqual(err.exception.decode_path, decode_path)
4232 integers(min_value=128),
4233 integers(min_value=0),
4236 def test_bad_len(self, l, offset, decode_path):
4237 with self.assertRaises(DecodeError) as err:
4239 Any.tag_default + len_encode(l)[:-1],
4241 decode_path=decode_path,
4244 self.assertEqual(err.exception.offset, offset)
4245 self.assertEqual(err.exception.decode_path, decode_path)
4247 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4249 any_values_strategy(),
4250 integers().map(lambda x: Integer(x).encode()),
4251 integers(min_value=1).map(tag_ctxc),
4252 integers(min_value=0),
4255 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4256 for klass in (Any, AnyInherited):
4257 _, _, optional, _decoded = values
4258 obj = klass(value=value, optional=optional, _decoded=_decoded)
4261 pprint(obj, big_blobs=True, with_decode_path=True)
4262 self.assertFalse(obj.expled)
4263 obj_encoded = obj.encode()
4264 obj_expled = obj(value, expl=tag_expl)
4265 self.assertTrue(obj_expled.expled)
4267 list(obj_expled.pps())
4268 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4269 obj_expled_encoded = obj_expled.encode()
4270 ctx_copied = deepcopy(ctx_dummy)
4271 obj_decoded, tail = obj_expled.decode(
4272 obj_expled_encoded + tail_junk,
4276 self.assertDictEqual(ctx_copied, ctx_dummy)
4278 list(obj_decoded.pps())
4279 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4280 self.assertEqual(tail, tail_junk)
4281 self.assertEqual(obj_decoded, obj_expled)
4282 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4283 self.assertEqual(bytes(obj_decoded), bytes(obj))
4284 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4285 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4286 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4288 obj_decoded.expl_llen,
4289 len(len_encode(len(obj_encoded))),
4291 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4292 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4295 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4297 self.assertEqual(obj_decoded.expl_offset, offset)
4298 self.assertEqual(obj_decoded.tlen, 0)
4299 self.assertEqual(obj_decoded.llen, 0)
4300 self.assertEqual(obj_decoded.vlen, len(value))
4301 assert_exceeding_data(
4303 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4308 integers(min_value=1).map(tag_ctxc),
4309 integers(min_value=0, max_value=3),
4310 integers(min_value=0),
4314 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4315 chunk = Boolean(False, expl=expl).encode()
4317 OctetString.tag_default +
4319 b"".join([chunk] * chunks) +
4322 with self.assertRaises(LenIndefForm):
4326 decode_path=decode_path,
4328 obj, tail = Any().decode(
4331 decode_path=decode_path,
4332 ctx={"bered": True},
4334 self.assertSequenceEqual(tail, junk)
4335 self.assertEqual(obj.offset, offset)
4336 self.assertEqual(obj.tlvlen, len(encoded))
4337 self.assertTrue(obj.lenindef)
4338 self.assertFalse(obj.ber_encoded)
4339 self.assertTrue(obj.bered)
4341 self.assertTrue(obj.lenindef)
4342 self.assertFalse(obj.ber_encoded)
4343 self.assertTrue(obj.bered)
4346 pprint(obj, big_blobs=True, with_decode_path=True)
4347 with self.assertRaises(NotEnoughData) as err:
4351 decode_path=decode_path,
4352 ctx={"bered": True},
4354 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4355 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4357 class SeqOf(SequenceOf):
4358 schema = Boolean(expl=expl)
4360 class Seq(Sequence):
4362 ("type", ObjectIdentifier(defines=((("value",), {
4363 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4368 ("type", ObjectIdentifier("1.2.3")),
4369 ("value", Any(encoded)),
4371 seq_encoded = seq.encode()
4372 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4373 self.assertIsNotNone(seq_decoded["value"].defined)
4375 list(seq_decoded.pps())
4376 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4377 self.assertTrue(seq_decoded.bered)
4378 self.assertFalse(seq_decoded["type"].bered)
4379 self.assertTrue(seq_decoded["value"].bered)
4381 chunk = chunk[:-1] + b"\x01"
4382 chunks = b"".join([chunk] * (chunks + 1))
4383 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4385 ("type", ObjectIdentifier("1.2.3")),
4386 ("value", Any(encoded)),
4388 seq_encoded = seq.encode()
4389 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4390 self.assertIsNotNone(seq_decoded["value"].defined)
4392 list(seq_decoded.pps())
4393 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4394 self.assertTrue(seq_decoded.bered)
4395 self.assertFalse(seq_decoded["type"].bered)
4396 self.assertTrue(seq_decoded["value"].bered)
4400 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4402 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4403 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4405 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4406 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4408 min_size=len(names),
4409 max_size=len(names),
4412 (name, Integer(**tag_kwargs))
4413 for name, tag_kwargs in zip(names, tags)
4416 if value_required or draw(booleans()):
4417 value = draw(tuples(
4418 sampled_from([name for name, _ in schema]),
4419 integers().map(Integer),
4423 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4424 default = draw(one_of(
4426 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4428 optional = draw(one_of(none(), booleans()))
4430 draw(integers(min_value=0)),
4431 draw(integers(min_value=0)),
4432 draw(integers(min_value=0)),
4434 return (schema, value, expl, default, optional, _decoded)
4437 class ChoiceInherited(Choice):
4441 class TestChoice(CommonMixin, TestCase):
4443 schema = (("whatever", Boolean()),)
4446 def test_schema_required(self):
4447 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4450 def test_impl_forbidden(self):
4451 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4452 Choice(impl=b"whatever")
4454 def test_invalid_value_type(self):
4455 with self.assertRaises(InvalidValueType) as err:
4456 self.base_klass(123)
4458 with self.assertRaises(ObjUnknown) as err:
4459 self.base_klass(("whenever", Boolean(False)))
4461 with self.assertRaises(InvalidValueType) as err:
4462 self.base_klass(("whatever", Integer(123)))
4466 def test_optional(self, optional):
4467 obj = self.base_klass(
4468 default=self.base_klass(("whatever", Boolean(False))),
4471 self.assertTrue(obj.optional)
4474 def test_ready(self, value):
4475 obj = self.base_klass()
4476 self.assertFalse(obj.ready)
4479 pprint(obj, big_blobs=True, with_decode_path=True)
4480 self.assertIsNone(obj["whatever"])
4481 with self.assertRaises(ObjNotReady) as err:
4484 obj["whatever"] = Boolean()
4485 self.assertFalse(obj.ready)
4488 pprint(obj, big_blobs=True, with_decode_path=True)
4489 obj["whatever"] = Boolean(value)
4490 self.assertTrue(obj.ready)
4493 pprint(obj, big_blobs=True, with_decode_path=True)
4495 @given(booleans(), booleans())
4496 def test_comparison(self, value1, value2):
4497 class WahlInherited(self.base_klass):
4499 for klass in (self.base_klass, WahlInherited):
4500 obj1 = klass(("whatever", Boolean(value1)))
4501 obj2 = klass(("whatever", Boolean(value2)))
4502 self.assertEqual(obj1 == obj2, value1 == value2)
4503 self.assertEqual(obj1 != obj2, value1 != value2)
4504 self.assertEqual(obj1 == obj2._value, value1 == value2)
4505 self.assertFalse(obj1 == obj2._value[1])
4507 @given(data_strategy())
4508 def test_call(self, d):
4509 for klass in (Choice, ChoiceInherited):
4517 ) = d.draw(choice_values_strategy())
4520 schema = schema_initial
4522 value=value_initial,
4524 default=default_initial,
4525 optional=optional_initial or False,
4526 _decoded=_decoded_initial,
4535 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4536 obj = obj_initial(value, expl, default, optional)
4538 value_expected = default if value is None else value
4540 default_initial if value_expected is None
4543 self.assertEqual(obj.choice, value_expected[0])
4544 self.assertEqual(obj.value, int(value_expected[1]))
4545 self.assertEqual(obj.expl_tag, expl or expl_initial)
4546 default_expect = default_initial if default is None else default
4547 if default_expect is not None:
4548 self.assertEqual(obj.default.choice, default_expect[0])
4549 self.assertEqual(obj.default.value, int(default_expect[1]))
4550 if obj.default is None:
4551 optional = optional_initial if optional is None else optional
4552 optional = False if optional is None else optional
4555 self.assertEqual(obj.optional, optional)
4556 self.assertEqual(obj.specs, obj_initial.specs)
4558 def test_simultaneous_impl_expl(self):
4559 # override it, as Any does not have implicit tag
4562 def test_decoded(self):
4563 # override it, as Any does not have implicit tag
4566 @given(choice_values_strategy())
4567 def test_copy(self, values):
4568 _schema, value, expl, default, optional, _decoded = values
4570 class Wahl(self.base_klass):
4576 optional=optional or False,
4579 obj_copied = obj.copy()
4580 self.assertIsNone(obj.tag)
4581 self.assertIsNone(obj_copied.tag)
4582 # hack for assert_copied_basic_fields
4583 obj.tag = "whatever"
4584 obj_copied.tag = "whatever"
4585 self.assert_copied_basic_fields(obj, obj_copied)
4586 self.assertEqual(obj._value, obj_copied._value)
4587 self.assertEqual(obj.specs, obj_copied.specs)
4590 def test_stripped(self, value):
4591 obj = self.base_klass(("whatever", Boolean(value)))
4592 with self.assertRaises(NotEnoughData):
4593 obj.decode(obj.encode()[:-1])
4597 integers(min_value=1).map(tag_ctxc),
4599 def test_stripped_expl(self, value, tag_expl):
4600 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4601 with self.assertRaises(NotEnoughData):
4602 obj.decode(obj.encode()[:-1])
4604 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4605 @given(data_strategy())
4606 def test_symmetric(self, d):
4607 _schema, value, _, default, optional, _decoded = d.draw(
4608 choice_values_strategy(value_required=True)
4610 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4611 offset = d.draw(integers(min_value=0))
4612 tail_junk = d.draw(binary(max_size=5))
4614 class Wahl(self.base_klass):
4624 pprint(obj, big_blobs=True, with_decode_path=True)
4625 self.assertFalse(obj.expled)
4626 obj_encoded = obj.encode()
4627 obj_expled = obj(value, expl=tag_expl)
4628 self.assertTrue(obj_expled.expled)
4630 list(obj_expled.pps())
4631 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4632 obj_expled_encoded = obj_expled.encode()
4633 ctx_copied = deepcopy(ctx_dummy)
4634 obj_decoded, tail = obj_expled.decode(
4635 obj_expled_encoded + tail_junk,
4639 self.assertDictEqual(ctx_copied, ctx_dummy)
4641 list(obj_decoded.pps())
4642 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4643 self.assertEqual(tail, tail_junk)
4644 self.assertEqual(obj_decoded, obj_expled)
4645 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4646 self.assertEqual(obj_decoded.value, obj_expled.value)
4647 self.assertEqual(obj_decoded.choice, obj.choice)
4648 self.assertEqual(obj_decoded.value, obj.value)
4649 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4650 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4651 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4653 obj_decoded.expl_llen,
4654 len(len_encode(len(obj_encoded))),
4656 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4657 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4660 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4662 self.assertEqual(obj_decoded.expl_offset, offset)
4663 self.assertSequenceEqual(
4665 obj_decoded.value.fulloffset - offset:
4666 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4670 assert_exceeding_data(
4672 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4677 def test_set_get(self, value):
4680 ("erste", Boolean()),
4681 ("zweite", Integer()),
4684 with self.assertRaises(ObjUnknown) as err:
4685 obj["whatever"] = "whenever"
4686 with self.assertRaises(InvalidValueType) as err:
4687 obj["zweite"] = Boolean(False)
4688 obj["zweite"] = Integer(value)
4690 with self.assertRaises(ObjUnknown) as err:
4693 self.assertIsNone(obj["erste"])
4694 self.assertEqual(obj["zweite"], Integer(value))
4696 def test_tag_mismatch(self):
4699 ("erste", Boolean()),
4701 int_encoded = Integer(123).encode()
4702 bool_encoded = Boolean(False).encode()
4704 obj.decode(bool_encoded)
4705 with self.assertRaises(TagMismatch):
4706 obj.decode(int_encoded)
4708 def test_tag_mismatch_underlying(self):
4709 class SeqOfBoolean(SequenceOf):
4712 class SeqOfInteger(SequenceOf):
4717 ("erste", SeqOfBoolean()),
4720 int_encoded = SeqOfInteger((Integer(123),)).encode()
4721 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4723 obj.decode(bool_encoded)
4724 with self.assertRaises(TagMismatch) as err:
4725 obj.decode(int_encoded)
4726 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4730 def seq_values_strategy(draw, seq_klass, do_expl=False):
4732 if draw(booleans()):
4734 value._value = draw(dictionaries(
4737 booleans().map(Boolean),
4738 integers().map(Integer),
4742 if draw(booleans()):
4743 schema = list(draw(dictionaries(
4746 booleans().map(Boolean),
4747 integers().map(Integer),
4753 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4755 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4757 if draw(booleans()):
4758 default = seq_klass()
4759 default._value = draw(dictionaries(
4762 booleans().map(Boolean),
4763 integers().map(Integer),
4766 optional = draw(one_of(none(), booleans()))
4768 draw(integers(min_value=0)),
4769 draw(integers(min_value=0)),
4770 draw(integers(min_value=0)),
4772 return (value, schema, impl, expl, default, optional, _decoded)
4776 def sequence_strategy(draw, seq_klass):
4777 inputs = draw(lists(
4779 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4780 tuples(just(Integer), integers(), one_of(none(), integers())),
4785 integers(min_value=1),
4786 min_size=len(inputs),
4787 max_size=len(inputs),
4790 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4791 for tag, expled in zip(tags, draw(lists(
4793 min_size=len(inputs),
4794 max_size=len(inputs),
4798 for i, optional in enumerate(draw(lists(
4799 sampled_from(("required", "optional", "empty")),
4800 min_size=len(inputs),
4801 max_size=len(inputs),
4803 if optional in ("optional", "empty"):
4804 inits[i]["optional"] = True
4805 if optional == "empty":
4807 empties = set(empties)
4808 names = list(draw(sets(
4810 min_size=len(inputs),
4811 max_size=len(inputs),
4814 for i, (klass, value, default) in enumerate(inputs):
4815 schema.append((names[i], klass(default=default, **inits[i])))
4816 seq_name = draw(text_letters())
4817 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4820 for i, (klass, value, default) in enumerate(inputs):
4827 "default_value": None if spec.default is None else default,
4831 expect["optional"] = True
4833 expect["presented"] = True
4834 expect["value"] = value
4836 expect["optional"] = True
4837 if default is not None and default == value:
4838 expect["presented"] = False
4839 seq[name] = klass(value)
4840 expects.append(expect)
4845 def sequences_strategy(draw, seq_klass):
4846 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4848 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4849 for tag, expled in zip(tags, draw(lists(
4856 i for i, is_default in enumerate(draw(lists(
4862 names = list(draw(sets(
4867 seq_expectses = draw(lists(
4868 sequence_strategy(seq_klass=seq_klass),
4872 seqs = [seq for seq, _ in seq_expectses]
4874 for i, (name, seq) in enumerate(zip(names, seqs)):
4877 seq(default=(seq if i in defaulted else None), **inits[i]),
4879 seq_name = draw(text_letters())
4880 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4883 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4886 "expects": expects_inner,
4889 seq_outer[name] = seq_inner
4890 if seq_outer.specs[name].default is None:
4891 expect["presented"] = True
4892 expect_outers.append(expect)
4893 return seq_outer, expect_outers
4896 class SeqMixing(object):
4897 def test_invalid_value_type(self):
4898 with self.assertRaises(InvalidValueType) as err:
4899 self.base_klass(123)
4902 def test_invalid_value_type_set(self):
4903 class Seq(self.base_klass):
4904 schema = (("whatever", Boolean()),)
4906 with self.assertRaises(InvalidValueType) as err:
4907 seq["whatever"] = Integer(123)
4911 def test_optional(self, optional):
4912 obj = self.base_klass(default=self.base_klass(), optional=optional)
4913 self.assertTrue(obj.optional)
4915 @given(data_strategy())
4916 def test_ready(self, d):
4918 str(i): v for i, v in enumerate(d.draw(lists(
4925 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4932 for name in d.draw(permutations(
4933 list(ready.keys()) + list(non_ready.keys()),
4935 schema_input.append((name, Boolean()))
4937 class Seq(self.base_klass):
4938 schema = tuple(schema_input)
4940 for name in ready.keys():
4942 seq[name] = Boolean()
4943 self.assertFalse(seq.ready)
4946 pprint(seq, big_blobs=True, with_decode_path=True)
4947 for name, value in ready.items():
4948 seq[name] = Boolean(value)
4949 self.assertFalse(seq.ready)
4952 pprint(seq, big_blobs=True, with_decode_path=True)
4953 with self.assertRaises(ObjNotReady) as err:
4956 for name, value in non_ready.items():
4957 seq[name] = Boolean(value)
4958 self.assertTrue(seq.ready)
4961 pprint(seq, big_blobs=True, with_decode_path=True)
4963 @given(data_strategy())
4964 def test_call(self, d):
4965 class SeqInherited(self.base_klass):
4967 for klass in (self.base_klass, SeqInherited):
4976 ) = d.draw(seq_values_strategy(seq_klass=klass))
4977 obj_initial = klass(
4983 optional_initial or False,
4994 ) = d.draw(seq_values_strategy(
4996 do_expl=impl_initial is None,
4998 obj = obj_initial(value, impl, expl, default, optional)
4999 value_expected = default if value is None else value
5001 default_initial if value_expected is None
5004 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5005 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5006 self.assertEqual(obj.expl_tag, expl or expl_initial)
5008 {} if obj.default is None else obj.default._value,
5009 getattr(default_initial if default is None else default, "_value", {}),
5011 if obj.default is None:
5012 optional = optional_initial if optional is None else optional
5013 optional = False if optional is None else optional
5016 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5017 self.assertEqual(obj.optional, optional)
5019 @given(data_strategy())
5020 def test_copy(self, d):
5021 class SeqInherited(self.base_klass):
5023 for klass in (self.base_klass, SeqInherited):
5024 values = d.draw(seq_values_strategy(seq_klass=klass))
5025 obj = klass(*values)
5026 obj_copied = obj.copy()
5027 self.assert_copied_basic_fields(obj, obj_copied)
5028 self.assertEqual(obj.specs, obj_copied.specs)
5029 self.assertEqual(obj._value, obj_copied._value)
5031 @given(data_strategy())
5032 def test_stripped(self, d):
5033 value = d.draw(integers())
5034 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5036 class Seq(self.base_klass):
5038 schema = (("whatever", Integer()),)
5040 seq["whatever"] = Integer(value)
5041 with self.assertRaises(NotEnoughData):
5042 seq.decode(seq.encode()[:-1])
5044 @given(data_strategy())
5045 def test_stripped_expl(self, d):
5046 value = d.draw(integers())
5047 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5049 class Seq(self.base_klass):
5051 schema = (("whatever", Integer()),)
5053 seq["whatever"] = Integer(value)
5054 with self.assertRaises(NotEnoughData):
5055 seq.decode(seq.encode()[:-1])
5057 @given(binary(min_size=2))
5058 def test_non_tag_mismatch_raised(self, junk):
5060 _, _, len_encoded = tag_strip(memoryview(junk))
5061 len_decode(len_encoded)
5067 class Seq(self.base_klass):
5069 ("whatever", Integer()),
5071 ("whenever", Integer()),
5074 seq["whatever"] = Integer(123)
5075 seq["junk"] = Any(junk)
5076 seq["whenever"] = Integer(123)
5077 with self.assertRaises(DecodeError):
5078 seq.decode(seq.encode())
5081 integers(min_value=31),
5082 integers(min_value=0),
5085 def test_bad_tag(self, tag, offset, decode_path):
5086 with self.assertRaises(DecodeError) as err:
5087 self.base_klass().decode(
5088 tag_encode(tag)[:-1],
5090 decode_path=decode_path,
5093 self.assertEqual(err.exception.offset, offset)
5094 self.assertEqual(err.exception.decode_path, decode_path)
5097 integers(min_value=128),
5098 integers(min_value=0),
5101 def test_bad_len(self, l, offset, decode_path):
5102 with self.assertRaises(DecodeError) as err:
5103 self.base_klass().decode(
5104 self.base_klass.tag_default + len_encode(l)[:-1],
5106 decode_path=decode_path,
5109 self.assertEqual(err.exception.offset, offset)
5110 self.assertEqual(err.exception.decode_path, decode_path)
5112 def _assert_expects(self, seq, expects):
5113 for expect in expects:
5115 seq.specs[expect["name"]].optional,
5118 if expect["default_value"] is not None:
5120 seq.specs[expect["name"]].default,
5121 expect["default_value"],
5123 if expect["presented"]:
5124 self.assertIn(expect["name"], seq)
5125 self.assertEqual(seq[expect["name"]], expect["value"])
5127 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5128 @given(data_strategy())
5129 def test_symmetric(self, d):
5130 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5131 tail_junk = d.draw(binary(max_size=5))
5132 self.assertTrue(seq.ready)
5133 self.assertFalse(seq.decoded)
5134 self._assert_expects(seq, expects)
5137 pprint(seq, big_blobs=True, with_decode_path=True)
5138 self.assertTrue(seq.ready)
5139 seq_encoded = seq.encode()
5140 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5141 self.assertFalse(seq_decoded.lenindef)
5142 self.assertFalse(seq_decoded.ber_encoded)
5143 self.assertFalse(seq_decoded.bered)
5145 t, _, lv = tag_strip(seq_encoded)
5146 _, _, v = len_decode(lv)
5147 seq_encoded_lenindef = t + LENINDEF + v + EOC
5148 ctx_copied = deepcopy(ctx_dummy)
5149 ctx_copied["bered"] = True
5150 seq_decoded_lenindef, tail_lenindef = seq.decode(
5151 seq_encoded_lenindef + tail_junk,
5154 del ctx_copied["bered"]
5155 self.assertDictEqual(ctx_copied, ctx_dummy)
5156 self.assertTrue(seq_decoded_lenindef.lenindef)
5157 self.assertTrue(seq_decoded_lenindef.bered)
5158 seq_decoded_lenindef = seq_decoded_lenindef.copy()
5159 self.assertTrue(seq_decoded_lenindef.lenindef)
5160 self.assertTrue(seq_decoded_lenindef.bered)
5161 with self.assertRaises(DecodeError):
5162 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5163 with self.assertRaises(DecodeError):
5164 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5165 repr(seq_decoded_lenindef)
5166 list(seq_decoded_lenindef.pps())
5167 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5168 self.assertTrue(seq_decoded_lenindef.ready)
5170 for decoded, decoded_tail, encoded in (
5171 (seq_decoded, tail, seq_encoded),
5172 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5174 self.assertEqual(decoded_tail, tail_junk)
5175 self._assert_expects(decoded, expects)
5176 self.assertEqual(seq, decoded)
5177 self.assertEqual(decoded.encode(), seq_encoded)
5178 self.assertEqual(decoded.tlvlen, len(encoded))
5179 for expect in expects:
5180 if not expect["presented"]:
5181 self.assertNotIn(expect["name"], decoded)
5183 self.assertIn(expect["name"], decoded)
5184 obj = decoded[expect["name"]]
5185 self.assertTrue(obj.decoded)
5186 offset = obj.expl_offset if obj.expled else obj.offset
5187 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5188 self.assertSequenceEqual(
5189 seq_encoded[offset:offset + tlvlen],
5193 assert_exceeding_data(
5195 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
5199 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5200 @given(data_strategy())
5201 def test_symmetric_with_seq(self, d):
5202 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5203 self.assertTrue(seq.ready)
5204 seq_encoded = seq.encode()
5205 seq_decoded, tail = seq.decode(seq_encoded)
5206 self.assertEqual(tail, b"")
5207 self.assertTrue(seq.ready)
5208 self.assertEqual(seq, seq_decoded)
5209 self.assertEqual(seq_decoded.encode(), seq_encoded)
5210 for expect_outer in expect_outers:
5211 if not expect_outer["presented"]:
5212 self.assertNotIn(expect_outer["name"], seq_decoded)
5214 self.assertIn(expect_outer["name"], seq_decoded)
5215 obj = seq_decoded[expect_outer["name"]]
5216 self.assertTrue(obj.decoded)
5217 offset = obj.expl_offset if obj.expled else obj.offset
5218 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5219 self.assertSequenceEqual(
5220 seq_encoded[offset:offset + tlvlen],
5223 self._assert_expects(obj, expect_outer["expects"])
5225 @given(data_strategy())
5226 def test_default_disappears(self, d):
5227 _schema = list(d.draw(dictionaries(
5229 sets(integers(), min_size=2, max_size=2),
5233 class Seq(self.base_klass):
5235 (n, Integer(default=d))
5236 for n, (_, d) in _schema
5239 for name, (value, _) in _schema:
5240 seq[name] = Integer(value)
5241 self.assertEqual(len(seq._value), len(_schema))
5242 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5243 self.assertGreater(len(seq.encode()), len(empty_seq))
5244 for name, (_, default) in _schema:
5245 seq[name] = Integer(default)
5246 self.assertEqual(len(seq._value), 0)
5247 self.assertSequenceEqual(seq.encode(), empty_seq)
5249 @given(data_strategy())
5250 def test_encoded_default_not_accepted(self, d):
5251 _schema = list(d.draw(dictionaries(
5256 tags = [tag_encode(tag) for tag in d.draw(sets(
5257 integers(min_value=0),
5258 min_size=len(_schema),
5259 max_size=len(_schema),
5262 class SeqWithoutDefault(self.base_klass):
5264 (n, Integer(impl=t))
5265 for (n, _), t in zip(_schema, tags)
5267 seq_without_default = SeqWithoutDefault()
5268 for name, value in _schema:
5269 seq_without_default[name] = Integer(value)
5270 seq_encoded = seq_without_default.encode()
5272 class SeqWithDefault(self.base_klass):
5274 (n, Integer(default=v, impl=t))
5275 for (n, v), t in zip(_schema, tags)
5277 seq_with_default = SeqWithDefault()
5278 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5279 seq_with_default.decode(seq_encoded)
5280 for ctx in ({"bered": True}, {"allow_default_values": True}):
5281 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5282 self.assertTrue(seq_decoded.ber_encoded)
5283 self.assertTrue(seq_decoded.bered)
5284 seq_decoded = seq_decoded.copy()
5285 self.assertTrue(seq_decoded.ber_encoded)
5286 self.assertTrue(seq_decoded.bered)
5287 for name, value in _schema:
5288 self.assertEqual(seq_decoded[name], seq_with_default[name])
5289 self.assertEqual(seq_decoded[name], value)
5291 @given(data_strategy())
5292 def test_missing_from_spec(self, d):
5293 names = list(d.draw(sets(text_letters(), min_size=2)))
5294 tags = [tag_encode(tag) for tag in d.draw(sets(
5295 integers(min_value=0),
5296 min_size=len(names),
5297 max_size=len(names),
5299 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5301 class SeqFull(self.base_klass):
5302 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5303 seq_full = SeqFull()
5304 for i, name in enumerate(names):
5305 seq_full[name] = Integer(i)
5306 seq_encoded = seq_full.encode()
5307 altered = names_tags[:-2] + names_tags[-1:]
5309 class SeqMissing(self.base_klass):
5310 schema = [(n, Integer(impl=t)) for n, t in altered]
5311 seq_missing = SeqMissing()
5312 with self.assertRaises(TagMismatch):
5313 seq_missing.decode(seq_encoded)
5315 def test_bered(self):
5316 class Seq(self.base_klass):
5317 schema = (("underlying", Boolean()),)
5318 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5319 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5320 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5321 self.assertFalse(decoded.ber_encoded)
5322 self.assertFalse(decoded.lenindef)
5323 self.assertTrue(decoded.bered)
5324 decoded = decoded.copy()
5325 self.assertFalse(decoded.ber_encoded)
5326 self.assertFalse(decoded.lenindef)
5327 self.assertTrue(decoded.bered)
5329 class Seq(self.base_klass):
5330 schema = (("underlying", OctetString()),)
5332 tag_encode(form=TagFormConstructed, num=4) +
5334 OctetString(b"whatever").encode() +
5337 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5338 with self.assertRaises(DecodeError):
5339 Seq().decode(encoded)
5340 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5341 self.assertFalse(decoded.ber_encoded)
5342 self.assertFalse(decoded.lenindef)
5343 self.assertTrue(decoded.bered)
5344 decoded = decoded.copy()
5345 self.assertFalse(decoded.ber_encoded)
5346 self.assertFalse(decoded.lenindef)
5347 self.assertTrue(decoded.bered)
5350 class TestSequence(SeqMixing, CommonMixin, TestCase):
5351 base_klass = Sequence
5357 def test_remaining(self, value, junk):
5358 class Seq(Sequence):
5360 ("whatever", Integer()),
5362 int_encoded = Integer(value).encode()
5364 Sequence.tag_default,
5365 len_encode(len(int_encoded + junk)),
5368 with assertRaisesRegex(self, DecodeError, "remaining"):
5369 Seq().decode(junked)
5371 @given(sets(text_letters(), min_size=2))
5372 def test_obj_unknown(self, names):
5373 missing = names.pop()
5375 class Seq(Sequence):
5376 schema = [(n, Boolean()) for n in names]
5378 with self.assertRaises(ObjUnknown) as err:
5381 with self.assertRaises(ObjUnknown) as err:
5382 seq[missing] = Boolean()
5385 def test_x690_vector(self):
5386 class Seq(Sequence):
5388 ("name", IA5String()),
5391 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5392 self.assertEqual(seq["name"], "Smith")
5393 self.assertEqual(seq["ok"], True)
5396 class TestSet(SeqMixing, CommonMixin, TestCase):
5399 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5400 @given(data_strategy())
5401 def test_sorted(self, d):
5403 tag_encode(tag) for tag in
5404 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5408 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5410 for name, _ in Seq.schema:
5411 seq[name] = OctetString(b"")
5412 seq_encoded = seq.encode()
5413 seq_decoded, _ = seq.decode(seq_encoded)
5414 self.assertSequenceEqual(
5415 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5416 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5419 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5420 @given(data_strategy())
5421 def test_unsorted(self, d):
5423 tag_encode(tag) for tag in
5424 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5426 tags = d.draw(permutations(tags))
5427 assume(tags != sorted(tags))
5428 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5429 seq_encoded = b"".join((
5431 len_encode(len(encoded)),
5436 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5438 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5439 seq.decode(seq_encoded)
5440 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5441 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5442 self.assertTrue(seq_decoded.ber_encoded)
5443 self.assertTrue(seq_decoded.bered)
5444 seq_decoded = seq_decoded.copy()
5445 self.assertTrue(seq_decoded.ber_encoded)
5446 self.assertTrue(seq_decoded.bered)
5447 self.assertSequenceEqual(
5448 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5454 def seqof_values_strategy(draw, schema=None, do_expl=False):
5456 schema = draw(sampled_from((Boolean(), Integer())))
5457 bound_min, bound_max = sorted(draw(sets(
5458 integers(min_value=0, max_value=10),
5462 if isinstance(schema, Boolean):
5463 values_generator = booleans().map(Boolean)
5464 elif isinstance(schema, Integer):
5465 values_generator = integers().map(Integer)
5466 values_generator = lists(
5471 values = draw(one_of(none(), values_generator))
5475 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5477 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5478 default = draw(one_of(none(), values_generator))
5479 optional = draw(one_of(none(), booleans()))
5481 draw(integers(min_value=0)),
5482 draw(integers(min_value=0)),
5483 draw(integers(min_value=0)),
5488 (bound_min, bound_max),
5497 class SeqOfMixing(object):
5498 def test_invalid_value_type(self):
5499 with self.assertRaises(InvalidValueType) as err:
5500 self.base_klass(123)
5503 def test_invalid_values_type(self):
5504 class SeqOf(self.base_klass):
5506 with self.assertRaises(InvalidValueType) as err:
5507 SeqOf([Integer(123), Boolean(False), Integer(234)])
5510 def test_schema_required(self):
5511 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5512 self.base_klass.__mro__[1]()
5514 @given(booleans(), booleans(), binary(), binary())
5515 def test_comparison(self, value1, value2, tag1, tag2):
5516 class SeqOf(self.base_klass):
5518 obj1 = SeqOf([Boolean(value1)])
5519 obj2 = SeqOf([Boolean(value2)])
5520 self.assertEqual(obj1 == obj2, value1 == value2)
5521 self.assertEqual(obj1 != obj2, value1 != value2)
5522 self.assertEqual(obj1 == list(obj2), value1 == value2)
5523 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5524 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5525 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5526 self.assertEqual(obj1 == obj2, tag1 == tag2)
5527 self.assertEqual(obj1 != obj2, tag1 != tag2)
5529 @given(lists(booleans()))
5530 def test_iter(self, values):
5531 class SeqOf(self.base_klass):
5533 obj = SeqOf([Boolean(value) for value in values])
5534 self.assertEqual(len(obj), len(values))
5535 for i, value in enumerate(obj):
5536 self.assertEqual(value, values[i])
5538 @given(data_strategy())
5539 def test_ready(self, d):
5540 ready = [Integer(v) for v in d.draw(lists(
5547 range(d.draw(integers(min_value=1, max_value=5)))
5550 class SeqOf(self.base_klass):
5552 values = d.draw(permutations(ready + non_ready))
5554 for value in values:
5556 self.assertFalse(seqof.ready)
5559 pprint(seqof, big_blobs=True, with_decode_path=True)
5560 with self.assertRaises(ObjNotReady) as err:
5563 for i, value in enumerate(values):
5564 self.assertEqual(seqof[i], value)
5565 if not seqof[i].ready:
5566 seqof[i] = Integer(i)
5567 self.assertTrue(seqof.ready)
5570 pprint(seqof, big_blobs=True, with_decode_path=True)
5572 def test_spec_mismatch(self):
5573 class SeqOf(self.base_klass):
5576 seqof.append(Integer(123))
5577 with self.assertRaises(ValueError):
5578 seqof.append(Boolean(False))
5579 with self.assertRaises(ValueError):
5580 seqof[0] = Boolean(False)
5582 @given(data_strategy())
5583 def test_bounds_satisfied(self, d):
5584 class SeqOf(self.base_klass):
5586 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5587 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5588 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5589 SeqOf(value=value, bounds=(bound_min, bound_max))
5591 @given(data_strategy())
5592 def test_bounds_unsatisfied(self, d):
5593 class SeqOf(self.base_klass):
5595 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5596 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5597 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5598 with self.assertRaises(BoundsError) as err:
5599 SeqOf(value=value, bounds=(bound_min, bound_max))
5601 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5602 SeqOf(bounds=(bound_min, bound_max)).decode(
5603 SeqOf(value).encode()
5606 value = [Boolean(True)] * d.draw(integers(
5607 min_value=bound_max + 1,
5608 max_value=bound_max + 10,
5610 with self.assertRaises(BoundsError) as err:
5611 SeqOf(value=value, bounds=(bound_min, bound_max))
5613 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5614 SeqOf(bounds=(bound_min, bound_max)).decode(
5615 SeqOf(value).encode()
5619 @given(integers(min_value=1, max_value=10))
5620 def test_out_of_bounds(self, bound_max):
5621 class SeqOf(self.base_klass):
5623 bounds = (0, bound_max)
5625 for _ in range(bound_max):
5626 seqof.append(Integer(123))
5627 with self.assertRaises(BoundsError):
5628 seqof.append(Integer(123))
5630 @given(data_strategy())
5631 def test_call(self, d):
5641 ) = d.draw(seqof_values_strategy())
5643 class SeqOf(self.base_klass):
5644 schema = schema_initial
5645 obj_initial = SeqOf(
5646 value=value_initial,
5647 bounds=bounds_initial,
5650 default=default_initial,
5651 optional=optional_initial or False,
5652 _decoded=_decoded_initial,
5663 ) = d.draw(seqof_values_strategy(
5664 schema=schema_initial,
5665 do_expl=impl_initial is None,
5667 if (default is None) and (obj_initial.default is not None):
5670 (bounds is None) and
5671 (value is not None) and
5672 (bounds_initial is not None) and
5673 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5677 (bounds is None) and
5678 (default is not None) and
5679 (bounds_initial is not None) and
5680 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5692 value_expected = default if value is None else value
5694 default_initial if value_expected is None
5697 value_expected = () if value_expected is None else value_expected
5698 self.assertEqual(obj, value_expected)
5699 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5700 self.assertEqual(obj.expl_tag, expl or expl_initial)
5703 default_initial if default is None else default,
5705 if obj.default is None:
5706 optional = optional_initial if optional is None else optional
5707 optional = False if optional is None else optional
5710 self.assertEqual(obj.optional, optional)
5712 (obj._bound_min, obj._bound_max),
5713 bounds or bounds_initial or (0, float("+inf")),
5716 @given(seqof_values_strategy())
5717 def test_copy(self, values):
5718 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5720 class SeqOf(self.base_klass):
5728 optional=optional or False,
5731 obj_copied = obj.copy()
5732 self.assert_copied_basic_fields(obj, obj_copied)
5733 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5734 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5735 self.assertEqual(obj._value, obj_copied._value)
5739 integers(min_value=1).map(tag_encode),
5741 def test_stripped(self, values, tag_impl):
5742 class SeqOf(self.base_klass):
5743 schema = OctetString()
5744 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5745 with self.assertRaises(NotEnoughData):
5746 obj.decode(obj.encode()[:-1])
5750 integers(min_value=1).map(tag_ctxc),
5752 def test_stripped_expl(self, values, tag_expl):
5753 class SeqOf(self.base_klass):
5754 schema = OctetString()
5755 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5756 with self.assertRaises(NotEnoughData):
5757 obj.decode(obj.encode()[:-1])
5760 integers(min_value=31),
5761 integers(min_value=0),
5764 def test_bad_tag(self, tag, offset, decode_path):
5765 with self.assertRaises(DecodeError) as err:
5766 self.base_klass().decode(
5767 tag_encode(tag)[:-1],
5769 decode_path=decode_path,
5772 self.assertEqual(err.exception.offset, offset)
5773 self.assertEqual(err.exception.decode_path, decode_path)
5776 integers(min_value=128),
5777 integers(min_value=0),
5780 def test_bad_len(self, l, offset, decode_path):
5781 with self.assertRaises(DecodeError) as err:
5782 self.base_klass().decode(
5783 self.base_klass.tag_default + len_encode(l)[:-1],
5785 decode_path=decode_path,
5788 self.assertEqual(err.exception.offset, offset)
5789 self.assertEqual(err.exception.decode_path, decode_path)
5791 @given(binary(min_size=1))
5792 def test_tag_mismatch(self, impl):
5793 assume(impl != self.base_klass.tag_default)
5794 with self.assertRaises(TagMismatch):
5795 self.base_klass(impl=impl).decode(self.base_klass().encode())
5797 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5799 seqof_values_strategy(schema=Integer()),
5800 lists(integers().map(Integer)),
5801 integers(min_value=1).map(tag_ctxc),
5802 integers(min_value=0),
5805 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5806 _, _, _, _, _, default, optional, _decoded = values
5808 class SeqOf(self.base_klass):
5818 pprint(obj, big_blobs=True, with_decode_path=True)
5819 self.assertFalse(obj.expled)
5820 obj_encoded = obj.encode()
5821 obj_expled = obj(value, expl=tag_expl)
5822 self.assertTrue(obj_expled.expled)
5824 list(obj_expled.pps())
5825 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5826 obj_expled_encoded = obj_expled.encode()
5827 ctx_copied = deepcopy(ctx_dummy)
5828 obj_decoded, tail = obj_expled.decode(
5829 obj_expled_encoded + tail_junk,
5833 self.assertDictEqual(ctx_copied, ctx_dummy)
5835 list(obj_decoded.pps())
5836 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5837 self.assertEqual(tail, tail_junk)
5838 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5839 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5840 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5841 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5843 obj_decoded.expl_llen,
5844 len(len_encode(len(obj_encoded))),
5846 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5847 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5850 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5852 self.assertEqual(obj_decoded.expl_offset, offset)
5853 for obj_inner in obj_decoded:
5854 self.assertIn(obj_inner, obj_decoded)
5855 self.assertSequenceEqual(
5858 obj_inner.offset - offset:
5859 obj_inner.offset + obj_inner.tlvlen - offset
5863 t, _, lv = tag_strip(obj_encoded)
5864 _, _, v = len_decode(lv)
5865 obj_encoded_lenindef = t + LENINDEF + v + EOC
5866 obj_decoded_lenindef, tail_lenindef = obj.decode(
5867 obj_encoded_lenindef + tail_junk,
5868 ctx={"bered": True},
5870 self.assertTrue(obj_decoded_lenindef.lenindef)
5871 self.assertTrue(obj_decoded_lenindef.bered)
5872 obj_decoded_lenindef = obj_decoded_lenindef.copy()
5873 self.assertTrue(obj_decoded_lenindef.lenindef)
5874 self.assertTrue(obj_decoded_lenindef.bered)
5875 repr(obj_decoded_lenindef)
5876 list(obj_decoded_lenindef.pps())
5877 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5878 self.assertEqual(tail_lenindef, tail_junk)
5879 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5880 with self.assertRaises(DecodeError):
5881 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5882 with self.assertRaises(DecodeError):
5883 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5885 assert_exceeding_data(
5887 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5891 def test_bered(self):
5892 class SeqOf(self.base_klass):
5894 encoded = Boolean(False).encode()
5895 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5896 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5897 with self.assertRaises(DecodeError):
5898 SeqOf().decode(encoded)
5899 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5900 self.assertFalse(decoded.ber_encoded)
5901 self.assertFalse(decoded.lenindef)
5902 self.assertTrue(decoded.bered)
5903 decoded = decoded.copy()
5904 self.assertFalse(decoded.ber_encoded)
5905 self.assertFalse(decoded.lenindef)
5906 self.assertTrue(decoded.bered)
5908 class SeqOf(self.base_klass):
5909 schema = OctetString()
5910 encoded = OctetString(b"whatever").encode()
5912 tag_encode(form=TagFormConstructed, num=4) +
5914 OctetString(b"whatever").encode() +
5917 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5918 with self.assertRaises(DecodeError):
5919 SeqOf().decode(encoded)
5920 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5921 self.assertFalse(decoded.ber_encoded)
5922 self.assertFalse(decoded.lenindef)
5923 self.assertTrue(decoded.bered)
5924 decoded = decoded.copy()
5925 self.assertFalse(decoded.ber_encoded)
5926 self.assertFalse(decoded.lenindef)
5927 self.assertTrue(decoded.bered)
5930 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5931 class SeqOf(SequenceOf):
5935 def _test_symmetric_compare_objs(self, obj1, obj2):
5936 self.assertEqual(obj1, obj2)
5937 self.assertSequenceEqual(list(obj1), list(obj2))
5940 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5945 def _test_symmetric_compare_objs(self, obj1, obj2):
5946 self.assertSetEqual(
5947 set(int(v) for v in obj1),
5948 set(int(v) for v in obj2),
5951 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5952 @given(data_strategy())
5953 def test_sorted(self, d):
5954 values = [OctetString(v) for v in d.draw(lists(binary()))]
5957 schema = OctetString()
5959 seq_encoded = seq.encode()
5960 seq_decoded, _ = seq.decode(seq_encoded)
5961 self.assertSequenceEqual(
5962 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5963 b"".join(sorted([v.encode() for v in values])),
5966 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5967 @given(data_strategy())
5968 def test_unsorted(self, d):
5969 values = [OctetString(v).encode() for v in d.draw(sets(
5970 binary(min_size=1, max_size=5),
5974 values = d.draw(permutations(values))
5975 assume(values != sorted(values))
5976 encoded = b"".join(values)
5977 seq_encoded = b"".join((
5979 len_encode(len(encoded)),
5984 schema = OctetString()
5986 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5987 seq.decode(seq_encoded)
5989 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5990 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5991 self.assertTrue(seq_decoded.ber_encoded)
5992 self.assertTrue(seq_decoded.bered)
5993 seq_decoded = seq_decoded.copy()
5994 self.assertTrue(seq_decoded.ber_encoded)
5995 self.assertTrue(seq_decoded.bered)
5996 self.assertSequenceEqual(
5997 [obj.encode() for obj in seq_decoded],
6002 class TestGoMarshalVectors(TestCase):
6004 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6005 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6006 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6007 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6008 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6010 class Seq(Sequence):
6012 ("erste", Integer()),
6013 ("zweite", Integer(optional=True))
6016 seq["erste"] = Integer(64)
6017 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6018 seq["erste"] = Integer(0x123456)
6019 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6020 seq["erste"] = Integer(64)
6021 seq["zweite"] = Integer(65)
6022 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6024 class NestedSeq(Sequence):
6028 seq["erste"] = Integer(127)
6029 seq["zweite"] = None
6030 nested = NestedSeq()
6031 nested["nest"] = seq
6032 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6034 self.assertSequenceEqual(
6035 OctetString(b"\x01\x02\x03").encode(),
6036 hexdec("0403010203"),
6039 class Seq(Sequence):
6041 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6044 seq["erste"] = Integer(64)
6045 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6047 class Seq(Sequence):
6049 ("erste", Integer(expl=tag_ctxc(5))),
6052 seq["erste"] = Integer(64)
6053 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6055 class Seq(Sequence):
6058 impl=tag_encode(0, klass=TagClassContext),
6063 seq["erste"] = Null()
6064 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6066 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6068 self.assertSequenceEqual(
6069 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6070 hexdec("170d3730303130313030303030305a"),
6072 self.assertSequenceEqual(
6073 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6074 hexdec("170d3039313131353232353631365a"),
6076 self.assertSequenceEqual(
6077 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6078 hexdec("180f32313030303430353132303130315a"),
6081 class Seq(Sequence):
6083 ("erste", GeneralizedTime()),
6086 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6087 self.assertSequenceEqual(
6089 hexdec("3011180f32303039313131353232353631365a"),
6092 self.assertSequenceEqual(
6093 BitString((1, b"\x80")).encode(),
6096 self.assertSequenceEqual(
6097 BitString((12, b"\x81\xF0")).encode(),
6098 hexdec("03030481f0"),
6101 self.assertSequenceEqual(
6102 ObjectIdentifier("1.2.3.4").encode(),
6103 hexdec("06032a0304"),
6105 self.assertSequenceEqual(
6106 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6107 hexdec("06092a864888932d010105"),
6109 self.assertSequenceEqual(
6110 ObjectIdentifier("2.100.3").encode(),
6111 hexdec("0603813403"),
6114 self.assertSequenceEqual(
6115 PrintableString("test").encode(),
6116 hexdec("130474657374"),
6118 self.assertSequenceEqual(
6119 PrintableString("x" * 127).encode(),
6120 hexdec("137F" + "78" * 127),
6122 self.assertSequenceEqual(
6123 PrintableString("x" * 128).encode(),
6124 hexdec("138180" + "78" * 128),
6126 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6128 class Seq(Sequence):
6130 ("erste", IA5String()),
6133 seq["erste"] = IA5String("test")
6134 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6136 class Seq(Sequence):
6138 ("erste", PrintableString()),
6141 seq["erste"] = PrintableString("test")
6142 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6143 # Asterisk is actually not allowable
6144 PrintableString._allowable_chars |= set(b"*")
6145 seq["erste"] = PrintableString("test*")
6146 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6147 PrintableString._allowable_chars -= set(b"*")
6149 class Seq(Sequence):
6151 ("erste", Any(optional=True)),
6152 ("zweite", Integer()),
6155 seq["zweite"] = Integer(64)
6156 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6161 seq.append(Integer(10))
6162 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6164 class _SeqOf(SequenceOf):
6165 schema = PrintableString()
6167 class SeqOf(SequenceOf):
6170 _seqof.append(PrintableString("1"))
6172 seqof.append(_seqof)
6173 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6175 class Seq(Sequence):
6177 ("erste", Integer(default=1)),
6180 seq["erste"] = Integer(0)
6181 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6182 seq["erste"] = Integer(1)
6183 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6184 seq["erste"] = Integer(2)
6185 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6188 class TestPP(TestCase):
6189 @given(data_strategy())
6190 def test_oid_printing(self, d):
6192 str(ObjectIdentifier(k)): v * 2
6193 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6195 chosen = d.draw(sampled_from(sorted(oids)))
6196 chosen_id = oids[chosen]
6197 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6198 self.assertNotIn(chosen_id, pp_console_row(pp))
6201 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6205 class TestAutoAddSlots(TestCase):
6207 class Inher(Integer):
6210 with self.assertRaises(AttributeError):
6212 inher.unexistent = "whatever"
6215 class TestOIDDefines(TestCase):
6216 @given(data_strategy())
6217 def runTest(self, d):
6218 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6219 value_name_chosen = d.draw(sampled_from(value_names))
6221 ObjectIdentifier(oid)
6222 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6224 oid_chosen = d.draw(sampled_from(oids))
6225 values = d.draw(lists(
6227 min_size=len(value_names),
6228 max_size=len(value_names),
6231 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6232 oid: Integer() for oid in oids[:-1]
6235 for i, value_name in enumerate(value_names):
6236 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6238 class Seq(Sequence):
6241 for value_name, value in zip(value_names, values):
6242 seq[value_name] = Any(Integer(value).encode())
6243 seq["type"] = oid_chosen
6244 seq, _ = Seq().decode(seq.encode())
6245 for value_name in value_names:
6246 if value_name == value_name_chosen:
6248 self.assertIsNone(seq[value_name].defined)
6249 if value_name_chosen in oids[:-1]:
6250 self.assertIsNotNone(seq[value_name_chosen].defined)
6251 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6252 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6255 pprint(seq, big_blobs=True, with_decode_path=True)
6258 class TestDefinesByPath(TestCase):
6259 def test_generated(self):
6260 class Seq(Sequence):
6262 ("type", ObjectIdentifier()),
6263 ("value", OctetString(expl=tag_ctxc(123))),
6266 class SeqInner(Sequence):
6268 ("typeInner", ObjectIdentifier()),
6269 ("valueInner", Any()),
6272 class PairValue(SetOf):
6275 class Pair(Sequence):
6277 ("type", ObjectIdentifier()),
6278 ("value", PairValue()),
6281 class Pairs(SequenceOf):
6288 type_octet_stringed,
6290 ObjectIdentifier(oid)
6291 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6293 seq_integered = Seq()
6294 seq_integered["type"] = type_integered
6295 seq_integered["value"] = OctetString(Integer(123).encode())
6296 seq_integered_raw = seq_integered.encode()
6300 (type_octet_stringed, OctetString(b"whatever")),
6301 (type_integered, Integer(123)),
6302 (type_octet_stringed, OctetString(b"whenever")),
6303 (type_integered, Integer(234)),
6305 for t, v in pairs_input:
6308 pair["value"] = PairValue((Any(v),))
6310 seq_inner = SeqInner()
6311 seq_inner["typeInner"] = type_innered
6312 seq_inner["valueInner"] = Any(pairs)
6313 seq_sequenced = Seq()
6314 seq_sequenced["type"] = type_sequenced
6315 seq_sequenced["value"] = OctetString(seq_inner.encode())
6316 seq_sequenced_raw = seq_sequenced.encode()
6318 list(seq_sequenced.pps())
6319 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6321 defines_by_path = []
6322 ctx_copied = deepcopy(ctx_dummy)
6323 seq_integered, _ = Seq().decode(
6327 self.assertDictEqual(ctx_copied, ctx_dummy)
6328 self.assertIsNone(seq_integered["value"].defined)
6329 defines_by_path.append(
6330 (("type",), ((("value",), {
6331 type_integered: Integer(),
6332 type_sequenced: SeqInner(),
6335 ctx_copied["defines_by_path"] = defines_by_path
6336 seq_integered, _ = Seq().decode(
6340 del ctx_copied["defines_by_path"]
6341 self.assertDictEqual(ctx_copied, ctx_dummy)
6342 self.assertIsNotNone(seq_integered["value"].defined)
6343 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6344 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6345 self.assertTrue(seq_integered_raw[
6346 seq_integered["value"].defined[1].offset:
6347 ].startswith(Integer(123).encode()))
6349 list(seq_integered.pps())
6350 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6352 ctx_copied["defines_by_path"] = defines_by_path
6353 seq_sequenced, _ = Seq().decode(
6357 del ctx_copied["defines_by_path"]
6358 self.assertDictEqual(ctx_copied, ctx_dummy)
6359 self.assertIsNotNone(seq_sequenced["value"].defined)
6360 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6361 seq_inner = seq_sequenced["value"].defined[1]
6362 self.assertIsNone(seq_inner["valueInner"].defined)
6364 list(seq_sequenced.pps())
6365 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6367 defines_by_path.append((
6368 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6369 ((("valueInner",), {type_innered: Pairs()}),),
6371 ctx_copied["defines_by_path"] = defines_by_path
6372 seq_sequenced, _ = Seq().decode(
6376 del ctx_copied["defines_by_path"]
6377 self.assertDictEqual(ctx_copied, ctx_dummy)
6378 self.assertIsNotNone(seq_sequenced["value"].defined)
6379 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6380 seq_inner = seq_sequenced["value"].defined[1]
6381 self.assertIsNotNone(seq_inner["valueInner"].defined)
6382 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6383 pairs = seq_inner["valueInner"].defined[1]
6385 self.assertIsNone(pair["value"][0].defined)
6387 list(seq_sequenced.pps())
6388 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6390 defines_by_path.append((
6393 DecodePathDefBy(type_sequenced),
6395 DecodePathDefBy(type_innered),
6400 type_integered: Integer(),
6401 type_octet_stringed: OctetString(),
6404 ctx_copied["defines_by_path"] = defines_by_path
6405 seq_sequenced, _ = Seq().decode(
6409 del ctx_copied["defines_by_path"]
6410 self.assertDictEqual(ctx_copied, ctx_dummy)
6411 self.assertIsNotNone(seq_sequenced["value"].defined)
6412 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6413 seq_inner = seq_sequenced["value"].defined[1]
6414 self.assertIsNotNone(seq_inner["valueInner"].defined)
6415 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6416 pairs_got = seq_inner["valueInner"].defined[1]
6417 for pair_input, pair_got in zip(pairs_input, pairs_got):
6418 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6419 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6421 list(seq_sequenced.pps())
6422 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6424 @given(oid_strategy(), integers())
6425 def test_simple(self, oid, tgt):
6426 class Inner(Sequence):
6428 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6429 ObjectIdentifier(oid): Integer(),
6433 class Outer(Sequence):
6436 ("tgt", OctetString()),
6440 inner["oid"] = ObjectIdentifier(oid)
6442 outer["inner"] = inner
6443 outer["tgt"] = OctetString(Integer(tgt).encode())
6444 decoded, _ = Outer().decode(outer.encode())
6445 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6448 class TestAbsDecodePath(TestCase):
6450 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6451 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6453 def test_concat(self, decode_path, rel_path):
6454 self.assertSequenceEqual(
6455 abs_decode_path(decode_path, rel_path),
6456 decode_path + rel_path,
6460 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6461 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6463 def test_abs(self, decode_path, rel_path):
6464 self.assertSequenceEqual(
6465 abs_decode_path(decode_path, ("/",) + rel_path),
6470 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6471 integers(min_value=1, max_value=3),
6472 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6474 def test_dots(self, decode_path, number_of_dots, rel_path):
6475 self.assertSequenceEqual(
6476 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6477 decode_path[:-number_of_dots] + rel_path,
6481 class TestStrictDefaultExistence(TestCase):
6482 @given(data_strategy())
6483 def runTest(self, d):
6484 count = d.draw(integers(min_value=1, max_value=10))
6485 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6487 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6488 for i in range(count)
6490 for klass in (Sequence, Set):
6494 for i in range(count):
6495 seq["int%d" % i] = Integer(123)
6497 chosen_choice = "int%d" % chosen
6498 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6499 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6501 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6502 self.assertTrue(decoded.ber_encoded)
6503 self.assertTrue(decoded.bered)
6504 decoded = decoded.copy()
6505 self.assertTrue(decoded.ber_encoded)
6506 self.assertTrue(decoded.bered)
6507 decoded, _ = seq.decode(raw, ctx={"bered": True})
6508 self.assertTrue(decoded.ber_encoded)
6509 self.assertTrue(decoded.bered)
6510 decoded = decoded.copy()
6511 self.assertTrue(decoded.ber_encoded)
6512 self.assertTrue(decoded.bered)
6515 class TestX690PrefixedType(TestCase):
6517 self.assertSequenceEqual(
6518 VisibleString("Jones").encode(),
6519 hexdec("1A054A6F6E6573"),
6521 self.assertSequenceEqual(
6524 impl=tag_encode(3, klass=TagClassApplication),
6526 hexdec("43054A6F6E6573"),
6528 self.assertSequenceEqual(
6532 impl=tag_encode(3, klass=TagClassApplication),
6536 hexdec("A20743054A6F6E6573"),
6538 self.assertSequenceEqual(
6542 impl=tag_encode(3, klass=TagClassApplication),
6544 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6546 hexdec("670743054A6F6E6573"),
6548 self.assertSequenceEqual(
6549 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6550 hexdec("82054A6F6E6573"),
6554 class TestExplOOB(TestCase):
6556 expl = tag_ctxc(123)
6557 raw = Integer(123).encode() + Integer(234).encode()
6558 raw = b"".join((expl, len_encode(len(raw)), raw))
6559 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6560 Integer(expl=expl).decode(raw)
6561 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})