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 GeneralizedTime
69 from pyderasn import GeneralString
70 from pyderasn import GraphicString
71 from pyderasn import hexdec
72 from pyderasn import hexenc
73 from pyderasn import IA5String
74 from pyderasn import Integer
75 from pyderasn import InvalidLength
76 from pyderasn import InvalidOID
77 from pyderasn import InvalidValueType
78 from pyderasn import len_decode
79 from pyderasn import len_encode
80 from pyderasn import LEN_YYMMDDHHMMSSZ
81 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
82 from pyderasn import LEN_YYYYMMDDHHMMSSZ
83 from pyderasn import LENINDEF
84 from pyderasn import LenIndefForm
85 from pyderasn import NotEnoughData
86 from pyderasn import Null
87 from pyderasn import NumericString
88 from pyderasn import ObjectIdentifier
89 from pyderasn import ObjNotReady
90 from pyderasn import ObjUnknown
91 from pyderasn import OctetString
92 from pyderasn import pp_console_row
93 from pyderasn import pprint
94 from pyderasn import PrintableString
95 from pyderasn import Sequence
96 from pyderasn import SequenceOf
97 from pyderasn import Set
98 from pyderasn import SetOf
99 from pyderasn import tag_ctxc
100 from pyderasn import tag_ctxp
101 from pyderasn import tag_decode
102 from pyderasn import tag_encode
103 from pyderasn import tag_strip
104 from pyderasn import TagClassApplication
105 from pyderasn import TagClassContext
106 from pyderasn import TagClassPrivate
107 from pyderasn import TagClassUniversal
108 from pyderasn import TagFormConstructed
109 from pyderasn import TagFormPrimitive
110 from pyderasn import TagMismatch
111 from pyderasn import TeletexString
112 from pyderasn import UniversalString
113 from pyderasn import UTCTime
114 from pyderasn import UTF8String
115 from pyderasn import VideotexString
116 from pyderasn import VisibleString
119 settings.register_profile("local", settings(
122 settings.load_profile("local")
123 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
125 tag_classes = sampled_from((
131 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
132 decode_path_strat = lists(integers(), max_size=3).map(
133 lambda decode_path: tuple(str(dp) for dp in decode_path)
135 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
138 class TestHex(TestCase):
140 def test_symmetric(self, data):
141 self.assertEqual(hexdec(hexenc(data)), data)
144 class TestTagCoder(TestCase):
145 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
149 integers(min_value=0, max_value=30),
152 def test_short(self, klass, form, num, junk):
153 raw = tag_encode(klass=klass, form=form, num=num)
154 self.assertEqual(tag_decode(raw), (klass, form, num))
155 self.assertEqual(len(raw), 1)
157 byte2int(tag_encode(klass=klass, form=form, num=0)),
158 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
160 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
161 self.assertSequenceEqual(stripped.tobytes(), raw)
162 self.assertEqual(tlen, len(raw))
163 self.assertSequenceEqual(tail, junk)
165 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
169 integers(min_value=31),
172 def test_long(self, klass, form, num, junk):
173 raw = tag_encode(klass=klass, form=form, num=num)
174 self.assertEqual(tag_decode(raw), (klass, form, num))
175 self.assertGreater(len(raw), 1)
177 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
180 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
181 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
182 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
183 self.assertSequenceEqual(stripped.tobytes(), raw)
184 self.assertEqual(tlen, len(raw))
185 self.assertSequenceEqual(tail, junk)
187 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
188 @given(integers(min_value=31))
189 def test_unfinished_tag(self, num):
190 raw = bytearray(tag_encode(num=num))
191 for i in range(1, len(raw)):
193 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
194 tag_strip(bytes(raw))
196 def test_go_vectors_valid(self):
197 for data, (eklass, etag, elen, eform) in (
198 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
199 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
200 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
201 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
202 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
203 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
204 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
205 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
206 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
207 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
209 tag, _, len_encoded = tag_strip(memoryview(data))
210 klass, form, num = tag_decode(tag)
211 _len, _, tail = len_decode(len_encoded)
212 self.assertSequenceEqual(tail, b"")
213 self.assertEqual(klass, eklass)
214 self.assertEqual(num, etag)
215 self.assertEqual(_len, elen)
216 self.assertEqual(form, eform)
218 def test_go_vectors_invalid(self):
226 with self.assertRaises(DecodeError):
227 _, _, len_encoded = tag_strip(memoryview(data))
228 len_decode(len_encoded)
231 integers(min_value=0, max_value=127),
232 integers(min_value=0, max_value=2),
234 def test_long_instead_of_short(self, l, dummy_num):
235 octets = (b"\x00" * dummy_num) + int2byte(l)
236 octets = int2byte((dummy_num + 1) | 0x80) + octets
237 with self.assertRaises(DecodeError):
241 class TestLenCoder(TestCase):
242 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
244 integers(min_value=0, max_value=127),
247 def test_short(self, l, junk):
248 raw = len_encode(l) + junk
249 decoded, llen, tail = len_decode(memoryview(raw))
250 self.assertEqual(decoded, l)
251 self.assertEqual(llen, 1)
252 self.assertEqual(len(raw), 1 + len(junk))
253 self.assertEqual(tail.tobytes(), junk)
255 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
257 integers(min_value=128),
260 def test_long(self, l, junk):
261 raw = len_encode(l) + junk
262 decoded, llen, tail = len_decode(memoryview(raw))
263 self.assertEqual(decoded, l)
264 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
265 self.assertEqual(llen, len(raw) - len(junk))
266 self.assertNotEqual(indexbytes(raw, 1), 0)
267 self.assertSequenceEqual(tail.tobytes(), junk)
269 def test_empty(self):
270 with self.assertRaises(NotEnoughData):
273 @given(integers(min_value=128))
274 def test_stripped(self, _len):
275 with self.assertRaises(NotEnoughData):
276 len_decode(len_encode(_len)[:-1])
279 text_printable = text(alphabet=printable, min_size=1)
283 def text_letters(draw):
284 result = draw(text(alphabet=ascii_letters, min_size=1))
286 result = result.encode("ascii")
290 class CommonMixin(object):
291 def test_tag_default(self):
292 obj = self.base_klass()
293 self.assertEqual(obj.tag, obj.tag_default)
295 def test_simultaneous_impl_expl(self):
296 with self.assertRaises(ValueError):
297 self.base_klass(impl=b"whatever", expl=b"whenever")
299 @given(binary(min_size=1), integers(), integers(), integers())
300 def test_decoded(self, impl, offset, llen, vlen):
301 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
302 self.assertEqual(obj.offset, offset)
303 self.assertEqual(obj.llen, llen)
304 self.assertEqual(obj.vlen, vlen)
305 self.assertEqual(obj.tlen, len(impl))
306 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
308 @given(binary(min_size=1))
309 def test_impl_inherited(self, impl_tag):
310 class Inherited(self.base_klass):
313 self.assertSequenceEqual(obj.impl, impl_tag)
314 self.assertFalse(obj.expled)
317 def test_expl_inherited(self, expl_tag):
318 class Inherited(self.base_klass):
321 self.assertSequenceEqual(obj.expl, expl_tag)
322 self.assertTrue(obj.expled)
324 def assert_copied_basic_fields(self, obj, obj_copied):
325 self.assertEqual(obj, obj_copied)
326 self.assertSequenceEqual(obj.tag, obj_copied.tag)
327 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
328 self.assertEqual(obj.default, obj_copied.default)
329 self.assertEqual(obj.optional, obj_copied.optional)
330 self.assertEqual(obj.offset, obj_copied.offset)
331 self.assertEqual(obj.llen, obj_copied.llen)
332 self.assertEqual(obj.vlen, obj_copied.vlen)
336 def boolean_values_strategy(draw, do_expl=False):
337 value = draw(one_of(none(), booleans()))
341 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
343 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
344 default = draw(one_of(none(), booleans()))
345 optional = draw(one_of(none(), booleans()))
347 draw(integers(min_value=0)),
348 draw(integers(min_value=0)),
349 draw(integers(min_value=0)),
351 return (value, impl, expl, default, optional, _decoded)
354 class BooleanInherited(Boolean):
358 class TestBoolean(CommonMixin, TestCase):
361 def test_invalid_value_type(self):
362 with self.assertRaises(InvalidValueType) as err:
367 def test_optional(self, optional):
368 obj = Boolean(default=Boolean(False), optional=optional)
369 self.assertTrue(obj.optional)
372 def test_ready(self, value):
374 self.assertFalse(obj.ready)
377 pprint(obj, big_blobs=True, with_decode_path=True)
378 with self.assertRaises(ObjNotReady) as err:
382 self.assertTrue(obj.ready)
385 pprint(obj, big_blobs=True, with_decode_path=True)
387 @given(booleans(), booleans(), binary(), binary())
388 def test_comparison(self, value1, value2, tag1, tag2):
389 for klass in (Boolean, BooleanInherited):
392 self.assertEqual(obj1 == obj2, value1 == value2)
393 self.assertEqual(obj1 != obj2, value1 != value2)
394 self.assertEqual(obj1 == bool(obj2), value1 == value2)
395 obj1 = klass(value1, impl=tag1)
396 obj2 = klass(value1, impl=tag2)
397 self.assertEqual(obj1 == obj2, tag1 == tag2)
398 self.assertEqual(obj1 != obj2, tag1 != tag2)
400 @given(data_strategy())
401 def test_call(self, d):
402 for klass in (Boolean, BooleanInherited):
410 ) = d.draw(boolean_values_strategy())
416 optional_initial or False,
426 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
427 obj = obj_initial(value, impl, expl, default, optional)
429 value_expected = default if value is None else value
431 default_initial if value_expected is None
434 self.assertEqual(obj, value_expected)
435 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
436 self.assertEqual(obj.expl_tag, expl or expl_initial)
439 default_initial if default is None else default,
441 if obj.default is None:
442 optional = optional_initial if optional is None else optional
443 optional = False if optional is None else optional
446 self.assertEqual(obj.optional, optional)
448 @given(boolean_values_strategy())
449 def test_copy(self, values):
450 for klass in (Boolean, BooleanInherited):
452 obj_copied = obj.copy()
453 self.assert_copied_basic_fields(obj, obj_copied)
457 integers(min_value=1).map(tag_encode),
459 def test_stripped(self, value, tag_impl):
460 obj = Boolean(value, impl=tag_impl)
461 with self.assertRaises(NotEnoughData):
462 obj.decode(obj.encode()[:-1])
466 integers(min_value=1).map(tag_ctxc),
468 def test_stripped_expl(self, value, tag_expl):
469 obj = Boolean(value, expl=tag_expl)
470 with self.assertRaises(NotEnoughData):
471 obj.decode(obj.encode()[:-1])
474 integers(min_value=31),
475 integers(min_value=0),
478 def test_bad_tag(self, tag, offset, decode_path):
479 with self.assertRaises(DecodeError) as err:
481 tag_encode(tag)[:-1],
483 decode_path=decode_path,
486 self.assertEqual(err.exception.offset, offset)
487 self.assertEqual(err.exception.decode_path, decode_path)
490 integers(min_value=31),
491 integers(min_value=0),
494 def test_bad_expl_tag(self, tag, offset, decode_path):
495 with self.assertRaises(DecodeError) as err:
496 Boolean(expl=Boolean.tag_default).decode(
497 tag_encode(tag)[:-1],
499 decode_path=decode_path,
502 self.assertEqual(err.exception.offset, offset)
503 self.assertEqual(err.exception.decode_path, decode_path)
506 integers(min_value=128),
507 integers(min_value=0),
510 def test_bad_len(self, l, offset, decode_path):
511 with self.assertRaises(DecodeError) as err:
513 Boolean.tag_default + len_encode(l)[:-1],
515 decode_path=decode_path,
518 self.assertEqual(err.exception.offset, offset)
519 self.assertEqual(err.exception.decode_path, decode_path)
522 integers(min_value=128),
523 integers(min_value=0),
526 def test_bad_expl_len(self, l, offset, decode_path):
527 with self.assertRaises(DecodeError) as err:
528 Boolean(expl=Boolean.tag_default).decode(
529 Boolean.tag_default + len_encode(l)[:-1],
531 decode_path=decode_path,
534 self.assertEqual(err.exception.offset, offset)
535 self.assertEqual(err.exception.decode_path, decode_path)
537 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
539 boolean_values_strategy(),
541 integers(min_value=1).map(tag_ctxc),
542 integers(min_value=0),
545 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
546 for klass in (Boolean, BooleanInherited):
547 _, _, _, default, optional, _decoded = values
556 pprint(obj, big_blobs=True, with_decode_path=True)
557 self.assertFalse(obj.expled)
558 obj_encoded = obj.encode()
559 obj_expled = obj(value, expl=tag_expl)
560 self.assertTrue(obj_expled.expled)
562 list(obj_expled.pps())
563 pprint(obj_expled, big_blobs=True, with_decode_path=True)
564 obj_expled_encoded = obj_expled.encode()
565 ctx_copied = deepcopy(ctx_dummy)
566 obj_decoded, tail = obj_expled.decode(
567 obj_expled_encoded + tail_junk,
571 self.assertDictEqual(ctx_copied, ctx_dummy)
573 list(obj_decoded.pps())
574 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
575 self.assertEqual(tail, tail_junk)
576 self.assertEqual(obj_decoded, obj_expled)
577 self.assertNotEqual(obj_decoded, obj)
578 self.assertEqual(bool(obj_decoded), bool(obj_expled))
579 self.assertEqual(bool(obj_decoded), bool(obj))
580 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
581 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
582 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
584 obj_decoded.expl_llen,
585 len(len_encode(len(obj_encoded))),
587 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
588 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
591 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
593 self.assertEqual(obj_decoded.expl_offset, offset)
595 @given(integers(min_value=2))
596 def test_invalid_len(self, l):
597 with self.assertRaises(InvalidLength):
598 Boolean().decode(b"".join((
604 @given(integers(min_value=0 + 1, max_value=255 - 1))
605 def test_ber_value(self, value):
606 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
607 Boolean().decode(b"".join((
612 obj, _ = Boolean().decode(
620 self.assertTrue(bool(obj))
621 self.assertTrue(obj.ber_encoded)
622 self.assertFalse(obj.lenindef)
623 self.assertTrue(obj.bered)
625 self.assertTrue(obj.ber_encoded)
626 self.assertFalse(obj.lenindef)
627 self.assertTrue(obj.bered)
630 integers(min_value=1).map(tag_ctxc),
631 binary().filter(lambda x: not x.startswith(EOC)),
633 def test_ber_expl_no_eoc(self, expl, junk):
634 encoded = expl + LENINDEF + Boolean(False).encode()
635 with self.assertRaises(LenIndefForm):
636 Boolean(expl=expl).decode(encoded + junk)
637 with assertRaisesRegex(self, DecodeError, "no EOC"):
638 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
639 obj, tail = Boolean(expl=expl).decode(
640 encoded + EOC + junk,
643 self.assertTrue(obj.expl_lenindef)
644 self.assertFalse(obj.lenindef)
645 self.assertFalse(obj.ber_encoded)
646 self.assertTrue(obj.bered)
648 self.assertTrue(obj.expl_lenindef)
649 self.assertFalse(obj.lenindef)
650 self.assertFalse(obj.ber_encoded)
651 self.assertTrue(obj.bered)
652 self.assertSequenceEqual(tail, junk)
655 pprint(obj, big_blobs=True, with_decode_path=True)
658 integers(min_value=1).map(tag_ctxc),
665 def test_ber_expl(self, expl, values):
671 Boolean(value).encode() +
674 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
676 class SeqOf(SequenceOf):
677 schema = Boolean(expl=expl)
678 with self.assertRaises(LenIndefForm):
679 SeqOf().decode(encoded)
680 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
681 self.assertSequenceEqual(tail, b"")
682 self.assertSequenceEqual([bool(v) for v in seqof], values)
698 len(expl) + 1 + 3 + EOC_LEN,
709 pprint(seqof, big_blobs=True, with_decode_path=True)
713 def integer_values_strategy(draw, do_expl=False):
714 bound_min, value, default, bound_max = sorted(draw(sets(
723 _specs = draw(sets(text_letters()))
726 min_size=len(_specs),
727 max_size=len(_specs),
729 _specs = list(zip(_specs, values))
732 bounds = (bound_min, bound_max)
736 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
738 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
741 optional = draw(one_of(none(), booleans()))
743 draw(integers(min_value=0)),
744 draw(integers(min_value=0)),
745 draw(integers(min_value=0)),
747 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
750 class IntegerInherited(Integer):
754 class TestInteger(CommonMixin, TestCase):
757 def test_invalid_value_type(self):
758 with self.assertRaises(InvalidValueType) as err:
762 @given(sets(text_letters(), min_size=2))
763 def test_unknown_name(self, names_input):
764 missing = names_input.pop()
767 schema = [(n, 123) for n in names_input]
768 with self.assertRaises(ObjUnknown) as err:
772 @given(sets(text_letters(), min_size=2))
773 def test_known_name(self, names_input):
775 schema = [(n, 123) for n in names_input]
776 Int(names_input.pop())
779 def test_optional(self, optional):
780 obj = Integer(default=Integer(0), optional=optional)
781 self.assertTrue(obj.optional)
784 def test_ready(self, value):
786 self.assertFalse(obj.ready)
789 pprint(obj, big_blobs=True, with_decode_path=True)
790 with self.assertRaises(ObjNotReady) as err:
794 self.assertTrue(obj.ready)
797 pprint(obj, big_blobs=True, with_decode_path=True)
800 @given(integers(), integers(), binary(), binary())
801 def test_comparison(self, value1, value2, tag1, tag2):
802 for klass in (Integer, IntegerInherited):
805 self.assertEqual(obj1 == obj2, value1 == value2)
806 self.assertEqual(obj1 != obj2, value1 != value2)
807 self.assertEqual(obj1 == int(obj2), value1 == value2)
808 obj1 = klass(value1, impl=tag1)
809 obj2 = klass(value1, impl=tag2)
810 self.assertEqual(obj1 == obj2, tag1 == tag2)
811 self.assertEqual(obj1 != obj2, tag1 != tag2)
813 @given(lists(integers()))
814 def test_sorted_works(self, values):
815 self.assertSequenceEqual(
816 [int(v) for v in sorted(Integer(v) for v in values)],
820 @given(data_strategy())
821 def test_named(self, d):
822 names_input = list(d.draw(sets(text_letters(), min_size=1)))
823 values_input = list(d.draw(sets(
825 min_size=len(names_input),
826 max_size=len(names_input),
828 chosen_name = d.draw(sampled_from(names_input))
829 names_input = dict(zip(names_input, values_input))
833 _int = Int(chosen_name)
834 self.assertEqual(_int.named, chosen_name)
835 self.assertEqual(int(_int), names_input[chosen_name])
837 @given(integers(), integers(min_value=0), integers(min_value=0))
838 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
839 value = bound_min + value_delta
840 bound_max = value + bound_delta
841 Integer(value=value, bounds=(bound_min, bound_max))
843 @given(sets(integers(), min_size=3, max_size=3))
844 def test_bounds_unsatisfied(self, values):
845 values = sorted(values)
846 with self.assertRaises(BoundsError) as err:
847 Integer(value=values[0], bounds=(values[1], values[2]))
849 with assertRaisesRegex(self, DecodeError, "bounds") as err:
850 Integer(bounds=(values[1], values[2])).decode(
851 Integer(values[0]).encode()
854 with self.assertRaises(BoundsError) as err:
855 Integer(value=values[2], bounds=(values[0], values[1]))
857 with assertRaisesRegex(self, DecodeError, "bounds") as err:
858 Integer(bounds=(values[0], values[1])).decode(
859 Integer(values[2]).encode()
863 @given(data_strategy())
864 def test_call(self, d):
865 for klass in (Integer, IntegerInherited):
875 ) = d.draw(integer_values_strategy())
882 optional_initial or False,
895 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
896 if (default is None) and (obj_initial.default is not None):
900 (value is not None) and
901 (bounds_initial is not None) and
902 not (bounds_initial[0] <= value <= bounds_initial[1])
907 (default is not None) and
908 (bounds_initial is not None) and
909 not (bounds_initial[0] <= default <= bounds_initial[1])
912 obj = obj_initial(value, bounds, impl, expl, default, optional)
914 value_expected = default if value is None else value
916 default_initial if value_expected is None
919 self.assertEqual(obj, value_expected)
920 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
921 self.assertEqual(obj.expl_tag, expl or expl_initial)
924 default_initial if default is None else default,
926 if obj.default is None:
927 optional = optional_initial if optional is None else optional
928 optional = False if optional is None else optional
931 self.assertEqual(obj.optional, optional)
933 (obj._bound_min, obj._bound_max),
934 bounds or bounds_initial or (float("-inf"), float("+inf")),
938 {} if _specs_initial is None else dict(_specs_initial),
941 @given(integer_values_strategy())
942 def test_copy(self, values):
943 for klass in (Integer, IntegerInherited):
945 obj_copied = obj.copy()
946 self.assert_copied_basic_fields(obj, obj_copied)
947 self.assertEqual(obj.specs, obj_copied.specs)
948 self.assertEqual(obj._bound_min, obj_copied._bound_min)
949 self.assertEqual(obj._bound_max, obj_copied._bound_max)
950 self.assertEqual(obj._value, obj_copied._value)
954 integers(min_value=1).map(tag_encode),
956 def test_stripped(self, value, tag_impl):
957 obj = Integer(value, impl=tag_impl)
958 with self.assertRaises(NotEnoughData):
959 obj.decode(obj.encode()[:-1])
963 integers(min_value=1).map(tag_ctxc),
965 def test_stripped_expl(self, value, tag_expl):
966 obj = Integer(value, expl=tag_expl)
967 with self.assertRaises(NotEnoughData):
968 obj.decode(obj.encode()[:-1])
970 def test_zero_len(self):
971 with self.assertRaises(NotEnoughData):
972 Integer().decode(b"".join((
978 integers(min_value=31),
979 integers(min_value=0),
982 def test_bad_tag(self, tag, offset, decode_path):
983 with self.assertRaises(DecodeError) as err:
985 tag_encode(tag)[:-1],
987 decode_path=decode_path,
990 self.assertEqual(err.exception.offset, offset)
991 self.assertEqual(err.exception.decode_path, decode_path)
994 integers(min_value=128),
995 integers(min_value=0),
998 def test_bad_len(self, l, offset, decode_path):
999 with self.assertRaises(DecodeError) as err:
1001 Integer.tag_default + len_encode(l)[:-1],
1003 decode_path=decode_path,
1006 self.assertEqual(err.exception.offset, offset)
1007 self.assertEqual(err.exception.decode_path, decode_path)
1010 sets(integers(), min_size=2, max_size=2),
1011 integers(min_value=0),
1014 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1015 value, bound_min = list(sorted(ints))
1018 bounds = (bound_min, bound_min)
1019 with self.assertRaises(DecodeError) as err:
1021 Integer(value).encode(),
1023 decode_path=decode_path,
1026 self.assertEqual(err.exception.offset, offset)
1027 self.assertEqual(err.exception.decode_path, decode_path)
1029 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1031 integer_values_strategy(),
1033 integers(min_value=1).map(tag_ctxc),
1034 integers(min_value=0),
1037 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1038 for klass in (Integer, IntegerInherited):
1039 _, _, _, _, default, optional, _, _decoded = values
1048 pprint(obj, big_blobs=True, with_decode_path=True)
1049 self.assertFalse(obj.expled)
1050 obj_encoded = obj.encode()
1051 obj_expled = obj(value, expl=tag_expl)
1052 self.assertTrue(obj_expled.expled)
1054 list(obj_expled.pps())
1055 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1056 obj_expled_encoded = obj_expled.encode()
1057 ctx_copied = deepcopy(ctx_dummy)
1058 obj_decoded, tail = obj_expled.decode(
1059 obj_expled_encoded + tail_junk,
1063 self.assertDictEqual(ctx_copied, ctx_dummy)
1065 list(obj_decoded.pps())
1066 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1067 self.assertEqual(tail, tail_junk)
1068 self.assertEqual(obj_decoded, obj_expled)
1069 self.assertNotEqual(obj_decoded, obj)
1070 self.assertEqual(int(obj_decoded), int(obj_expled))
1071 self.assertEqual(int(obj_decoded), int(obj))
1072 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1073 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1074 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1076 obj_decoded.expl_llen,
1077 len(len_encode(len(obj_encoded))),
1079 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1080 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1083 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1085 self.assertEqual(obj_decoded.expl_offset, offset)
1087 def test_go_vectors_valid(self):
1088 for data, expect in ((
1092 (b"\xff\x7f", -129),
1096 (b"\xff\x00", -256),
1100 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1101 (b"\x80\x00\x00\x00", -2147483648),
1104 Integer().decode(b"".join((
1105 Integer.tag_default,
1106 len_encode(len(data)),
1112 def test_go_vectors_invalid(self):
1117 with self.assertRaises(DecodeError):
1118 Integer().decode(b"".join((
1119 Integer.tag_default,
1120 len_encode(len(data)),
1126 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1129 if draw(booleans()):
1130 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1132 integers(min_value=0, max_value=255),
1133 min_size=len(schema),
1134 max_size=len(schema),
1136 schema = list(zip(schema, bits))
1138 def _value(value_required):
1139 if not value_required and draw(booleans()):
1141 generation_choice = 0
1143 generation_choice = draw(sampled_from((1, 2, 3)))
1144 if generation_choice == 1 or draw(booleans()):
1145 return "'%s'B" % "".join(draw(lists(
1146 sampled_from(("0", "1")),
1147 max_size=len(schema),
1149 elif generation_choice == 2 or draw(booleans()):
1150 return draw(binary(max_size=len(schema) // 8))
1151 elif generation_choice == 3 or draw(booleans()):
1152 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1154 value = _value(value_required)
1155 default = _value(value_required=False)
1159 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1161 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1162 optional = draw(one_of(none(), booleans()))
1164 draw(integers(min_value=0)),
1165 draw(integers(min_value=0)),
1166 draw(integers(min_value=0)),
1168 return (schema, value, impl, expl, default, optional, _decoded)
1171 class BitStringInherited(BitString):
1175 class TestBitString(CommonMixin, TestCase):
1176 base_klass = BitString
1178 @given(lists(booleans()))
1179 def test_b_encoding(self, bits):
1180 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1181 self.assertEqual(obj.bit_len, len(bits))
1182 self.assertSequenceEqual(list(obj), bits)
1183 for i, bit in enumerate(bits):
1184 self.assertEqual(obj[i], bit)
1186 @given(lists(booleans()))
1187 def test_out_of_bounds_bits(self, bits):
1188 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1189 for i in range(len(bits), len(bits) * 2):
1190 self.assertFalse(obj[i])
1192 def test_bad_b_encoding(self):
1193 with self.assertRaises(ValueError):
1194 BitString("'010120101'B")
1197 integers(min_value=1, max_value=255),
1198 integers(min_value=1, max_value=255),
1200 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1201 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1202 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1203 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1205 class BS(BitString):
1206 schema = (("whatever", 0),)
1207 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1208 self.assertEqual(obj.bit_len, leading_zeros + 1)
1209 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1211 def test_zero_len(self):
1212 with self.assertRaises(NotEnoughData):
1213 BitString().decode(b"".join((
1214 BitString.tag_default,
1218 def test_invalid_value_type(self):
1219 with self.assertRaises(InvalidValueType) as err:
1222 with self.assertRaises(InvalidValueType) as err:
1226 def test_obj_unknown(self):
1227 with self.assertRaises(ObjUnknown) as err:
1228 BitString(b"whatever")["whenever"]
1231 def test_get_invalid_type(self):
1232 with self.assertRaises(InvalidValueType) as err:
1233 BitString(b"whatever")[(1, 2, 3)]
1236 @given(data_strategy())
1237 def test_unknown_name(self, d):
1238 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1239 missing = _schema.pop()
1241 class BS(BitString):
1242 schema = [(n, i) for i, n in enumerate(_schema)]
1243 with self.assertRaises(ObjUnknown) as err:
1248 def test_optional(self, optional):
1249 obj = BitString(default=BitString(b""), optional=optional)
1250 self.assertTrue(obj.optional)
1253 def test_ready(self, value):
1255 self.assertFalse(obj.ready)
1258 pprint(obj, big_blobs=True, with_decode_path=True)
1259 with self.assertRaises(ObjNotReady) as err:
1262 obj = BitString(value)
1263 self.assertTrue(obj.ready)
1266 pprint(obj, big_blobs=True, with_decode_path=True)
1269 tuples(integers(min_value=0), binary()),
1270 tuples(integers(min_value=0), binary()),
1274 def test_comparison(self, value1, value2, tag1, tag2):
1275 for klass in (BitString, BitStringInherited):
1276 obj1 = klass(value1)
1277 obj2 = klass(value2)
1278 self.assertEqual(obj1 == obj2, value1 == value2)
1279 self.assertEqual(obj1 != obj2, value1 != value2)
1280 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1281 obj1 = klass(value1, impl=tag1)
1282 obj2 = klass(value1, impl=tag2)
1283 self.assertEqual(obj1 == obj2, tag1 == tag2)
1284 self.assertEqual(obj1 != obj2, tag1 != tag2)
1286 @given(data_strategy())
1287 def test_call(self, d):
1288 for klass in (BitString, BitStringInherited):
1297 ) = d.draw(bit_string_values_strategy())
1300 schema = schema_initial
1302 value=value_initial,
1305 default=default_initial,
1306 optional=optional_initial or False,
1307 _decoded=_decoded_initial,
1317 ) = d.draw(bit_string_values_strategy(
1318 schema=schema_initial,
1319 do_expl=impl_initial is None,
1328 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1329 self.assertEqual(obj.expl_tag, expl or expl_initial)
1330 if obj.default is None:
1331 optional = optional_initial if optional is None else optional
1332 optional = False if optional is None else optional
1335 self.assertEqual(obj.optional, optional)
1336 self.assertEqual(obj.specs, obj_initial.specs)
1338 @given(bit_string_values_strategy())
1339 def test_copy(self, values):
1340 for klass in (BitString, BitStringInherited):
1341 _schema, value, impl, expl, default, optional, _decoded = values
1350 optional=optional or False,
1353 obj_copied = obj.copy()
1354 self.assert_copied_basic_fields(obj, obj_copied)
1355 self.assertEqual(obj.specs, obj_copied.specs)
1356 self.assertEqual(obj._value, obj_copied._value)
1360 integers(min_value=1).map(tag_encode),
1362 def test_stripped(self, value, tag_impl):
1363 obj = BitString(value, impl=tag_impl)
1364 with self.assertRaises(NotEnoughData):
1365 obj.decode(obj.encode()[:-1])
1369 integers(min_value=1).map(tag_ctxc),
1371 def test_stripped_expl(self, value, tag_expl):
1372 obj = BitString(value, expl=tag_expl)
1373 with self.assertRaises(NotEnoughData):
1374 obj.decode(obj.encode()[:-1])
1377 integers(min_value=31),
1378 integers(min_value=0),
1381 def test_bad_tag(self, tag, offset, decode_path):
1382 with self.assertRaises(DecodeError) as err:
1384 tag_encode(tag)[:-1],
1386 decode_path=decode_path,
1389 self.assertEqual(err.exception.offset, offset)
1390 self.assertEqual(err.exception.decode_path, decode_path)
1393 integers(min_value=128),
1394 integers(min_value=0),
1397 def test_bad_len(self, l, offset, decode_path):
1398 with self.assertRaises(DecodeError) as err:
1400 BitString.tag_default + len_encode(l)[:-1],
1402 decode_path=decode_path,
1405 self.assertEqual(err.exception.offset, offset)
1406 self.assertEqual(err.exception.decode_path, decode_path)
1408 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1409 @given(data_strategy())
1410 def test_symmetric(self, d):
1419 ) = d.draw(bit_string_values_strategy(value_required=True))
1420 tail_junk = d.draw(binary(max_size=5))
1421 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1422 offset = d.draw(integers(min_value=0))
1423 for klass in (BitString, BitStringInherited):
1434 pprint(obj, big_blobs=True, with_decode_path=True)
1435 self.assertFalse(obj.expled)
1436 obj_encoded = obj.encode()
1437 obj_expled = obj(value, expl=tag_expl)
1438 self.assertTrue(obj_expled.expled)
1440 list(obj_expled.pps())
1441 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1442 obj_expled_encoded = obj_expled.encode()
1443 ctx_copied = deepcopy(ctx_dummy)
1444 obj_decoded, tail = obj_expled.decode(
1445 obj_expled_encoded + tail_junk,
1449 self.assertDictEqual(ctx_copied, ctx_dummy)
1451 list(obj_decoded.pps())
1452 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1453 self.assertEqual(tail, tail_junk)
1454 self.assertEqual(obj_decoded, obj_expled)
1455 self.assertNotEqual(obj_decoded, obj)
1456 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1457 self.assertEqual(bytes(obj_decoded), bytes(obj))
1458 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1459 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1460 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1462 obj_decoded.expl_llen,
1463 len(len_encode(len(obj_encoded))),
1465 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1466 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1469 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1471 self.assertEqual(obj_decoded.expl_offset, offset)
1472 if isinstance(value, tuple):
1473 self.assertSetEqual(set(value), set(obj_decoded.named))
1477 @given(integers(min_value=1, max_value=255))
1478 def test_bad_zero_value(self, pad_size):
1479 with self.assertRaises(DecodeError):
1480 BitString().decode(b"".join((
1481 BitString.tag_default,
1486 def test_go_vectors_invalid(self):
1492 with self.assertRaises(DecodeError):
1493 BitString().decode(b"".join((
1494 BitString.tag_default,
1499 def test_go_vectors_valid(self):
1500 obj, _ = BitString().decode(b"".join((
1501 BitString.tag_default,
1505 self.assertEqual(bytes(obj), b"")
1506 self.assertEqual(obj.bit_len, 0)
1508 obj, _ = BitString().decode(b"".join((
1509 BitString.tag_default,
1513 self.assertEqual(bytes(obj), b"\x00")
1514 self.assertEqual(obj.bit_len, 1)
1516 obj = BitString((16, b"\x82\x40"))
1517 self.assertTrue(obj[0])
1518 self.assertFalse(obj[1])
1519 self.assertTrue(obj[6])
1520 self.assertTrue(obj[9])
1521 self.assertFalse(obj[17])
1524 integers(min_value=1, max_value=30),
1527 binary(min_size=1, max_size=5),
1529 binary(min_size=1, max_size=5),
1537 lists(booleans(), min_size=1),
1540 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1541 def chunk_constructed(contents):
1543 tag_encode(form=TagFormConstructed, num=3) +
1545 b"".join(BitString(content).encode() for content in contents) +
1549 payload_expected = b""
1550 bit_len_expected = 0
1551 for chunk_input in chunk_inputs:
1552 if isinstance(chunk_input, binary_type):
1553 chunks.append(BitString(chunk_input).encode())
1554 payload_expected += chunk_input
1555 bit_len_expected += len(chunk_input) * 8
1557 chunks.append(chunk_constructed(chunk_input))
1558 payload = b"".join(chunk_input)
1559 payload_expected += payload
1560 bit_len_expected += len(payload) * 8
1561 chunk_last = BitString("'%s'B" % "".join(
1562 "1" if bit else "0" for bit in chunk_last_bits
1564 payload_expected += bytes(chunk_last)
1565 bit_len_expected += chunk_last.bit_len
1566 encoded_indefinite = (
1567 tag_encode(form=TagFormConstructed, num=impl) +
1570 chunk_last.encode() +
1573 encoded_definite = (
1574 tag_encode(form=TagFormConstructed, num=impl) +
1575 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1579 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1580 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1581 for lenindef_expected, encoded in (
1582 (True, encoded_indefinite),
1583 (False, encoded_definite),
1585 obj, tail = BitString(impl=tag_encode(impl)).decode(
1587 ctx={"bered": True},
1589 self.assertSequenceEqual(tail, junk)
1590 self.assertEqual(obj.bit_len, bit_len_expected)
1591 self.assertSequenceEqual(bytes(obj), payload_expected)
1592 self.assertTrue(obj.ber_encoded)
1593 self.assertEqual(obj.lenindef, lenindef_expected)
1594 self.assertTrue(obj.bered)
1596 self.assertTrue(obj.ber_encoded)
1597 self.assertEqual(obj.lenindef, lenindef_expected)
1598 self.assertTrue(obj.bered)
1599 self.assertEqual(len(encoded), obj.tlvlen)
1602 integers(min_value=0),
1605 def test_ber_definite_too_short(self, offset, decode_path):
1606 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1608 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1610 decode_path=decode_path,
1611 ctx={"bered": True},
1613 self.assertEqual(err.exception.decode_path, decode_path)
1614 self.assertEqual(err.exception.offset, offset)
1617 integers(min_value=0),
1620 def test_ber_definite_no_data(self, offset, decode_path):
1621 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1623 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1625 decode_path=decode_path,
1626 ctx={"bered": True},
1628 self.assertEqual(err.exception.decode_path, decode_path)
1629 self.assertEqual(err.exception.offset, offset)
1632 integers(min_value=0),
1634 integers(min_value=1, max_value=3),
1636 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1637 bs = BitString(b"data").encode()
1638 with self.assertRaises(NotEnoughData) as err:
1640 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1642 decode_path=decode_path,
1643 ctx={"bered": True},
1645 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1646 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1649 integers(min_value=0),
1651 integers(min_value=1, max_value=3),
1653 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1654 bs = BitString(b"data").encode()
1655 bs_longer = BitString(b"data-longer").encode()
1656 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1659 tag_encode(3, form=TagFormConstructed) +
1660 len_encode((chunks + 1) * len(bs)) +
1665 decode_path=decode_path,
1666 ctx={"bered": True},
1668 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1669 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1672 integers(min_value=0),
1675 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1676 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1678 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1680 decode_path=decode_path,
1681 ctx={"bered": True},
1683 self.assertEqual(err.exception.decode_path, decode_path)
1684 self.assertEqual(err.exception.offset, offset)
1686 @given(data_strategy())
1687 def test_ber_indefinite_not_multiple(self, d):
1688 bs_short = BitString("'A'H").encode()
1689 bs_full = BitString("'AA'H").encode()
1690 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1691 chunks.append(bs_short)
1692 d.draw(permutations(chunks))
1693 chunks.append(bs_short)
1694 offset = d.draw(integers(min_value=0))
1695 decode_path = d.draw(decode_path_strat)
1696 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1699 tag_encode(3, form=TagFormConstructed) +
1705 decode_path=decode_path,
1706 ctx={"bered": True},
1709 err.exception.decode_path,
1710 decode_path + (str(chunks.index(bs_short)),),
1713 err.exception.offset,
1714 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1717 def test_x690_vector(self):
1718 vector = BitString("'0A3B5F291CD'H")
1719 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1720 self.assertSequenceEqual(tail, b"")
1721 self.assertEqual(obj, vector)
1722 obj, tail = BitString().decode(
1723 hexdec("23800303000A3B0305045F291CD00000"),
1724 ctx={"bered": True},
1726 self.assertSequenceEqual(tail, b"")
1727 self.assertEqual(obj, vector)
1728 self.assertTrue(obj.ber_encoded)
1729 self.assertTrue(obj.lenindef)
1730 self.assertTrue(obj.bered)
1732 self.assertTrue(obj.ber_encoded)
1733 self.assertTrue(obj.lenindef)
1734 self.assertTrue(obj.bered)
1738 def octet_string_values_strategy(draw, do_expl=False):
1739 bound_min, bound_max = sorted(draw(sets(
1740 integers(min_value=0, max_value=1 << 7),
1744 value = draw(one_of(
1746 binary(min_size=bound_min, max_size=bound_max),
1748 default = draw(one_of(
1750 binary(min_size=bound_min, max_size=bound_max),
1753 if draw(booleans()):
1754 bounds = (bound_min, bound_max)
1758 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1760 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1761 optional = draw(one_of(none(), booleans()))
1763 draw(integers(min_value=0)),
1764 draw(integers(min_value=0)),
1765 draw(integers(min_value=0)),
1767 return (value, bounds, impl, expl, default, optional, _decoded)
1770 class OctetStringInherited(OctetString):
1774 class TestOctetString(CommonMixin, TestCase):
1775 base_klass = OctetString
1777 def test_invalid_value_type(self):
1778 with self.assertRaises(InvalidValueType) as err:
1779 OctetString(text_type(123))
1783 def test_optional(self, optional):
1784 obj = OctetString(default=OctetString(b""), optional=optional)
1785 self.assertTrue(obj.optional)
1788 def test_ready(self, value):
1790 self.assertFalse(obj.ready)
1793 pprint(obj, big_blobs=True, with_decode_path=True)
1794 with self.assertRaises(ObjNotReady) as err:
1797 obj = OctetString(value)
1798 self.assertTrue(obj.ready)
1801 pprint(obj, big_blobs=True, with_decode_path=True)
1803 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1804 def test_comparison(self, value1, value2, tag1, tag2):
1805 for klass in (OctetString, OctetStringInherited):
1806 obj1 = klass(value1)
1807 obj2 = klass(value2)
1808 self.assertEqual(obj1 == obj2, value1 == value2)
1809 self.assertEqual(obj1 != obj2, value1 != value2)
1810 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1811 obj1 = klass(value1, impl=tag1)
1812 obj2 = klass(value1, impl=tag2)
1813 self.assertEqual(obj1 == obj2, tag1 == tag2)
1814 self.assertEqual(obj1 != obj2, tag1 != tag2)
1816 @given(lists(binary()))
1817 def test_sorted_works(self, values):
1818 self.assertSequenceEqual(
1819 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1823 @given(data_strategy())
1824 def test_bounds_satisfied(self, d):
1825 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1826 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1827 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1828 OctetString(value=value, bounds=(bound_min, bound_max))
1830 @given(data_strategy())
1831 def test_bounds_unsatisfied(self, d):
1832 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1833 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1834 value = d.draw(binary(max_size=bound_min - 1))
1835 with self.assertRaises(BoundsError) as err:
1836 OctetString(value=value, bounds=(bound_min, bound_max))
1838 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1839 OctetString(bounds=(bound_min, bound_max)).decode(
1840 OctetString(value).encode()
1843 value = d.draw(binary(min_size=bound_max + 1))
1844 with self.assertRaises(BoundsError) as err:
1845 OctetString(value=value, bounds=(bound_min, bound_max))
1847 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1848 OctetString(bounds=(bound_min, bound_max)).decode(
1849 OctetString(value).encode()
1853 @given(data_strategy())
1854 def test_call(self, d):
1855 for klass in (OctetString, OctetStringInherited):
1864 ) = d.draw(octet_string_values_strategy())
1865 obj_initial = klass(
1871 optional_initial or False,
1882 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1883 if (default is None) and (obj_initial.default is not None):
1886 (bounds is None) and
1887 (value is not None) and
1888 (bounds_initial is not None) and
1889 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1893 (bounds is None) and
1894 (default is not None) and
1895 (bounds_initial is not None) and
1896 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1899 obj = obj_initial(value, bounds, impl, expl, default, optional)
1901 value_expected = default if value is None else value
1903 default_initial if value_expected is None
1906 self.assertEqual(obj, value_expected)
1907 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1908 self.assertEqual(obj.expl_tag, expl or expl_initial)
1911 default_initial if default is None else default,
1913 if obj.default is None:
1914 optional = optional_initial if optional is None else optional
1915 optional = False if optional is None else optional
1918 self.assertEqual(obj.optional, optional)
1920 (obj._bound_min, obj._bound_max),
1921 bounds or bounds_initial or (0, float("+inf")),
1924 @given(octet_string_values_strategy())
1925 def test_copy(self, values):
1926 for klass in (OctetString, OctetStringInherited):
1927 obj = klass(*values)
1928 obj_copied = obj.copy()
1929 self.assert_copied_basic_fields(obj, obj_copied)
1930 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1931 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1932 self.assertEqual(obj._value, obj_copied._value)
1936 integers(min_value=1).map(tag_encode),
1938 def test_stripped(self, value, tag_impl):
1939 obj = OctetString(value, impl=tag_impl)
1940 with self.assertRaises(NotEnoughData):
1941 obj.decode(obj.encode()[:-1])
1945 integers(min_value=1).map(tag_ctxc),
1947 def test_stripped_expl(self, value, tag_expl):
1948 obj = OctetString(value, expl=tag_expl)
1949 with self.assertRaises(NotEnoughData):
1950 obj.decode(obj.encode()[:-1])
1953 integers(min_value=31),
1954 integers(min_value=0),
1957 def test_bad_tag(self, tag, offset, decode_path):
1958 with self.assertRaises(DecodeError) as err:
1959 OctetString().decode(
1960 tag_encode(tag)[:-1],
1962 decode_path=decode_path,
1965 self.assertEqual(err.exception.offset, offset)
1966 self.assertEqual(err.exception.decode_path, decode_path)
1969 integers(min_value=128),
1970 integers(min_value=0),
1973 def test_bad_len(self, l, offset, decode_path):
1974 with self.assertRaises(DecodeError) as err:
1975 OctetString().decode(
1976 OctetString.tag_default + len_encode(l)[:-1],
1978 decode_path=decode_path,
1981 self.assertEqual(err.exception.offset, offset)
1982 self.assertEqual(err.exception.decode_path, decode_path)
1985 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1986 integers(min_value=0),
1989 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1990 value, bound_min = list(sorted(ints))
1992 class String(OctetString):
1993 bounds = (bound_min, bound_min)
1994 with self.assertRaises(DecodeError) as err:
1996 OctetString(b"\x00" * value).encode(),
1998 decode_path=decode_path,
2001 self.assertEqual(err.exception.offset, offset)
2002 self.assertEqual(err.exception.decode_path, decode_path)
2004 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2006 octet_string_values_strategy(),
2008 integers(min_value=1).map(tag_ctxc),
2009 integers(min_value=0),
2012 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2013 for klass in (OctetString, OctetStringInherited):
2014 _, _, _, _, default, optional, _decoded = values
2023 pprint(obj, big_blobs=True, with_decode_path=True)
2024 self.assertFalse(obj.expled)
2025 obj_encoded = obj.encode()
2026 obj_expled = obj(value, expl=tag_expl)
2027 self.assertTrue(obj_expled.expled)
2029 list(obj_expled.pps())
2030 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2031 obj_expled_encoded = obj_expled.encode()
2032 ctx_copied = deepcopy(ctx_dummy)
2033 obj_decoded, tail = obj_expled.decode(
2034 obj_expled_encoded + tail_junk,
2038 self.assertDictEqual(ctx_copied, ctx_dummy)
2040 list(obj_decoded.pps())
2041 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2042 self.assertEqual(tail, tail_junk)
2043 self.assertEqual(obj_decoded, obj_expled)
2044 self.assertNotEqual(obj_decoded, obj)
2045 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2046 self.assertEqual(bytes(obj_decoded), bytes(obj))
2047 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2048 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2049 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2051 obj_decoded.expl_llen,
2052 len(len_encode(len(obj_encoded))),
2054 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2055 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2058 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2060 self.assertEqual(obj_decoded.expl_offset, offset)
2063 integers(min_value=1, max_value=30),
2066 binary(min_size=1, max_size=5),
2068 binary(min_size=1, max_size=5),
2078 def test_constructed(self, impl, chunk_inputs, junk):
2079 def chunk_constructed(contents):
2081 tag_encode(form=TagFormConstructed, num=4) +
2083 b"".join(OctetString(content).encode() for content in contents) +
2087 payload_expected = b""
2088 for chunk_input in chunk_inputs:
2089 if isinstance(chunk_input, binary_type):
2090 chunks.append(OctetString(chunk_input).encode())
2091 payload_expected += chunk_input
2093 chunks.append(chunk_constructed(chunk_input))
2094 payload = b"".join(chunk_input)
2095 payload_expected += payload
2096 encoded_indefinite = (
2097 tag_encode(form=TagFormConstructed, num=impl) +
2102 encoded_definite = (
2103 tag_encode(form=TagFormConstructed, num=impl) +
2104 len_encode(len(b"".join(chunks))) +
2107 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2108 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2109 for lenindef_expected, encoded in (
2110 (True, encoded_indefinite),
2111 (False, encoded_definite),
2113 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2115 ctx={"bered": True},
2117 self.assertSequenceEqual(tail, junk)
2118 self.assertSequenceEqual(bytes(obj), payload_expected)
2119 self.assertTrue(obj.ber_encoded)
2120 self.assertEqual(obj.lenindef, lenindef_expected)
2121 self.assertTrue(obj.bered)
2123 self.assertTrue(obj.ber_encoded)
2124 self.assertEqual(obj.lenindef, lenindef_expected)
2125 self.assertTrue(obj.bered)
2126 self.assertEqual(len(encoded), obj.tlvlen)
2129 integers(min_value=0),
2132 def test_ber_definite_too_short(self, offset, decode_path):
2133 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2134 OctetString().decode(
2135 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2137 decode_path=decode_path,
2138 ctx={"bered": True},
2140 self.assertEqual(err.exception.decode_path, decode_path)
2141 self.assertEqual(err.exception.offset, offset)
2144 integers(min_value=0),
2146 integers(min_value=1, max_value=3),
2148 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2149 bs = OctetString(b"data").encode()
2150 with self.assertRaises(NotEnoughData) as err:
2151 OctetString().decode(
2152 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2154 decode_path=decode_path,
2155 ctx={"bered": True},
2157 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2158 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2161 integers(min_value=0),
2163 integers(min_value=1, max_value=3),
2165 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2166 bs = OctetString(b"data").encode()
2167 bs_longer = OctetString(b"data-longer").encode()
2168 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2169 OctetString().decode(
2171 tag_encode(4, form=TagFormConstructed) +
2172 len_encode((chunks + 1) * len(bs)) +
2177 decode_path=decode_path,
2178 ctx={"bered": True},
2180 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2181 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2185 def null_values_strategy(draw, do_expl=False):
2189 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2191 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2192 optional = draw(one_of(none(), booleans()))
2194 draw(integers(min_value=0)),
2195 draw(integers(min_value=0)),
2196 draw(integers(min_value=0)),
2198 return (impl, expl, optional, _decoded)
2201 class NullInherited(Null):
2205 class TestNull(CommonMixin, TestCase):
2208 def test_ready(self):
2210 self.assertTrue(obj.ready)
2213 pprint(obj, big_blobs=True, with_decode_path=True)
2215 @given(binary(), binary())
2216 def test_comparison(self, tag1, tag2):
2217 for klass in (Null, NullInherited):
2218 obj1 = klass(impl=tag1)
2219 obj2 = klass(impl=tag2)
2220 self.assertEqual(obj1 == obj2, tag1 == tag2)
2221 self.assertEqual(obj1 != obj2, tag1 != tag2)
2222 self.assertNotEqual(obj1, tag2)
2224 @given(data_strategy())
2225 def test_call(self, d):
2226 for klass in (Null, NullInherited):
2232 ) = d.draw(null_values_strategy())
2233 obj_initial = klass(
2236 optional=optional_initial or False,
2237 _decoded=_decoded_initial,
2244 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2245 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2246 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2247 self.assertEqual(obj.expl_tag, expl or expl_initial)
2248 optional = optional_initial if optional is None else optional
2249 optional = False if optional is None else optional
2250 self.assertEqual(obj.optional, optional)
2252 @given(null_values_strategy())
2253 def test_copy(self, values):
2254 for klass in (Null, NullInherited):
2255 impl, expl, optional, _decoded = values
2259 optional=optional or False,
2262 obj_copied = obj.copy()
2263 self.assert_copied_basic_fields(obj, obj_copied)
2265 @given(integers(min_value=1).map(tag_encode))
2266 def test_stripped(self, tag_impl):
2267 obj = Null(impl=tag_impl)
2268 with self.assertRaises(NotEnoughData):
2269 obj.decode(obj.encode()[:-1])
2271 @given(integers(min_value=1).map(tag_ctxc))
2272 def test_stripped_expl(self, tag_expl):
2273 obj = Null(expl=tag_expl)
2274 with self.assertRaises(NotEnoughData):
2275 obj.decode(obj.encode()[:-1])
2278 integers(min_value=31),
2279 integers(min_value=0),
2282 def test_bad_tag(self, tag, offset, decode_path):
2283 with self.assertRaises(DecodeError) as err:
2285 tag_encode(tag)[:-1],
2287 decode_path=decode_path,
2290 self.assertEqual(err.exception.offset, offset)
2291 self.assertEqual(err.exception.decode_path, decode_path)
2294 integers(min_value=128),
2295 integers(min_value=0),
2298 def test_bad_len(self, l, offset, decode_path):
2299 with self.assertRaises(DecodeError) as err:
2301 Null.tag_default + len_encode(l)[:-1],
2303 decode_path=decode_path,
2306 self.assertEqual(err.exception.offset, offset)
2307 self.assertEqual(err.exception.decode_path, decode_path)
2309 @given(binary(min_size=1))
2310 def test_tag_mismatch(self, impl):
2311 assume(impl != Null.tag_default)
2312 with self.assertRaises(TagMismatch):
2313 Null(impl=impl).decode(Null().encode())
2316 null_values_strategy(),
2317 integers(min_value=1).map(tag_ctxc),
2318 integers(min_value=0),
2321 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2322 for klass in (Null, NullInherited):
2323 _, _, optional, _decoded = values
2324 obj = klass(optional=optional, _decoded=_decoded)
2327 pprint(obj, big_blobs=True, with_decode_path=True)
2328 self.assertFalse(obj.expled)
2329 obj_encoded = obj.encode()
2330 obj_expled = obj(expl=tag_expl)
2331 self.assertTrue(obj_expled.expled)
2333 list(obj_expled.pps())
2334 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2335 obj_expled_encoded = obj_expled.encode()
2336 ctx_copied = deepcopy(ctx_dummy)
2337 obj_decoded, tail = obj_expled.decode(
2338 obj_expled_encoded + tail_junk,
2342 self.assertDictEqual(ctx_copied, ctx_dummy)
2344 list(obj_decoded.pps())
2345 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2346 self.assertEqual(tail, tail_junk)
2347 self.assertEqual(obj_decoded, obj_expled)
2348 self.assertNotEqual(obj_decoded, obj)
2349 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2350 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2351 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2353 obj_decoded.expl_llen,
2354 len(len_encode(len(obj_encoded))),
2356 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2357 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2360 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2362 self.assertEqual(obj_decoded.expl_offset, offset)
2364 @given(integers(min_value=1))
2365 def test_invalid_len(self, l):
2366 with self.assertRaises(InvalidLength):
2367 Null().decode(b"".join((
2374 def oid_strategy(draw):
2375 first_arc = draw(integers(min_value=0, max_value=2))
2377 if first_arc in (0, 1):
2378 second_arc = draw(integers(min_value=0, max_value=39))
2380 second_arc = draw(integers(min_value=0))
2381 other_arcs = draw(lists(integers(min_value=0)))
2382 return tuple([first_arc, second_arc] + other_arcs)
2386 def oid_values_strategy(draw, do_expl=False):
2387 value = draw(one_of(none(), oid_strategy()))
2391 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2393 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2394 default = draw(one_of(none(), oid_strategy()))
2395 optional = draw(one_of(none(), booleans()))
2397 draw(integers(min_value=0)),
2398 draw(integers(min_value=0)),
2399 draw(integers(min_value=0)),
2401 return (value, impl, expl, default, optional, _decoded)
2404 class ObjectIdentifierInherited(ObjectIdentifier):
2408 class TestObjectIdentifier(CommonMixin, TestCase):
2409 base_klass = ObjectIdentifier
2411 def test_invalid_value_type(self):
2412 with self.assertRaises(InvalidValueType) as err:
2413 ObjectIdentifier(123)
2417 def test_optional(self, optional):
2418 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2419 self.assertTrue(obj.optional)
2421 @given(oid_strategy())
2422 def test_ready(self, value):
2423 obj = ObjectIdentifier()
2424 self.assertFalse(obj.ready)
2427 pprint(obj, big_blobs=True, with_decode_path=True)
2428 with self.assertRaises(ObjNotReady) as err:
2431 obj = ObjectIdentifier(value)
2432 self.assertTrue(obj.ready)
2433 self.assertFalse(obj.ber_encoded)
2436 pprint(obj, big_blobs=True, with_decode_path=True)
2439 @given(oid_strategy(), oid_strategy(), binary(), binary())
2440 def test_comparison(self, value1, value2, tag1, tag2):
2441 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2442 obj1 = klass(value1)
2443 obj2 = klass(value2)
2444 self.assertEqual(obj1 == obj2, value1 == value2)
2445 self.assertEqual(obj1 != obj2, value1 != value2)
2446 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2447 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2448 obj1 = klass(value1, impl=tag1)
2449 obj2 = klass(value1, impl=tag2)
2450 self.assertEqual(obj1 == obj2, tag1 == tag2)
2451 self.assertEqual(obj1 != obj2, tag1 != tag2)
2453 @given(lists(oid_strategy()))
2454 def test_sorted_works(self, values):
2455 self.assertSequenceEqual(
2456 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2460 @given(data_strategy())
2461 def test_call(self, d):
2462 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2470 ) = d.draw(oid_values_strategy())
2471 obj_initial = klass(
2472 value=value_initial,
2475 default=default_initial,
2476 optional=optional_initial or False,
2477 _decoded=_decoded_initial,
2486 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2495 value_expected = default if value is None else value
2497 default_initial if value_expected is None
2500 self.assertEqual(obj, value_expected)
2501 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2502 self.assertEqual(obj.expl_tag, expl or expl_initial)
2505 default_initial if default is None else default,
2507 if obj.default is None:
2508 optional = optional_initial if optional is None else optional
2509 optional = False if optional is None else optional
2512 self.assertEqual(obj.optional, optional)
2514 @given(oid_values_strategy())
2515 def test_copy(self, values):
2516 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2533 obj_copied = obj.copy()
2534 self.assert_copied_basic_fields(obj, obj_copied)
2535 self.assertEqual(obj._value, obj_copied._value)
2537 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2540 integers(min_value=1).map(tag_encode),
2542 def test_stripped(self, value, tag_impl):
2543 obj = ObjectIdentifier(value, impl=tag_impl)
2544 with self.assertRaises(NotEnoughData):
2545 obj.decode(obj.encode()[:-1])
2549 integers(min_value=1).map(tag_ctxc),
2551 def test_stripped_expl(self, value, tag_expl):
2552 obj = ObjectIdentifier(value, expl=tag_expl)
2553 with self.assertRaises(NotEnoughData):
2554 obj.decode(obj.encode()[:-1])
2557 integers(min_value=31),
2558 integers(min_value=0),
2561 def test_bad_tag(self, tag, offset, decode_path):
2562 with self.assertRaises(DecodeError) as err:
2563 ObjectIdentifier().decode(
2564 tag_encode(tag)[:-1],
2566 decode_path=decode_path,
2569 self.assertEqual(err.exception.offset, offset)
2570 self.assertEqual(err.exception.decode_path, decode_path)
2573 integers(min_value=128),
2574 integers(min_value=0),
2577 def test_bad_len(self, l, offset, decode_path):
2578 with self.assertRaises(DecodeError) as err:
2579 ObjectIdentifier().decode(
2580 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2582 decode_path=decode_path,
2585 self.assertEqual(err.exception.offset, offset)
2586 self.assertEqual(err.exception.decode_path, decode_path)
2588 def test_zero_oid(self):
2589 with self.assertRaises(NotEnoughData):
2590 ObjectIdentifier().decode(
2591 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2594 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2595 @given(oid_strategy())
2596 def test_unfinished_oid(self, value):
2597 assume(list(value)[-1] > 255)
2598 obj_encoded = ObjectIdentifier(value).encode()
2599 obj, _ = ObjectIdentifier().decode(obj_encoded)
2600 data = obj_encoded[obj.tlen + obj.llen:-1]
2602 ObjectIdentifier.tag_default,
2603 len_encode(len(data)),
2606 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2609 @given(integers(min_value=0))
2610 def test_invalid_short(self, value):
2611 with self.assertRaises(InvalidOID):
2612 ObjectIdentifier((value,))
2613 with self.assertRaises(InvalidOID):
2614 ObjectIdentifier("%d" % value)
2616 @given(integers(min_value=3), integers(min_value=0))
2617 def test_invalid_first_arc(self, first_arc, second_arc):
2618 with self.assertRaises(InvalidOID):
2619 ObjectIdentifier((first_arc, second_arc))
2620 with self.assertRaises(InvalidOID):
2621 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2623 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2624 def test_invalid_second_arc(self, first_arc, second_arc):
2625 with self.assertRaises(InvalidOID):
2626 ObjectIdentifier((first_arc, second_arc))
2627 with self.assertRaises(InvalidOID):
2628 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2630 @given(text(alphabet=ascii_letters + ".", min_size=1))
2631 def test_junk(self, oid):
2632 with self.assertRaises(InvalidOID):
2633 ObjectIdentifier(oid)
2635 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2636 @given(oid_strategy())
2637 def test_validness(self, oid):
2638 obj = ObjectIdentifier(oid)
2639 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2642 pprint(obj, big_blobs=True, with_decode_path=True)
2644 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2646 oid_values_strategy(),
2648 integers(min_value=1).map(tag_ctxc),
2649 integers(min_value=0),
2652 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2653 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2654 _, _, _, default, optional, _decoded = values
2663 pprint(obj, big_blobs=True, with_decode_path=True)
2664 self.assertFalse(obj.expled)
2665 obj_encoded = obj.encode()
2666 obj_expled = obj(value, expl=tag_expl)
2667 self.assertTrue(obj_expled.expled)
2669 list(obj_expled.pps())
2670 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2671 obj_expled_encoded = obj_expled.encode()
2672 ctx_copied = deepcopy(ctx_dummy)
2673 obj_decoded, tail = obj_expled.decode(
2674 obj_expled_encoded + tail_junk,
2678 self.assertDictEqual(ctx_copied, ctx_dummy)
2680 list(obj_decoded.pps())
2681 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2682 self.assertEqual(tail, tail_junk)
2683 self.assertEqual(obj_decoded, obj_expled)
2684 self.assertNotEqual(obj_decoded, obj)
2685 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2686 self.assertEqual(tuple(obj_decoded), tuple(obj))
2687 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2688 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2689 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2691 obj_decoded.expl_llen,
2692 len(len_encode(len(obj_encoded))),
2694 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2695 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2698 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2700 self.assertEqual(obj_decoded.expl_offset, offset)
2703 oid_strategy().map(ObjectIdentifier),
2704 oid_strategy().map(ObjectIdentifier),
2706 def test_add(self, oid1, oid2):
2707 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2708 for oid_to_add in (oid2, tuple(oid2)):
2709 self.assertEqual(oid1 + oid_to_add, oid_expect)
2710 with self.assertRaises(InvalidValueType):
2713 def test_go_vectors_valid(self):
2714 for data, expect in (
2716 (b"\x55\x02", (2, 5, 2)),
2717 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2718 (b"\x81\x34\x03", (2, 100, 3)),
2721 ObjectIdentifier().decode(b"".join((
2722 ObjectIdentifier.tag_default,
2723 len_encode(len(data)),
2729 def test_go_vectors_invalid(self):
2730 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2731 with self.assertRaises(DecodeError):
2732 ObjectIdentifier().decode(b"".join((
2733 Integer.tag_default,
2734 len_encode(len(data)),
2738 def test_x690_vector(self):
2740 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2741 ObjectIdentifier((2, 999, 3)),
2744 @given(data_strategy())
2745 def test_nonnormalized_first_arc(self, d):
2747 ObjectIdentifier.tag_default +
2750 ObjectIdentifier((1, 0)).encode()[-1:]
2752 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2753 self.assertTrue(obj.ber_encoded)
2754 self.assertTrue(obj.bered)
2756 self.assertTrue(obj.ber_encoded)
2757 self.assertTrue(obj.bered)
2758 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2759 ObjectIdentifier().decode(tampered)
2761 @given(data_strategy())
2762 def test_nonnormalized_arcs(self, d):
2763 arcs = d.draw(lists(
2764 integers(min_value=0, max_value=100),
2768 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2769 _, tlen, lv = tag_strip(dered)
2770 _, llen, v = len_decode(lv)
2771 v_no_first_arc = v[1:]
2772 idx_for_tamper = d.draw(integers(
2774 max_value=len(v_no_first_arc) - 1,
2776 tampered = list(bytearray(v_no_first_arc))
2777 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2778 tampered.insert(idx_for_tamper, 0x80)
2779 tampered = bytes(bytearray(tampered))
2781 ObjectIdentifier.tag_default +
2782 len_encode(len(tampered)) +
2785 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2786 self.assertTrue(obj.ber_encoded)
2787 self.assertTrue(obj.bered)
2789 self.assertTrue(obj.ber_encoded)
2790 self.assertTrue(obj.bered)
2791 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2792 ObjectIdentifier().decode(tampered)
2796 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2798 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2799 values = list(draw(sets(
2801 min_size=len(schema),
2802 max_size=len(schema),
2804 schema = list(zip(schema, values))
2805 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2809 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2811 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2812 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2813 optional = draw(one_of(none(), booleans()))
2815 draw(integers(min_value=0)),
2816 draw(integers(min_value=0)),
2817 draw(integers(min_value=0)),
2819 return (schema, value, impl, expl, default, optional, _decoded)
2822 class TestEnumerated(CommonMixin, TestCase):
2823 class EWhatever(Enumerated):
2824 schema = (("whatever", 0),)
2826 base_klass = EWhatever
2828 def test_schema_required(self):
2829 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2832 def test_invalid_value_type(self):
2833 with self.assertRaises(InvalidValueType) as err:
2834 self.base_klass((1, 2))
2837 @given(sets(text_letters(), min_size=2))
2838 def test_unknown_name(self, schema_input):
2839 missing = schema_input.pop()
2841 class E(Enumerated):
2842 schema = [(n, 123) for n in schema_input]
2843 with self.assertRaises(ObjUnknown) as err:
2848 sets(text_letters(), min_size=2),
2849 sets(integers(), min_size=2),
2851 def test_unknown_value(self, schema_input, values_input):
2853 missing_value = values_input.pop()
2854 _input = list(zip(schema_input, values_input))
2856 class E(Enumerated):
2858 with self.assertRaises(DecodeError) as err:
2863 def test_optional(self, optional):
2864 obj = self.base_klass(default="whatever", optional=optional)
2865 self.assertTrue(obj.optional)
2867 def test_ready(self):
2868 obj = self.base_klass()
2869 self.assertFalse(obj.ready)
2872 pprint(obj, big_blobs=True, with_decode_path=True)
2873 with self.assertRaises(ObjNotReady) as err:
2876 obj = self.base_klass("whatever")
2877 self.assertTrue(obj.ready)
2880 pprint(obj, big_blobs=True, with_decode_path=True)
2882 @given(integers(), integers(), binary(), binary())
2883 def test_comparison(self, value1, value2, tag1, tag2):
2884 class E(Enumerated):
2886 ("whatever0", value1),
2887 ("whatever1", value2),
2890 class EInherited(E):
2892 for klass in (E, EInherited):
2893 obj1 = klass(value1)
2894 obj2 = klass(value2)
2895 self.assertEqual(obj1 == obj2, value1 == value2)
2896 self.assertEqual(obj1 != obj2, value1 != value2)
2897 self.assertEqual(obj1 == int(obj2), value1 == value2)
2898 obj1 = klass(value1, impl=tag1)
2899 obj2 = klass(value1, impl=tag2)
2900 self.assertEqual(obj1 == obj2, tag1 == tag2)
2901 self.assertEqual(obj1 != obj2, tag1 != tag2)
2903 @given(data_strategy())
2904 def test_call(self, d):
2913 ) = d.draw(enumerated_values_strategy())
2915 class E(Enumerated):
2916 schema = schema_initial
2918 value=value_initial,
2921 default=default_initial,
2922 optional=optional_initial or False,
2923 _decoded=_decoded_initial,
2933 ) = d.draw(enumerated_values_strategy(
2934 schema=schema_initial,
2935 do_expl=impl_initial is None,
2945 value_expected = default if value is None else value
2947 default_initial if value_expected is None
2952 dict(schema_initial).get(value_expected, value_expected),
2954 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2955 self.assertEqual(obj.expl_tag, expl or expl_initial)
2958 default_initial if default is None else default,
2960 if obj.default is None:
2961 optional = optional_initial if optional is None else optional
2962 optional = False if optional is None else optional
2965 self.assertEqual(obj.optional, optional)
2966 self.assertEqual(obj.specs, dict(schema_initial))
2968 @given(enumerated_values_strategy())
2969 def test_copy(self, values):
2970 schema_input, value, impl, expl, default, optional, _decoded = values
2972 class E(Enumerated):
2973 schema = schema_input
2982 obj_copied = obj.copy()
2983 self.assert_copied_basic_fields(obj, obj_copied)
2984 self.assertEqual(obj.specs, obj_copied.specs)
2986 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2987 @given(data_strategy())
2988 def test_symmetric(self, d):
2989 schema_input, _, _, _, default, optional, _decoded = d.draw(
2990 enumerated_values_strategy(),
2992 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2993 offset = d.draw(integers(min_value=0))
2994 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2995 tail_junk = d.draw(binary(max_size=5))
2997 class E(Enumerated):
2998 schema = schema_input
3007 pprint(obj, big_blobs=True, with_decode_path=True)
3008 self.assertFalse(obj.expled)
3009 obj_encoded = obj.encode()
3010 obj_expled = obj(value, expl=tag_expl)
3011 self.assertTrue(obj_expled.expled)
3013 list(obj_expled.pps())
3014 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3015 obj_expled_encoded = obj_expled.encode()
3016 ctx_copied = deepcopy(ctx_dummy)
3017 obj_decoded, tail = obj_expled.decode(
3018 obj_expled_encoded + tail_junk,
3022 self.assertDictEqual(ctx_copied, ctx_dummy)
3024 list(obj_decoded.pps())
3025 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3026 self.assertEqual(tail, tail_junk)
3027 self.assertEqual(obj_decoded, obj_expled)
3028 self.assertNotEqual(obj_decoded, obj)
3029 self.assertEqual(int(obj_decoded), int(obj_expled))
3030 self.assertEqual(int(obj_decoded), int(obj))
3031 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3032 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3033 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3035 obj_decoded.expl_llen,
3036 len(len_encode(len(obj_encoded))),
3038 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3039 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3042 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3044 self.assertEqual(obj_decoded.expl_offset, offset)
3048 def string_values_strategy(draw, alphabet, do_expl=False):
3049 bound_min, bound_max = sorted(draw(sets(
3050 integers(min_value=0, max_value=1 << 7),
3054 value = draw(one_of(
3056 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3058 default = draw(one_of(
3060 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3063 if draw(booleans()):
3064 bounds = (bound_min, bound_max)
3068 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3070 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3071 optional = draw(one_of(none(), booleans()))
3073 draw(integers(min_value=0)),
3074 draw(integers(min_value=0)),
3075 draw(integers(min_value=0)),
3077 return (value, bounds, impl, expl, default, optional, _decoded)
3080 class StringMixin(object):
3081 def test_invalid_value_type(self):
3082 with self.assertRaises(InvalidValueType) as err:
3083 self.base_klass((1, 2))
3086 def text_alphabet(self):
3087 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3088 return printable + whitespace
3092 def test_optional(self, optional):
3093 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3094 self.assertTrue(obj.optional)
3096 @given(data_strategy())
3097 def test_ready(self, d):
3098 obj = self.base_klass()
3099 self.assertFalse(obj.ready)
3102 pprint(obj, big_blobs=True, with_decode_path=True)
3104 with self.assertRaises(ObjNotReady) as err:
3107 value = d.draw(text(alphabet=self.text_alphabet()))
3108 obj = self.base_klass(value)
3109 self.assertTrue(obj.ready)
3112 pprint(obj, big_blobs=True, with_decode_path=True)
3115 @given(data_strategy())
3116 def test_comparison(self, d):
3117 value1 = d.draw(text(alphabet=self.text_alphabet()))
3118 value2 = d.draw(text(alphabet=self.text_alphabet()))
3119 tag1 = d.draw(binary(min_size=1))
3120 tag2 = d.draw(binary(min_size=1))
3121 obj1 = self.base_klass(value1)
3122 obj2 = self.base_klass(value2)
3123 self.assertEqual(obj1 == obj2, value1 == value2)
3124 self.assertEqual(obj1 != obj2, value1 != value2)
3125 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3126 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3127 obj1 = self.base_klass(value1, impl=tag1)
3128 obj2 = self.base_klass(value1, impl=tag2)
3129 self.assertEqual(obj1 == obj2, tag1 == tag2)
3130 self.assertEqual(obj1 != obj2, tag1 != tag2)
3132 @given(data_strategy())
3133 def test_bounds_satisfied(self, d):
3134 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3135 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3136 value = d.draw(text(
3137 alphabet=self.text_alphabet(),
3141 self.base_klass(value=value, bounds=(bound_min, bound_max))
3143 @given(data_strategy())
3144 def test_bounds_unsatisfied(self, d):
3145 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3146 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3147 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3148 with self.assertRaises(BoundsError) as err:
3149 self.base_klass(value=value, bounds=(bound_min, bound_max))
3151 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3152 self.base_klass(bounds=(bound_min, bound_max)).decode(
3153 self.base_klass(value).encode()
3156 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3157 with self.assertRaises(BoundsError) as err:
3158 self.base_klass(value=value, bounds=(bound_min, bound_max))
3160 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3161 self.base_klass(bounds=(bound_min, bound_max)).decode(
3162 self.base_klass(value).encode()
3166 @given(data_strategy())
3167 def test_call(self, d):
3176 ) = d.draw(string_values_strategy(self.text_alphabet()))
3177 obj_initial = self.base_klass(
3183 optional_initial or False,
3194 ) = d.draw(string_values_strategy(
3195 self.text_alphabet(),
3196 do_expl=impl_initial is None,
3198 if (default is None) and (obj_initial.default is not None):
3201 (bounds is None) and
3202 (value is not None) and
3203 (bounds_initial is not None) and
3204 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3208 (bounds is None) and
3209 (default is not None) and
3210 (bounds_initial is not None) and
3211 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3214 obj = obj_initial(value, bounds, impl, expl, default, optional)
3216 value_expected = default if value is None else value
3218 default_initial if value_expected is None
3221 self.assertEqual(obj, value_expected)
3222 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3223 self.assertEqual(obj.expl_tag, expl or expl_initial)
3226 default_initial if default is None else default,
3228 if obj.default is None:
3229 optional = optional_initial if optional is None else optional
3230 optional = False if optional is None else optional
3233 self.assertEqual(obj.optional, optional)
3235 (obj._bound_min, obj._bound_max),
3236 bounds or bounds_initial or (0, float("+inf")),
3239 @given(data_strategy())
3240 def test_copy(self, d):
3241 values = d.draw(string_values_strategy(self.text_alphabet()))
3242 obj = self.base_klass(*values)
3243 obj_copied = obj.copy()
3244 self.assert_copied_basic_fields(obj, obj_copied)
3245 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3246 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3247 self.assertEqual(obj._value, obj_copied._value)
3249 @given(data_strategy())
3250 def test_stripped(self, d):
3251 value = d.draw(text(alphabet=self.text_alphabet()))
3252 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3253 obj = self.base_klass(value, impl=tag_impl)
3254 with self.assertRaises(NotEnoughData):
3255 obj.decode(obj.encode()[:-1])
3257 @given(data_strategy())
3258 def test_stripped_expl(self, d):
3259 value = d.draw(text(alphabet=self.text_alphabet()))
3260 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3261 obj = self.base_klass(value, expl=tag_expl)
3262 with self.assertRaises(NotEnoughData):
3263 obj.decode(obj.encode()[:-1])
3266 integers(min_value=31),
3267 integers(min_value=0),
3270 def test_bad_tag(self, tag, offset, decode_path):
3271 with self.assertRaises(DecodeError) as err:
3272 self.base_klass().decode(
3273 tag_encode(tag)[:-1],
3275 decode_path=decode_path,
3278 self.assertEqual(err.exception.offset, offset)
3279 self.assertEqual(err.exception.decode_path, decode_path)
3282 integers(min_value=128),
3283 integers(min_value=0),
3286 def test_bad_len(self, l, offset, decode_path):
3287 with self.assertRaises(DecodeError) as err:
3288 self.base_klass().decode(
3289 self.base_klass.tag_default + len_encode(l)[:-1],
3291 decode_path=decode_path,
3294 self.assertEqual(err.exception.offset, offset)
3295 self.assertEqual(err.exception.decode_path, decode_path)
3298 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3299 integers(min_value=0),
3302 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3303 value, bound_min = list(sorted(ints))
3305 class String(self.base_klass):
3306 # Multiply this value by four, to satisfy UTF-32 bounds
3307 # (4 bytes per character) validation
3308 bounds = (bound_min * 4, bound_min * 4)
3309 with self.assertRaises(DecodeError) as err:
3311 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3313 decode_path=decode_path,
3316 self.assertEqual(err.exception.offset, offset)
3317 self.assertEqual(err.exception.decode_path, decode_path)
3319 @given(data_strategy())
3320 def test_symmetric(self, d):
3321 values = d.draw(string_values_strategy(self.text_alphabet()))
3322 value = d.draw(text(alphabet=self.text_alphabet()))
3323 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3324 offset = d.draw(integers(min_value=0))
3325 tail_junk = d.draw(binary(max_size=5))
3326 _, _, _, _, default, optional, _decoded = values
3327 obj = self.base_klass(
3335 pprint(obj, big_blobs=True, with_decode_path=True)
3336 self.assertFalse(obj.expled)
3337 obj_encoded = obj.encode()
3338 obj_expled = obj(value, expl=tag_expl)
3339 self.assertTrue(obj_expled.expled)
3341 list(obj_expled.pps())
3342 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3343 obj_expled_encoded = obj_expled.encode()
3344 ctx_copied = deepcopy(ctx_dummy)
3345 obj_decoded, tail = obj_expled.decode(
3346 obj_expled_encoded + tail_junk,
3350 self.assertDictEqual(ctx_copied, ctx_dummy)
3352 list(obj_decoded.pps())
3353 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3354 self.assertEqual(tail, tail_junk)
3355 self.assertEqual(obj_decoded, obj_expled)
3356 self.assertNotEqual(obj_decoded, obj)
3357 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3358 self.assertEqual(bytes(obj_decoded), bytes(obj))
3359 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3360 self.assertEqual(text_type(obj_decoded), text_type(obj))
3361 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3362 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3363 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3365 obj_decoded.expl_llen,
3366 len(len_encode(len(obj_encoded))),
3368 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3369 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3372 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3374 self.assertEqual(obj_decoded.expl_offset, offset)
3377 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3378 base_klass = UTF8String
3381 cyrillic_letters = text(
3382 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3388 class UnicodeDecodeErrorMixin(object):
3389 @given(cyrillic_letters)
3390 def test_unicode_decode_error(self, cyrillic_text):
3391 with self.assertRaises(DecodeError):
3392 self.base_klass(cyrillic_text)
3395 class TestNumericString(StringMixin, CommonMixin, TestCase):
3396 base_klass = NumericString
3398 def text_alphabet(self):
3401 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3402 def test_non_numeric(self, non_numeric_text):
3403 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3404 self.base_klass(non_numeric_text)
3407 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3408 integers(min_value=0),
3411 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3412 value, bound_min = list(sorted(ints))
3414 class String(self.base_klass):
3415 bounds = (bound_min, bound_min)
3416 with self.assertRaises(DecodeError) as err:
3418 self.base_klass(b"1" * value).encode(),
3420 decode_path=decode_path,
3423 self.assertEqual(err.exception.offset, offset)
3424 self.assertEqual(err.exception.decode_path, decode_path)
3427 class TestPrintableString(
3428 UnicodeDecodeErrorMixin,
3433 base_klass = PrintableString
3435 def text_alphabet(self):
3436 return ascii_letters + digits + " '()+,-./:=?"
3438 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3439 def test_non_printable(self, non_printable_text):
3440 with assertRaisesRegex(self, DecodeError, "non-printable"):
3441 self.base_klass(non_printable_text)
3444 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3445 integers(min_value=0),
3448 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3449 value, bound_min = list(sorted(ints))
3451 class String(self.base_klass):
3452 bounds = (bound_min, bound_min)
3453 with self.assertRaises(DecodeError) as err:
3455 self.base_klass(b"1" * value).encode(),
3457 decode_path=decode_path,
3460 self.assertEqual(err.exception.offset, offset)
3461 self.assertEqual(err.exception.decode_path, decode_path)
3464 class TestTeletexString(
3465 UnicodeDecodeErrorMixin,
3470 base_klass = TeletexString
3473 class TestVideotexString(
3474 UnicodeDecodeErrorMixin,
3479 base_klass = VideotexString
3482 class TestIA5String(
3483 UnicodeDecodeErrorMixin,
3488 base_klass = IA5String
3491 class TestGraphicString(
3492 UnicodeDecodeErrorMixin,
3497 base_klass = GraphicString
3500 class TestVisibleString(
3501 UnicodeDecodeErrorMixin,
3506 base_klass = VisibleString
3508 def test_x690_vector(self):
3509 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3510 self.assertSequenceEqual(tail, b"")
3511 self.assertEqual(str(obj), "Jones")
3512 self.assertFalse(obj.ber_encoded)
3513 self.assertFalse(obj.lenindef)
3514 self.assertFalse(obj.bered)
3516 obj, tail = VisibleString().decode(
3517 hexdec("3A0904034A6F6E04026573"),
3518 ctx={"bered": True},
3520 self.assertSequenceEqual(tail, b"")
3521 self.assertEqual(str(obj), "Jones")
3522 self.assertTrue(obj.ber_encoded)
3523 self.assertFalse(obj.lenindef)
3524 self.assertTrue(obj.bered)
3526 self.assertTrue(obj.ber_encoded)
3527 self.assertFalse(obj.lenindef)
3528 self.assertTrue(obj.bered)
3530 obj, tail = VisibleString().decode(
3531 hexdec("3A8004034A6F6E040265730000"),
3532 ctx={"bered": True},
3534 self.assertSequenceEqual(tail, b"")
3535 self.assertEqual(str(obj), "Jones")
3536 self.assertTrue(obj.ber_encoded)
3537 self.assertTrue(obj.lenindef)
3538 self.assertTrue(obj.bered)
3540 self.assertTrue(obj.ber_encoded)
3541 self.assertTrue(obj.lenindef)
3542 self.assertTrue(obj.bered)
3545 class TestGeneralString(
3546 UnicodeDecodeErrorMixin,
3551 base_klass = GeneralString
3554 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3555 base_klass = UniversalString
3558 class TestBMPString(StringMixin, CommonMixin, TestCase):
3559 base_klass = BMPString
3563 def generalized_time_values_strategy(
3571 if draw(booleans()):
3572 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3574 value = value.replace(microsecond=0)
3576 if draw(booleans()):
3577 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3579 default = default.replace(microsecond=0)
3583 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3585 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3586 optional = draw(one_of(none(), booleans()))
3588 draw(integers(min_value=0)),
3589 draw(integers(min_value=0)),
3590 draw(integers(min_value=0)),
3592 return (value, impl, expl, default, optional, _decoded)
3595 class TimeMixin(object):
3596 def test_invalid_value_type(self):
3597 with self.assertRaises(InvalidValueType) as err:
3598 self.base_klass(datetime.now().timetuple())
3601 @given(data_strategy())
3602 def test_optional(self, d):
3603 default = d.draw(datetimes(
3604 min_value=self.min_datetime,
3605 max_value=self.max_datetime,
3607 optional = d.draw(booleans())
3608 obj = self.base_klass(default=default, optional=optional)
3609 self.assertTrue(obj.optional)
3611 @given(data_strategy())
3612 def test_ready(self, d):
3613 obj = self.base_klass()
3614 self.assertFalse(obj.ready)
3617 pprint(obj, big_blobs=True, with_decode_path=True)
3618 with self.assertRaises(ObjNotReady) as err:
3621 value = d.draw(datetimes(min_value=self.min_datetime))
3622 obj = self.base_klass(value)
3623 self.assertTrue(obj.ready)
3626 pprint(obj, big_blobs=True, with_decode_path=True)
3628 @given(data_strategy())
3629 def test_comparison(self, d):
3630 value1 = d.draw(datetimes(
3631 min_value=self.min_datetime,
3632 max_value=self.max_datetime,
3634 value2 = d.draw(datetimes(
3635 min_value=self.min_datetime,
3636 max_value=self.max_datetime,
3638 tag1 = d.draw(binary(min_size=1))
3639 tag2 = d.draw(binary(min_size=1))
3641 value1 = value1.replace(microsecond=0)
3642 value2 = value2.replace(microsecond=0)
3643 obj1 = self.base_klass(value1)
3644 obj2 = self.base_klass(value2)
3645 self.assertEqual(obj1 == obj2, value1 == value2)
3646 self.assertEqual(obj1 != obj2, value1 != value2)
3647 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3648 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3649 obj1 = self.base_klass(value1, impl=tag1)
3650 obj2 = self.base_klass(value1, impl=tag2)
3651 self.assertEqual(obj1 == obj2, tag1 == tag2)
3652 self.assertEqual(obj1 != obj2, tag1 != tag2)
3654 @given(data_strategy())
3655 def test_call(self, d):
3663 ) = d.draw(generalized_time_values_strategy(
3664 min_datetime=self.min_datetime,
3665 max_datetime=self.max_datetime,
3666 omit_ms=self.omit_ms,
3668 obj_initial = self.base_klass(
3669 value=value_initial,
3672 default=default_initial,
3673 optional=optional_initial or False,
3674 _decoded=_decoded_initial,
3683 ) = d.draw(generalized_time_values_strategy(
3684 min_datetime=self.min_datetime,
3685 max_datetime=self.max_datetime,
3686 omit_ms=self.omit_ms,
3687 do_expl=impl_initial is None,
3697 value_expected = default if value is None else value
3699 default_initial if value_expected is None
3702 self.assertEqual(obj, value_expected)
3703 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3704 self.assertEqual(obj.expl_tag, expl or expl_initial)
3707 default_initial if default is None else default,
3709 if obj.default is None:
3710 optional = optional_initial if optional is None else optional
3711 optional = False if optional is None else optional
3714 self.assertEqual(obj.optional, optional)
3716 @given(data_strategy())
3717 def test_copy(self, d):
3718 values = d.draw(generalized_time_values_strategy(
3719 min_datetime=self.min_datetime,
3720 max_datetime=self.max_datetime,
3722 obj = self.base_klass(*values)
3723 obj_copied = obj.copy()
3724 self.assert_copied_basic_fields(obj, obj_copied)
3725 self.assertEqual(obj._value, obj_copied._value)
3727 @given(data_strategy())
3728 def test_stripped(self, d):
3729 value = d.draw(datetimes(
3730 min_value=self.min_datetime,
3731 max_value=self.max_datetime,
3733 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3734 obj = self.base_klass(value, impl=tag_impl)
3735 with self.assertRaises(NotEnoughData):
3736 obj.decode(obj.encode()[:-1])
3738 @given(data_strategy())
3739 def test_stripped_expl(self, d):
3740 value = d.draw(datetimes(
3741 min_value=self.min_datetime,
3742 max_value=self.max_datetime,
3744 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3745 obj = self.base_klass(value, expl=tag_expl)
3746 with self.assertRaises(NotEnoughData):
3747 obj.decode(obj.encode()[:-1])
3749 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3750 @given(data_strategy())
3751 def test_symmetric(self, d):
3752 values = d.draw(generalized_time_values_strategy(
3753 min_datetime=self.min_datetime,
3754 max_datetime=self.max_datetime,
3756 value = d.draw(datetimes(
3757 min_value=self.min_datetime,
3758 max_value=self.max_datetime,
3760 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3761 offset = d.draw(integers(min_value=0))
3762 tail_junk = d.draw(binary(max_size=5))
3763 _, _, _, default, optional, _decoded = values
3764 obj = self.base_klass(
3772 pprint(obj, big_blobs=True, with_decode_path=True)
3773 self.assertFalse(obj.expled)
3774 obj_encoded = obj.encode()
3775 self.additional_symmetric_check(value, obj_encoded)
3776 obj_expled = obj(value, expl=tag_expl)
3777 self.assertTrue(obj_expled.expled)
3779 list(obj_expled.pps())
3780 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3781 obj_expled_encoded = obj_expled.encode()
3782 ctx_copied = deepcopy(ctx_dummy)
3783 obj_decoded, tail = obj_expled.decode(
3784 obj_expled_encoded + tail_junk,
3788 self.assertDictEqual(ctx_copied, ctx_dummy)
3790 list(obj_decoded.pps())
3791 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3792 self.assertEqual(tail, tail_junk)
3793 self.assertEqual(obj_decoded, obj_expled)
3794 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3795 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3796 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3797 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3798 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3800 obj_decoded.expl_llen,
3801 len(len_encode(len(obj_encoded))),
3803 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3804 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3807 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3809 self.assertEqual(obj_decoded.expl_offset, offset)
3812 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3813 base_klass = GeneralizedTime
3815 min_datetime = datetime(1900, 1, 1)
3816 max_datetime = datetime(9999, 12, 31)
3818 def additional_symmetric_check(self, value, obj_encoded):
3819 if value.microsecond > 0:
3820 self.assertFalse(obj_encoded.endswith(b"0Z"))
3822 def test_x690_vector_valid(self):
3826 b"19920722132100.3Z",
3828 GeneralizedTime(data)
3830 def test_x690_vector_invalid(self):
3833 b"19920622123421.0Z",
3834 b"19920722132100.30Z",
3836 with self.assertRaises(DecodeError) as err:
3837 GeneralizedTime(data)
3840 def test_go_vectors_invalid(self):
3852 b"-20100102030410Z",
3853 b"2010-0102030410Z",
3854 b"2010-0002030410Z",
3855 b"201001-02030410Z",
3856 b"20100102-030410Z",
3857 b"2010010203-0410Z",
3858 b"201001020304-10Z",
3859 # These ones are INVALID in *DER*, but accepted
3860 # by Go's encoding/asn1
3861 b"20100102030405+0607",
3862 b"20100102030405-0607",
3864 with self.assertRaises(DecodeError) as err:
3865 GeneralizedTime(data)
3868 def test_go_vectors_valid(self):
3870 GeneralizedTime(b"20100102030405Z").todatetime(),
3871 datetime(2010, 1, 2, 3, 4, 5, 0),
3876 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3877 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3879 binary(min_size=1, max_size=1),
3881 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3882 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3885 def test_junk(self, part0, part1, part2):
3886 junk = part0 + part1 + part2
3887 assume(not (set(junk) <= set(digits.encode("ascii"))))
3888 with self.assertRaises(DecodeError):
3889 GeneralizedTime().decode(
3890 GeneralizedTime.tag_default +
3891 len_encode(len(junk)) +
3897 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3898 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3900 binary(min_size=1, max_size=1),
3902 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3903 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3906 def test_junk_dm(self, part0, part1, part2):
3907 junk = part0 + part1 + part2
3908 assume(not (set(junk) <= set(digits.encode("ascii"))))
3909 with self.assertRaises(DecodeError):
3910 GeneralizedTime().decode(
3911 GeneralizedTime.tag_default +
3912 len_encode(len(junk)) +
3916 def test_ns_fractions(self):
3917 GeneralizedTime(b"20010101000000.000001Z")
3918 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
3919 GeneralizedTime(b"20010101000000.0000001Z")
3922 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3923 base_klass = UTCTime
3925 min_datetime = datetime(2000, 1, 1)
3926 max_datetime = datetime(2049, 12, 31)
3928 def additional_symmetric_check(self, value, obj_encoded):
3931 def test_x690_vector_valid(self):
3939 def test_x690_vector_invalid(self):
3944 with self.assertRaises(DecodeError) as err:
3948 def test_go_vectors_invalid(self):
3974 # These ones are INVALID in *DER*, but accepted
3975 # by Go's encoding/asn1
3976 b"910506164540-0700",
3977 b"910506164540+0730",
3981 with self.assertRaises(DecodeError) as err:
3985 def test_go_vectors_valid(self):
3987 UTCTime(b"910506234540Z").todatetime(),
3988 datetime(1991, 5, 6, 23, 45, 40, 0),
3991 @given(integers(min_value=0, max_value=49))
3992 def test_pre50(self, year):
3994 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3998 @given(integers(min_value=50, max_value=99))
3999 def test_post50(self, year):
4001 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4007 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4008 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4010 binary(min_size=1, max_size=1),
4012 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4013 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4016 def test_junk(self, part0, part1, part2):
4017 junk = part0 + part1 + part2
4018 assume(not (set(junk) <= set(digits.encode("ascii"))))
4019 with self.assertRaises(DecodeError):
4021 UTCTime.tag_default +
4022 len_encode(len(junk)) +
4028 def any_values_strategy(draw, do_expl=False):
4029 value = draw(one_of(none(), binary()))
4032 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4033 optional = draw(one_of(none(), booleans()))
4035 draw(integers(min_value=0)),
4036 draw(integers(min_value=0)),
4037 draw(integers(min_value=0)),
4039 return (value, expl, optional, _decoded)
4042 class AnyInherited(Any):
4046 class TestAny(CommonMixin, TestCase):
4049 def test_invalid_value_type(self):
4050 with self.assertRaises(InvalidValueType) as err:
4055 def test_optional(self, optional):
4056 obj = Any(optional=optional)
4057 self.assertEqual(obj.optional, optional)
4060 def test_ready(self, value):
4062 self.assertFalse(obj.ready)
4065 pprint(obj, big_blobs=True, with_decode_path=True)
4066 with self.assertRaises(ObjNotReady) as err:
4070 self.assertTrue(obj.ready)
4073 pprint(obj, big_blobs=True, with_decode_path=True)
4076 def test_basic(self, value):
4077 integer_encoded = Integer(value).encode()
4079 Any(integer_encoded),
4080 Any(Integer(value)),
4081 Any(Any(Integer(value))),
4083 self.assertSequenceEqual(bytes(obj), integer_encoded)
4085 obj.decode(obj.encode())[0].vlen,
4086 len(integer_encoded),
4090 pprint(obj, big_blobs=True, with_decode_path=True)
4091 self.assertSequenceEqual(obj.encode(), integer_encoded)
4093 @given(binary(), binary())
4094 def test_comparison(self, value1, value2):
4095 for klass in (Any, AnyInherited):
4096 obj1 = klass(value1)
4097 obj2 = klass(value2)
4098 self.assertEqual(obj1 == obj2, value1 == value2)
4099 self.assertEqual(obj1 != obj2, value1 != value2)
4100 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4102 @given(data_strategy())
4103 def test_call(self, d):
4104 for klass in (Any, AnyInherited):
4110 ) = d.draw(any_values_strategy())
4111 obj_initial = klass(
4114 optional_initial or False,
4122 ) = d.draw(any_values_strategy(do_expl=True))
4123 obj = obj_initial(value, expl, optional)
4125 value_expected = None if value is None else value
4126 self.assertEqual(obj, value_expected)
4127 self.assertEqual(obj.expl_tag, expl or expl_initial)
4128 if obj.default is None:
4129 optional = optional_initial if optional is None else optional
4130 optional = False if optional is None else optional
4131 self.assertEqual(obj.optional, optional)
4133 def test_simultaneous_impl_expl(self):
4134 # override it, as Any does not have implicit tag
4137 def test_decoded(self):
4138 # override it, as Any does not have implicit tag
4141 @given(any_values_strategy())
4142 def test_copy(self, values):
4143 for klass in (Any, AnyInherited):
4144 obj = klass(*values)
4145 obj_copied = obj.copy()
4146 self.assert_copied_basic_fields(obj, obj_copied)
4147 self.assertEqual(obj._value, obj_copied._value)
4149 @given(binary().map(OctetString))
4150 def test_stripped(self, value):
4152 with self.assertRaises(NotEnoughData):
4153 obj.decode(obj.encode()[:-1])
4157 integers(min_value=1).map(tag_ctxc),
4159 def test_stripped_expl(self, value, tag_expl):
4160 obj = Any(value, expl=tag_expl)
4161 with self.assertRaises(NotEnoughData):
4162 obj.decode(obj.encode()[:-1])
4165 integers(min_value=31),
4166 integers(min_value=0),
4169 def test_bad_tag(self, tag, offset, decode_path):
4170 with self.assertRaises(DecodeError) as err:
4172 tag_encode(tag)[:-1],
4174 decode_path=decode_path,
4177 self.assertEqual(err.exception.offset, offset)
4178 self.assertEqual(err.exception.decode_path, decode_path)
4181 integers(min_value=128),
4182 integers(min_value=0),
4185 def test_bad_len(self, l, offset, decode_path):
4186 with self.assertRaises(DecodeError) as err:
4188 Any.tag_default + len_encode(l)[:-1],
4190 decode_path=decode_path,
4193 self.assertEqual(err.exception.offset, offset)
4194 self.assertEqual(err.exception.decode_path, decode_path)
4196 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4198 any_values_strategy(),
4199 integers().map(lambda x: Integer(x).encode()),
4200 integers(min_value=1).map(tag_ctxc),
4201 integers(min_value=0),
4204 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4205 for klass in (Any, AnyInherited):
4206 _, _, optional, _decoded = values
4207 obj = klass(value=value, optional=optional, _decoded=_decoded)
4210 pprint(obj, big_blobs=True, with_decode_path=True)
4211 self.assertFalse(obj.expled)
4212 obj_encoded = obj.encode()
4213 obj_expled = obj(value, expl=tag_expl)
4214 self.assertTrue(obj_expled.expled)
4216 list(obj_expled.pps())
4217 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4218 obj_expled_encoded = obj_expled.encode()
4219 ctx_copied = deepcopy(ctx_dummy)
4220 obj_decoded, tail = obj_expled.decode(
4221 obj_expled_encoded + tail_junk,
4225 self.assertDictEqual(ctx_copied, ctx_dummy)
4227 list(obj_decoded.pps())
4228 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4229 self.assertEqual(tail, tail_junk)
4230 self.assertEqual(obj_decoded, obj_expled)
4231 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4232 self.assertEqual(bytes(obj_decoded), bytes(obj))
4233 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4234 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4235 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4237 obj_decoded.expl_llen,
4238 len(len_encode(len(obj_encoded))),
4240 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4241 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4244 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4246 self.assertEqual(obj_decoded.expl_offset, offset)
4247 self.assertEqual(obj_decoded.tlen, 0)
4248 self.assertEqual(obj_decoded.llen, 0)
4249 self.assertEqual(obj_decoded.vlen, len(value))
4252 integers(min_value=1).map(tag_ctxc),
4253 integers(min_value=0, max_value=3),
4254 integers(min_value=0),
4258 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4259 chunk = Boolean(False, expl=expl).encode()
4261 OctetString.tag_default +
4263 b"".join([chunk] * chunks) +
4266 with self.assertRaises(LenIndefForm):
4270 decode_path=decode_path,
4272 obj, tail = Any().decode(
4275 decode_path=decode_path,
4276 ctx={"bered": True},
4278 self.assertSequenceEqual(tail, junk)
4279 self.assertEqual(obj.offset, offset)
4280 self.assertEqual(obj.tlvlen, len(encoded))
4281 self.assertTrue(obj.lenindef)
4282 self.assertFalse(obj.ber_encoded)
4283 self.assertTrue(obj.bered)
4285 self.assertTrue(obj.lenindef)
4286 self.assertFalse(obj.ber_encoded)
4287 self.assertTrue(obj.bered)
4290 pprint(obj, big_blobs=True, with_decode_path=True)
4291 with self.assertRaises(NotEnoughData) as err:
4295 decode_path=decode_path,
4296 ctx={"bered": True},
4298 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4299 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4301 class SeqOf(SequenceOf):
4302 schema = Boolean(expl=expl)
4304 class Seq(Sequence):
4306 ("type", ObjectIdentifier(defines=((("value",), {
4307 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4312 ("type", ObjectIdentifier("1.2.3")),
4313 ("value", Any(encoded)),
4315 seq_encoded = seq.encode()
4316 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4317 self.assertIsNotNone(seq_decoded["value"].defined)
4319 list(seq_decoded.pps())
4320 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4321 self.assertTrue(seq_decoded.bered)
4322 self.assertFalse(seq_decoded["type"].bered)
4323 self.assertTrue(seq_decoded["value"].bered)
4325 chunk = chunk[:-1] + b"\x01"
4326 chunks = b"".join([chunk] * (chunks + 1))
4327 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4329 ("type", ObjectIdentifier("1.2.3")),
4330 ("value", Any(encoded)),
4332 seq_encoded = seq.encode()
4333 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4334 self.assertIsNotNone(seq_decoded["value"].defined)
4336 list(seq_decoded.pps())
4337 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4338 self.assertTrue(seq_decoded.bered)
4339 self.assertFalse(seq_decoded["type"].bered)
4340 self.assertTrue(seq_decoded["value"].bered)
4344 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4346 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4347 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4349 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4350 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4352 min_size=len(names),
4353 max_size=len(names),
4356 (name, Integer(**tag_kwargs))
4357 for name, tag_kwargs in zip(names, tags)
4360 if value_required or draw(booleans()):
4361 value = draw(tuples(
4362 sampled_from([name for name, _ in schema]),
4363 integers().map(Integer),
4367 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4368 default = draw(one_of(
4370 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4372 optional = draw(one_of(none(), booleans()))
4374 draw(integers(min_value=0)),
4375 draw(integers(min_value=0)),
4376 draw(integers(min_value=0)),
4378 return (schema, value, expl, default, optional, _decoded)
4381 class ChoiceInherited(Choice):
4385 class TestChoice(CommonMixin, TestCase):
4387 schema = (("whatever", Boolean()),)
4390 def test_schema_required(self):
4391 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4394 def test_impl_forbidden(self):
4395 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4396 Choice(impl=b"whatever")
4398 def test_invalid_value_type(self):
4399 with self.assertRaises(InvalidValueType) as err:
4400 self.base_klass(123)
4402 with self.assertRaises(ObjUnknown) as err:
4403 self.base_klass(("whenever", Boolean(False)))
4405 with self.assertRaises(InvalidValueType) as err:
4406 self.base_klass(("whatever", Integer(123)))
4410 def test_optional(self, optional):
4411 obj = self.base_klass(
4412 default=self.base_klass(("whatever", Boolean(False))),
4415 self.assertTrue(obj.optional)
4418 def test_ready(self, value):
4419 obj = self.base_klass()
4420 self.assertFalse(obj.ready)
4423 pprint(obj, big_blobs=True, with_decode_path=True)
4424 self.assertIsNone(obj["whatever"])
4425 with self.assertRaises(ObjNotReady) as err:
4428 obj["whatever"] = Boolean()
4429 self.assertFalse(obj.ready)
4432 pprint(obj, big_blobs=True, with_decode_path=True)
4433 obj["whatever"] = Boolean(value)
4434 self.assertTrue(obj.ready)
4437 pprint(obj, big_blobs=True, with_decode_path=True)
4439 @given(booleans(), booleans())
4440 def test_comparison(self, value1, value2):
4441 class WahlInherited(self.base_klass):
4443 for klass in (self.base_klass, WahlInherited):
4444 obj1 = klass(("whatever", Boolean(value1)))
4445 obj2 = klass(("whatever", Boolean(value2)))
4446 self.assertEqual(obj1 == obj2, value1 == value2)
4447 self.assertEqual(obj1 != obj2, value1 != value2)
4448 self.assertEqual(obj1 == obj2._value, value1 == value2)
4449 self.assertFalse(obj1 == obj2._value[1])
4451 @given(data_strategy())
4452 def test_call(self, d):
4453 for klass in (Choice, ChoiceInherited):
4461 ) = d.draw(choice_values_strategy())
4464 schema = schema_initial
4466 value=value_initial,
4468 default=default_initial,
4469 optional=optional_initial or False,
4470 _decoded=_decoded_initial,
4479 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4480 obj = obj_initial(value, expl, default, optional)
4482 value_expected = default if value is None else value
4484 default_initial if value_expected is None
4487 self.assertEqual(obj.choice, value_expected[0])
4488 self.assertEqual(obj.value, int(value_expected[1]))
4489 self.assertEqual(obj.expl_tag, expl or expl_initial)
4490 default_expect = default_initial if default is None else default
4491 if default_expect is not None:
4492 self.assertEqual(obj.default.choice, default_expect[0])
4493 self.assertEqual(obj.default.value, int(default_expect[1]))
4494 if obj.default is None:
4495 optional = optional_initial if optional is None else optional
4496 optional = False if optional is None else optional
4499 self.assertEqual(obj.optional, optional)
4500 self.assertEqual(obj.specs, obj_initial.specs)
4502 def test_simultaneous_impl_expl(self):
4503 # override it, as Any does not have implicit tag
4506 def test_decoded(self):
4507 # override it, as Any does not have implicit tag
4510 @given(choice_values_strategy())
4511 def test_copy(self, values):
4512 _schema, value, expl, default, optional, _decoded = values
4514 class Wahl(self.base_klass):
4520 optional=optional or False,
4523 obj_copied = obj.copy()
4524 self.assertIsNone(obj.tag)
4525 self.assertIsNone(obj_copied.tag)
4526 # hack for assert_copied_basic_fields
4527 obj.tag = "whatever"
4528 obj_copied.tag = "whatever"
4529 self.assert_copied_basic_fields(obj, obj_copied)
4530 self.assertEqual(obj._value, obj_copied._value)
4531 self.assertEqual(obj.specs, obj_copied.specs)
4534 def test_stripped(self, value):
4535 obj = self.base_klass(("whatever", Boolean(value)))
4536 with self.assertRaises(NotEnoughData):
4537 obj.decode(obj.encode()[:-1])
4541 integers(min_value=1).map(tag_ctxc),
4543 def test_stripped_expl(self, value, tag_expl):
4544 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4545 with self.assertRaises(NotEnoughData):
4546 obj.decode(obj.encode()[:-1])
4548 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4549 @given(data_strategy())
4550 def test_symmetric(self, d):
4551 _schema, value, _, default, optional, _decoded = d.draw(
4552 choice_values_strategy(value_required=True)
4554 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4555 offset = d.draw(integers(min_value=0))
4556 tail_junk = d.draw(binary(max_size=5))
4558 class Wahl(self.base_klass):
4568 pprint(obj, big_blobs=True, with_decode_path=True)
4569 self.assertFalse(obj.expled)
4570 obj_encoded = obj.encode()
4571 obj_expled = obj(value, expl=tag_expl)
4572 self.assertTrue(obj_expled.expled)
4574 list(obj_expled.pps())
4575 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4576 obj_expled_encoded = obj_expled.encode()
4577 ctx_copied = deepcopy(ctx_dummy)
4578 obj_decoded, tail = obj_expled.decode(
4579 obj_expled_encoded + tail_junk,
4583 self.assertDictEqual(ctx_copied, ctx_dummy)
4585 list(obj_decoded.pps())
4586 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4587 self.assertEqual(tail, tail_junk)
4588 self.assertEqual(obj_decoded, obj_expled)
4589 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4590 self.assertEqual(obj_decoded.value, obj_expled.value)
4591 self.assertEqual(obj_decoded.choice, obj.choice)
4592 self.assertEqual(obj_decoded.value, obj.value)
4593 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4594 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4595 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4597 obj_decoded.expl_llen,
4598 len(len_encode(len(obj_encoded))),
4600 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4601 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4604 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4606 self.assertEqual(obj_decoded.expl_offset, offset)
4607 self.assertSequenceEqual(
4609 obj_decoded.value.fulloffset - offset:
4610 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4616 def test_set_get(self, value):
4619 ("erste", Boolean()),
4620 ("zweite", Integer()),
4623 with self.assertRaises(ObjUnknown) as err:
4624 obj["whatever"] = "whenever"
4625 with self.assertRaises(InvalidValueType) as err:
4626 obj["zweite"] = Boolean(False)
4627 obj["zweite"] = Integer(value)
4629 with self.assertRaises(ObjUnknown) as err:
4632 self.assertIsNone(obj["erste"])
4633 self.assertEqual(obj["zweite"], Integer(value))
4635 def test_tag_mismatch(self):
4638 ("erste", Boolean()),
4640 int_encoded = Integer(123).encode()
4641 bool_encoded = Boolean(False).encode()
4643 obj.decode(bool_encoded)
4644 with self.assertRaises(TagMismatch):
4645 obj.decode(int_encoded)
4647 def test_tag_mismatch_underlying(self):
4648 class SeqOfBoolean(SequenceOf):
4651 class SeqOfInteger(SequenceOf):
4656 ("erste", SeqOfBoolean()),
4659 int_encoded = SeqOfInteger((Integer(123),)).encode()
4660 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4662 obj.decode(bool_encoded)
4663 with self.assertRaises(TagMismatch) as err:
4664 obj.decode(int_encoded)
4665 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4669 def seq_values_strategy(draw, seq_klass, do_expl=False):
4671 if draw(booleans()):
4674 k: v for k, v in draw(dictionaries(
4677 booleans().map(Boolean),
4678 integers().map(Integer),
4683 if draw(booleans()):
4684 schema = list(draw(dictionaries(
4687 booleans().map(Boolean),
4688 integers().map(Integer),
4694 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4696 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4698 if draw(booleans()):
4699 default = seq_klass()
4701 k: v for k, v in draw(dictionaries(
4704 booleans().map(Boolean),
4705 integers().map(Integer),
4709 optional = draw(one_of(none(), booleans()))
4711 draw(integers(min_value=0)),
4712 draw(integers(min_value=0)),
4713 draw(integers(min_value=0)),
4715 return (value, schema, impl, expl, default, optional, _decoded)
4719 def sequence_strategy(draw, seq_klass):
4720 inputs = draw(lists(
4722 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4723 tuples(just(Integer), integers(), one_of(none(), integers())),
4728 integers(min_value=1),
4729 min_size=len(inputs),
4730 max_size=len(inputs),
4733 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4734 for tag, expled in zip(tags, draw(lists(
4736 min_size=len(inputs),
4737 max_size=len(inputs),
4741 for i, optional in enumerate(draw(lists(
4742 sampled_from(("required", "optional", "empty")),
4743 min_size=len(inputs),
4744 max_size=len(inputs),
4746 if optional in ("optional", "empty"):
4747 inits[i]["optional"] = True
4748 if optional == "empty":
4750 empties = set(empties)
4751 names = list(draw(sets(
4753 min_size=len(inputs),
4754 max_size=len(inputs),
4757 for i, (klass, value, default) in enumerate(inputs):
4758 schema.append((names[i], klass(default=default, **inits[i])))
4759 seq_name = draw(text_letters())
4760 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4763 for i, (klass, value, default) in enumerate(inputs):
4770 "default_value": None if spec.default is None else default,
4774 expect["optional"] = True
4776 expect["presented"] = True
4777 expect["value"] = value
4779 expect["optional"] = True
4780 if default is not None and default == value:
4781 expect["presented"] = False
4782 seq[name] = klass(value)
4783 expects.append(expect)
4788 def sequences_strategy(draw, seq_klass):
4789 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4791 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4792 for tag, expled in zip(tags, draw(lists(
4799 i for i, is_default in enumerate(draw(lists(
4805 names = list(draw(sets(
4810 seq_expectses = draw(lists(
4811 sequence_strategy(seq_klass=seq_klass),
4815 seqs = [seq for seq, _ in seq_expectses]
4817 for i, (name, seq) in enumerate(zip(names, seqs)):
4820 seq(default=(seq if i in defaulted else None), **inits[i]),
4822 seq_name = draw(text_letters())
4823 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4826 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4829 "expects": expects_inner,
4832 seq_outer[name] = seq_inner
4833 if seq_outer.specs[name].default is None:
4834 expect["presented"] = True
4835 expect_outers.append(expect)
4836 return seq_outer, expect_outers
4839 class SeqMixing(object):
4840 def test_invalid_value_type(self):
4841 with self.assertRaises(InvalidValueType) as err:
4842 self.base_klass(123)
4845 def test_invalid_value_type_set(self):
4846 class Seq(self.base_klass):
4847 schema = (("whatever", Boolean()),)
4849 with self.assertRaises(InvalidValueType) as err:
4850 seq["whatever"] = Integer(123)
4854 def test_optional(self, optional):
4855 obj = self.base_klass(default=self.base_klass(), optional=optional)
4856 self.assertTrue(obj.optional)
4858 @given(data_strategy())
4859 def test_ready(self, d):
4861 str(i): v for i, v in enumerate(d.draw(lists(
4868 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4875 for name in d.draw(permutations(
4876 list(ready.keys()) + list(non_ready.keys()),
4878 schema_input.append((name, Boolean()))
4880 class Seq(self.base_klass):
4881 schema = tuple(schema_input)
4883 for name in ready.keys():
4885 seq[name] = Boolean()
4886 self.assertFalse(seq.ready)
4889 pprint(seq, big_blobs=True, with_decode_path=True)
4890 for name, value in ready.items():
4891 seq[name] = Boolean(value)
4892 self.assertFalse(seq.ready)
4895 pprint(seq, big_blobs=True, with_decode_path=True)
4896 with self.assertRaises(ObjNotReady) as err:
4899 for name, value in non_ready.items():
4900 seq[name] = Boolean(value)
4901 self.assertTrue(seq.ready)
4904 pprint(seq, big_blobs=True, with_decode_path=True)
4906 @given(data_strategy())
4907 def test_call(self, d):
4908 class SeqInherited(self.base_klass):
4910 for klass in (self.base_klass, SeqInherited):
4919 ) = d.draw(seq_values_strategy(seq_klass=klass))
4920 obj_initial = klass(
4926 optional_initial or False,
4937 ) = d.draw(seq_values_strategy(
4939 do_expl=impl_initial is None,
4941 obj = obj_initial(value, impl, expl, default, optional)
4942 value_expected = default if value is None else value
4944 default_initial if value_expected is None
4947 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4948 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4949 self.assertEqual(obj.expl_tag, expl or expl_initial)
4951 {} if obj.default is None else obj.default._value,
4952 getattr(default_initial if default is None else default, "_value", {}),
4954 if obj.default is None:
4955 optional = optional_initial if optional is None else optional
4956 optional = False if optional is None else optional
4959 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4960 self.assertEqual(obj.optional, optional)
4962 @given(data_strategy())
4963 def test_copy(self, d):
4964 class SeqInherited(self.base_klass):
4966 for klass in (self.base_klass, SeqInherited):
4967 values = d.draw(seq_values_strategy(seq_klass=klass))
4968 obj = klass(*values)
4969 obj_copied = obj.copy()
4970 self.assert_copied_basic_fields(obj, obj_copied)
4971 self.assertEqual(obj.specs, obj_copied.specs)
4972 self.assertEqual(obj._value, obj_copied._value)
4974 @given(data_strategy())
4975 def test_stripped(self, d):
4976 value = d.draw(integers())
4977 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4979 class Seq(self.base_klass):
4981 schema = (("whatever", Integer()),)
4983 seq["whatever"] = Integer(value)
4984 with self.assertRaises(NotEnoughData):
4985 seq.decode(seq.encode()[:-1])
4987 @given(data_strategy())
4988 def test_stripped_expl(self, d):
4989 value = d.draw(integers())
4990 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4992 class Seq(self.base_klass):
4994 schema = (("whatever", Integer()),)
4996 seq["whatever"] = Integer(value)
4997 with self.assertRaises(NotEnoughData):
4998 seq.decode(seq.encode()[:-1])
5000 @given(binary(min_size=2))
5001 def test_non_tag_mismatch_raised(self, junk):
5003 _, _, len_encoded = tag_strip(memoryview(junk))
5004 len_decode(len_encoded)
5010 class Seq(self.base_klass):
5012 ("whatever", Integer()),
5014 ("whenever", Integer()),
5017 seq["whatever"] = Integer(123)
5018 seq["junk"] = Any(junk)
5019 seq["whenever"] = Integer(123)
5020 with self.assertRaises(DecodeError):
5021 seq.decode(seq.encode())
5024 integers(min_value=31),
5025 integers(min_value=0),
5028 def test_bad_tag(self, tag, offset, decode_path):
5029 with self.assertRaises(DecodeError) as err:
5030 self.base_klass().decode(
5031 tag_encode(tag)[:-1],
5033 decode_path=decode_path,
5036 self.assertEqual(err.exception.offset, offset)
5037 self.assertEqual(err.exception.decode_path, decode_path)
5040 integers(min_value=128),
5041 integers(min_value=0),
5044 def test_bad_len(self, l, offset, decode_path):
5045 with self.assertRaises(DecodeError) as err:
5046 self.base_klass().decode(
5047 self.base_klass.tag_default + len_encode(l)[:-1],
5049 decode_path=decode_path,
5052 self.assertEqual(err.exception.offset, offset)
5053 self.assertEqual(err.exception.decode_path, decode_path)
5055 def _assert_expects(self, seq, expects):
5056 for expect in expects:
5058 seq.specs[expect["name"]].optional,
5061 if expect["default_value"] is not None:
5063 seq.specs[expect["name"]].default,
5064 expect["default_value"],
5066 if expect["presented"]:
5067 self.assertIn(expect["name"], seq)
5068 self.assertEqual(seq[expect["name"]], expect["value"])
5070 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5071 @given(data_strategy())
5072 def test_symmetric(self, d):
5073 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5074 tail_junk = d.draw(binary(max_size=5))
5075 self.assertTrue(seq.ready)
5076 self.assertFalse(seq.decoded)
5077 self._assert_expects(seq, expects)
5080 pprint(seq, big_blobs=True, with_decode_path=True)
5081 self.assertTrue(seq.ready)
5082 seq_encoded = seq.encode()
5083 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5084 self.assertFalse(seq_decoded.lenindef)
5085 self.assertFalse(seq_decoded.ber_encoded)
5086 self.assertFalse(seq_decoded.bered)
5088 t, _, lv = tag_strip(seq_encoded)
5089 _, _, v = len_decode(lv)
5090 seq_encoded_lenindef = t + LENINDEF + v + EOC
5091 ctx_copied = deepcopy(ctx_dummy)
5092 ctx_copied["bered"] = True
5093 seq_decoded_lenindef, tail_lenindef = seq.decode(
5094 seq_encoded_lenindef + tail_junk,
5097 del ctx_copied["bered"]
5098 self.assertDictEqual(ctx_copied, ctx_dummy)
5099 self.assertTrue(seq_decoded_lenindef.lenindef)
5100 self.assertTrue(seq_decoded_lenindef.bered)
5101 seq_decoded_lenindef = seq_decoded_lenindef.copy()
5102 self.assertTrue(seq_decoded_lenindef.lenindef)
5103 self.assertTrue(seq_decoded_lenindef.bered)
5104 with self.assertRaises(DecodeError):
5105 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5106 with self.assertRaises(DecodeError):
5107 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5108 repr(seq_decoded_lenindef)
5109 list(seq_decoded_lenindef.pps())
5110 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5111 self.assertTrue(seq_decoded_lenindef.ready)
5113 for decoded, decoded_tail, encoded in (
5114 (seq_decoded, tail, seq_encoded),
5115 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5117 self.assertEqual(decoded_tail, tail_junk)
5118 self._assert_expects(decoded, expects)
5119 self.assertEqual(seq, decoded)
5120 self.assertEqual(decoded.encode(), seq_encoded)
5121 self.assertEqual(decoded.tlvlen, len(encoded))
5122 for expect in expects:
5123 if not expect["presented"]:
5124 self.assertNotIn(expect["name"], decoded)
5126 self.assertIn(expect["name"], decoded)
5127 obj = decoded[expect["name"]]
5128 self.assertTrue(obj.decoded)
5129 offset = obj.expl_offset if obj.expled else obj.offset
5130 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5131 self.assertSequenceEqual(
5132 seq_encoded[offset:offset + tlvlen],
5136 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5137 @given(data_strategy())
5138 def test_symmetric_with_seq(self, d):
5139 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5140 self.assertTrue(seq.ready)
5141 seq_encoded = seq.encode()
5142 seq_decoded, tail = seq.decode(seq_encoded)
5143 self.assertEqual(tail, b"")
5144 self.assertTrue(seq.ready)
5145 self.assertEqual(seq, seq_decoded)
5146 self.assertEqual(seq_decoded.encode(), seq_encoded)
5147 for expect_outer in expect_outers:
5148 if not expect_outer["presented"]:
5149 self.assertNotIn(expect_outer["name"], seq_decoded)
5151 self.assertIn(expect_outer["name"], seq_decoded)
5152 obj = seq_decoded[expect_outer["name"]]
5153 self.assertTrue(obj.decoded)
5154 offset = obj.expl_offset if obj.expled else obj.offset
5155 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5156 self.assertSequenceEqual(
5157 seq_encoded[offset:offset + tlvlen],
5160 self._assert_expects(obj, expect_outer["expects"])
5162 @given(data_strategy())
5163 def test_default_disappears(self, d):
5164 _schema = list(d.draw(dictionaries(
5166 sets(integers(), min_size=2, max_size=2),
5170 class Seq(self.base_klass):
5172 (n, Integer(default=d))
5173 for n, (_, d) in _schema
5176 for name, (value, _) in _schema:
5177 seq[name] = Integer(value)
5178 self.assertEqual(len(seq._value), len(_schema))
5179 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5180 self.assertGreater(len(seq.encode()), len(empty_seq))
5181 for name, (_, default) in _schema:
5182 seq[name] = Integer(default)
5183 self.assertEqual(len(seq._value), 0)
5184 self.assertSequenceEqual(seq.encode(), empty_seq)
5186 @given(data_strategy())
5187 def test_encoded_default_not_accepted(self, d):
5188 _schema = list(d.draw(dictionaries(
5193 tags = [tag_encode(tag) for tag in d.draw(sets(
5194 integers(min_value=0),
5195 min_size=len(_schema),
5196 max_size=len(_schema),
5199 class SeqWithoutDefault(self.base_klass):
5201 (n, Integer(impl=t))
5202 for (n, _), t in zip(_schema, tags)
5204 seq_without_default = SeqWithoutDefault()
5205 for name, value in _schema:
5206 seq_without_default[name] = Integer(value)
5207 seq_encoded = seq_without_default.encode()
5209 class SeqWithDefault(self.base_klass):
5211 (n, Integer(default=v, impl=t))
5212 for (n, v), t in zip(_schema, tags)
5214 seq_with_default = SeqWithDefault()
5215 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5216 seq_with_default.decode(seq_encoded)
5217 for ctx in ({"bered": True}, {"allow_default_values": True}):
5218 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5219 self.assertTrue(seq_decoded.ber_encoded)
5220 self.assertTrue(seq_decoded.bered)
5221 seq_decoded = seq_decoded.copy()
5222 self.assertTrue(seq_decoded.ber_encoded)
5223 self.assertTrue(seq_decoded.bered)
5224 for name, value in _schema:
5225 self.assertEqual(seq_decoded[name], seq_with_default[name])
5226 self.assertEqual(seq_decoded[name], value)
5228 @given(data_strategy())
5229 def test_missing_from_spec(self, d):
5230 names = list(d.draw(sets(text_letters(), min_size=2)))
5231 tags = [tag_encode(tag) for tag in d.draw(sets(
5232 integers(min_value=0),
5233 min_size=len(names),
5234 max_size=len(names),
5236 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5238 class SeqFull(self.base_klass):
5239 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5240 seq_full = SeqFull()
5241 for i, name in enumerate(names):
5242 seq_full[name] = Integer(i)
5243 seq_encoded = seq_full.encode()
5244 altered = names_tags[:-2] + names_tags[-1:]
5246 class SeqMissing(self.base_klass):
5247 schema = [(n, Integer(impl=t)) for n, t in altered]
5248 seq_missing = SeqMissing()
5249 with self.assertRaises(TagMismatch):
5250 seq_missing.decode(seq_encoded)
5252 @given(data_strategy())
5253 def test_bered(self, d):
5254 class Seq(self.base_klass):
5255 schema = (("underlying", Boolean()),)
5256 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5257 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5258 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5259 self.assertFalse(decoded.ber_encoded)
5260 self.assertFalse(decoded.lenindef)
5261 self.assertTrue(decoded.bered)
5262 decoded = decoded.copy()
5263 self.assertFalse(decoded.ber_encoded)
5264 self.assertFalse(decoded.lenindef)
5265 self.assertTrue(decoded.bered)
5267 class Seq(self.base_klass):
5268 schema = (("underlying", OctetString()),)
5270 tag_encode(form=TagFormConstructed, num=4) +
5272 OctetString(b"whatever").encode() +
5275 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5276 with self.assertRaises(DecodeError):
5277 Seq().decode(encoded)
5278 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5279 self.assertFalse(decoded.ber_encoded)
5280 self.assertFalse(decoded.lenindef)
5281 self.assertTrue(decoded.bered)
5282 decoded = decoded.copy()
5283 self.assertFalse(decoded.ber_encoded)
5284 self.assertFalse(decoded.lenindef)
5285 self.assertTrue(decoded.bered)
5288 class TestSequence(SeqMixing, CommonMixin, TestCase):
5289 base_klass = Sequence
5295 def test_remaining(self, value, junk):
5296 class Seq(Sequence):
5298 ("whatever", Integer()),
5300 int_encoded = Integer(value).encode()
5302 Sequence.tag_default,
5303 len_encode(len(int_encoded + junk)),
5306 with assertRaisesRegex(self, DecodeError, "remaining"):
5307 Seq().decode(junked)
5309 @given(sets(text_letters(), min_size=2))
5310 def test_obj_unknown(self, names):
5311 missing = names.pop()
5313 class Seq(Sequence):
5314 schema = [(n, Boolean()) for n in names]
5316 with self.assertRaises(ObjUnknown) as err:
5319 with self.assertRaises(ObjUnknown) as err:
5320 seq[missing] = Boolean()
5323 def test_x690_vector(self):
5324 class Seq(Sequence):
5326 ("name", IA5String()),
5329 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5330 self.assertEqual(seq["name"], "Smith")
5331 self.assertEqual(seq["ok"], True)
5334 class TestSet(SeqMixing, CommonMixin, TestCase):
5337 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5338 @given(data_strategy())
5339 def test_sorted(self, d):
5341 tag_encode(tag) for tag in
5342 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5346 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5348 for name, _ in Seq.schema:
5349 seq[name] = OctetString(b"")
5350 seq_encoded = seq.encode()
5351 seq_decoded, _ = seq.decode(seq_encoded)
5352 self.assertSequenceEqual(
5353 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5354 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5357 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5358 @given(data_strategy())
5359 def test_unsorted(self, d):
5361 tag_encode(tag) for tag in
5362 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5364 tags = d.draw(permutations(tags))
5365 assume(tags != sorted(tags))
5366 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5367 seq_encoded = b"".join((
5369 len_encode(len(encoded)),
5374 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5376 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5377 seq.decode(seq_encoded)
5378 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5379 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5380 self.assertTrue(seq_decoded.ber_encoded)
5381 self.assertTrue(seq_decoded.bered)
5382 seq_decoded = seq_decoded.copy()
5383 self.assertTrue(seq_decoded.ber_encoded)
5384 self.assertTrue(seq_decoded.bered)
5385 self.assertSequenceEqual(
5386 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5392 def seqof_values_strategy(draw, schema=None, do_expl=False):
5394 schema = draw(sampled_from((Boolean(), Integer())))
5395 bound_min, bound_max = sorted(draw(sets(
5396 integers(min_value=0, max_value=10),
5400 if isinstance(schema, Boolean):
5401 values_generator = booleans().map(Boolean)
5402 elif isinstance(schema, Integer):
5403 values_generator = integers().map(Integer)
5404 values_generator = lists(
5409 values = draw(one_of(none(), values_generator))
5413 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5415 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5416 default = draw(one_of(none(), values_generator))
5417 optional = draw(one_of(none(), booleans()))
5419 draw(integers(min_value=0)),
5420 draw(integers(min_value=0)),
5421 draw(integers(min_value=0)),
5426 (bound_min, bound_max),
5435 class SeqOfMixing(object):
5436 def test_invalid_value_type(self):
5437 with self.assertRaises(InvalidValueType) as err:
5438 self.base_klass(123)
5441 def test_invalid_values_type(self):
5442 class SeqOf(self.base_klass):
5444 with self.assertRaises(InvalidValueType) as err:
5445 SeqOf([Integer(123), Boolean(False), Integer(234)])
5448 def test_schema_required(self):
5449 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5450 self.base_klass.__mro__[1]()
5452 @given(booleans(), booleans(), binary(), binary())
5453 def test_comparison(self, value1, value2, tag1, tag2):
5454 class SeqOf(self.base_klass):
5456 obj1 = SeqOf([Boolean(value1)])
5457 obj2 = SeqOf([Boolean(value2)])
5458 self.assertEqual(obj1 == obj2, value1 == value2)
5459 self.assertEqual(obj1 != obj2, value1 != value2)
5460 self.assertEqual(obj1 == list(obj2), value1 == value2)
5461 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5462 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5463 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5464 self.assertEqual(obj1 == obj2, tag1 == tag2)
5465 self.assertEqual(obj1 != obj2, tag1 != tag2)
5467 @given(lists(booleans()))
5468 def test_iter(self, values):
5469 class SeqOf(self.base_klass):
5471 obj = SeqOf([Boolean(value) for value in values])
5472 self.assertEqual(len(obj), len(values))
5473 for i, value in enumerate(obj):
5474 self.assertEqual(value, values[i])
5476 @given(data_strategy())
5477 def test_ready(self, d):
5478 ready = [Integer(v) for v in d.draw(lists(
5485 range(d.draw(integers(min_value=1, max_value=5)))
5488 class SeqOf(self.base_klass):
5490 values = d.draw(permutations(ready + non_ready))
5492 for value in values:
5494 self.assertFalse(seqof.ready)
5497 pprint(seqof, big_blobs=True, with_decode_path=True)
5498 with self.assertRaises(ObjNotReady) as err:
5501 for i, value in enumerate(values):
5502 self.assertEqual(seqof[i], value)
5503 if not seqof[i].ready:
5504 seqof[i] = Integer(i)
5505 self.assertTrue(seqof.ready)
5508 pprint(seqof, big_blobs=True, with_decode_path=True)
5510 def test_spec_mismatch(self):
5511 class SeqOf(self.base_klass):
5514 seqof.append(Integer(123))
5515 with self.assertRaises(ValueError):
5516 seqof.append(Boolean(False))
5517 with self.assertRaises(ValueError):
5518 seqof[0] = Boolean(False)
5520 @given(data_strategy())
5521 def test_bounds_satisfied(self, d):
5522 class SeqOf(self.base_klass):
5524 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5525 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5526 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5527 SeqOf(value=value, bounds=(bound_min, bound_max))
5529 @given(data_strategy())
5530 def test_bounds_unsatisfied(self, d):
5531 class SeqOf(self.base_klass):
5533 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5534 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5535 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5536 with self.assertRaises(BoundsError) as err:
5537 SeqOf(value=value, bounds=(bound_min, bound_max))
5539 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5540 SeqOf(bounds=(bound_min, bound_max)).decode(
5541 SeqOf(value).encode()
5544 value = [Boolean(True)] * d.draw(integers(
5545 min_value=bound_max + 1,
5546 max_value=bound_max + 10,
5548 with self.assertRaises(BoundsError) as err:
5549 SeqOf(value=value, bounds=(bound_min, bound_max))
5551 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5552 SeqOf(bounds=(bound_min, bound_max)).decode(
5553 SeqOf(value).encode()
5557 @given(integers(min_value=1, max_value=10))
5558 def test_out_of_bounds(self, bound_max):
5559 class SeqOf(self.base_klass):
5561 bounds = (0, bound_max)
5563 for _ in range(bound_max):
5564 seqof.append(Integer(123))
5565 with self.assertRaises(BoundsError):
5566 seqof.append(Integer(123))
5568 @given(data_strategy())
5569 def test_call(self, d):
5579 ) = d.draw(seqof_values_strategy())
5581 class SeqOf(self.base_klass):
5582 schema = schema_initial
5583 obj_initial = SeqOf(
5584 value=value_initial,
5585 bounds=bounds_initial,
5588 default=default_initial,
5589 optional=optional_initial or False,
5590 _decoded=_decoded_initial,
5601 ) = d.draw(seqof_values_strategy(
5602 schema=schema_initial,
5603 do_expl=impl_initial is None,
5605 if (default is None) and (obj_initial.default is not None):
5608 (bounds is None) and
5609 (value is not None) and
5610 (bounds_initial is not None) and
5611 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5615 (bounds is None) and
5616 (default is not None) and
5617 (bounds_initial is not None) and
5618 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5630 value_expected = default if value is None else value
5632 default_initial if value_expected is None
5635 value_expected = () if value_expected is None else value_expected
5636 self.assertEqual(obj, value_expected)
5637 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5638 self.assertEqual(obj.expl_tag, expl or expl_initial)
5641 default_initial if default is None else default,
5643 if obj.default is None:
5644 optional = optional_initial if optional is None else optional
5645 optional = False if optional is None else optional
5648 self.assertEqual(obj.optional, optional)
5650 (obj._bound_min, obj._bound_max),
5651 bounds or bounds_initial or (0, float("+inf")),
5654 @given(seqof_values_strategy())
5655 def test_copy(self, values):
5656 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5658 class SeqOf(self.base_klass):
5666 optional=optional or False,
5669 obj_copied = obj.copy()
5670 self.assert_copied_basic_fields(obj, obj_copied)
5671 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5672 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5673 self.assertEqual(obj._value, obj_copied._value)
5677 integers(min_value=1).map(tag_encode),
5679 def test_stripped(self, values, tag_impl):
5680 class SeqOf(self.base_klass):
5681 schema = OctetString()
5682 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5683 with self.assertRaises(NotEnoughData):
5684 obj.decode(obj.encode()[:-1])
5688 integers(min_value=1).map(tag_ctxc),
5690 def test_stripped_expl(self, values, tag_expl):
5691 class SeqOf(self.base_klass):
5692 schema = OctetString()
5693 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5694 with self.assertRaises(NotEnoughData):
5695 obj.decode(obj.encode()[:-1])
5698 integers(min_value=31),
5699 integers(min_value=0),
5702 def test_bad_tag(self, tag, offset, decode_path):
5703 with self.assertRaises(DecodeError) as err:
5704 self.base_klass().decode(
5705 tag_encode(tag)[:-1],
5707 decode_path=decode_path,
5710 self.assertEqual(err.exception.offset, offset)
5711 self.assertEqual(err.exception.decode_path, decode_path)
5714 integers(min_value=128),
5715 integers(min_value=0),
5718 def test_bad_len(self, l, offset, decode_path):
5719 with self.assertRaises(DecodeError) as err:
5720 self.base_klass().decode(
5721 self.base_klass.tag_default + len_encode(l)[:-1],
5723 decode_path=decode_path,
5726 self.assertEqual(err.exception.offset, offset)
5727 self.assertEqual(err.exception.decode_path, decode_path)
5729 @given(binary(min_size=1))
5730 def test_tag_mismatch(self, impl):
5731 assume(impl != self.base_klass.tag_default)
5732 with self.assertRaises(TagMismatch):
5733 self.base_klass(impl=impl).decode(self.base_klass().encode())
5735 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5737 seqof_values_strategy(schema=Integer()),
5738 lists(integers().map(Integer)),
5739 integers(min_value=1).map(tag_ctxc),
5740 integers(min_value=0),
5743 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5744 _, _, _, _, _, default, optional, _decoded = values
5746 class SeqOf(self.base_klass):
5756 pprint(obj, big_blobs=True, with_decode_path=True)
5757 self.assertFalse(obj.expled)
5758 obj_encoded = obj.encode()
5759 obj_expled = obj(value, expl=tag_expl)
5760 self.assertTrue(obj_expled.expled)
5762 list(obj_expled.pps())
5763 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5764 obj_expled_encoded = obj_expled.encode()
5765 ctx_copied = deepcopy(ctx_dummy)
5766 obj_decoded, tail = obj_expled.decode(
5767 obj_expled_encoded + tail_junk,
5771 self.assertDictEqual(ctx_copied, ctx_dummy)
5773 list(obj_decoded.pps())
5774 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5775 self.assertEqual(tail, tail_junk)
5776 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5777 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5778 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5779 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5781 obj_decoded.expl_llen,
5782 len(len_encode(len(obj_encoded))),
5784 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5785 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5788 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5790 self.assertEqual(obj_decoded.expl_offset, offset)
5791 for obj_inner in obj_decoded:
5792 self.assertIn(obj_inner, obj_decoded)
5793 self.assertSequenceEqual(
5796 obj_inner.offset - offset:
5797 obj_inner.offset + obj_inner.tlvlen - offset
5801 t, _, lv = tag_strip(obj_encoded)
5802 _, _, v = len_decode(lv)
5803 obj_encoded_lenindef = t + LENINDEF + v + EOC
5804 obj_decoded_lenindef, tail_lenindef = obj.decode(
5805 obj_encoded_lenindef + tail_junk,
5806 ctx={"bered": True},
5808 self.assertTrue(obj_decoded_lenindef.lenindef)
5809 self.assertTrue(obj_decoded_lenindef.bered)
5810 obj_decoded_lenindef = obj_decoded_lenindef.copy()
5811 self.assertTrue(obj_decoded_lenindef.lenindef)
5812 self.assertTrue(obj_decoded_lenindef.bered)
5813 repr(obj_decoded_lenindef)
5814 list(obj_decoded_lenindef.pps())
5815 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5816 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5817 with self.assertRaises(DecodeError):
5818 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5819 with self.assertRaises(DecodeError):
5820 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5822 @given(data_strategy())
5823 def test_bered(self, d):
5824 class SeqOf(self.base_klass):
5826 encoded = Boolean(False).encode()
5827 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5828 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5829 with self.assertRaises(DecodeError):
5830 SeqOf().decode(encoded)
5831 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5832 self.assertFalse(decoded.ber_encoded)
5833 self.assertFalse(decoded.lenindef)
5834 self.assertTrue(decoded.bered)
5835 decoded = decoded.copy()
5836 self.assertFalse(decoded.ber_encoded)
5837 self.assertFalse(decoded.lenindef)
5838 self.assertTrue(decoded.bered)
5840 class SeqOf(self.base_klass):
5841 schema = OctetString()
5842 encoded = OctetString(b"whatever").encode()
5844 tag_encode(form=TagFormConstructed, num=4) +
5846 OctetString(b"whatever").encode() +
5849 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5850 with self.assertRaises(DecodeError):
5851 SeqOf().decode(encoded)
5852 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5853 self.assertFalse(decoded.ber_encoded)
5854 self.assertFalse(decoded.lenindef)
5855 self.assertTrue(decoded.bered)
5856 decoded = decoded.copy()
5857 self.assertFalse(decoded.ber_encoded)
5858 self.assertFalse(decoded.lenindef)
5859 self.assertTrue(decoded.bered)
5862 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5863 class SeqOf(SequenceOf):
5867 def _test_symmetric_compare_objs(self, obj1, obj2):
5868 self.assertEqual(obj1, obj2)
5869 self.assertSequenceEqual(list(obj1), list(obj2))
5872 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5877 def _test_symmetric_compare_objs(self, obj1, obj2):
5878 self.assertSetEqual(
5879 set(int(v) for v in obj1),
5880 set(int(v) for v in obj2),
5883 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5884 @given(data_strategy())
5885 def test_sorted(self, d):
5886 values = [OctetString(v) for v in d.draw(lists(binary()))]
5889 schema = OctetString()
5891 seq_encoded = seq.encode()
5892 seq_decoded, _ = seq.decode(seq_encoded)
5893 self.assertSequenceEqual(
5894 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5895 b"".join(sorted([v.encode() for v in values])),
5898 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5899 @given(data_strategy())
5900 def test_unsorted(self, d):
5901 values = [OctetString(v).encode() for v in d.draw(sets(
5902 binary(min_size=1, max_size=5),
5906 values = d.draw(permutations(values))
5907 assume(values != sorted(values))
5908 encoded = b"".join(values)
5909 seq_encoded = b"".join((
5911 len_encode(len(encoded)),
5916 schema = OctetString()
5918 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5919 seq.decode(seq_encoded)
5921 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5922 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5923 self.assertTrue(seq_decoded.ber_encoded)
5924 self.assertTrue(seq_decoded.bered)
5925 seq_decoded = seq_decoded.copy()
5926 self.assertTrue(seq_decoded.ber_encoded)
5927 self.assertTrue(seq_decoded.bered)
5928 self.assertSequenceEqual(
5929 [obj.encode() for obj in seq_decoded],
5934 class TestGoMarshalVectors(TestCase):
5936 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5937 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5938 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5939 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5940 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5942 class Seq(Sequence):
5944 ("erste", Integer()),
5945 ("zweite", Integer(optional=True))
5948 seq["erste"] = Integer(64)
5949 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5950 seq["erste"] = Integer(0x123456)
5951 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5952 seq["erste"] = Integer(64)
5953 seq["zweite"] = Integer(65)
5954 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5956 class NestedSeq(Sequence):
5960 seq["erste"] = Integer(127)
5961 seq["zweite"] = None
5962 nested = NestedSeq()
5963 nested["nest"] = seq
5964 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5966 self.assertSequenceEqual(
5967 OctetString(b"\x01\x02\x03").encode(),
5968 hexdec("0403010203"),
5971 class Seq(Sequence):
5973 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5976 seq["erste"] = Integer(64)
5977 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5979 class Seq(Sequence):
5981 ("erste", Integer(expl=tag_ctxc(5))),
5984 seq["erste"] = Integer(64)
5985 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5987 class Seq(Sequence):
5990 impl=tag_encode(0, klass=TagClassContext),
5995 seq["erste"] = Null()
5996 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5998 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6000 self.assertSequenceEqual(
6001 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6002 hexdec("170d3730303130313030303030305a"),
6004 self.assertSequenceEqual(
6005 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6006 hexdec("170d3039313131353232353631365a"),
6008 self.assertSequenceEqual(
6009 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6010 hexdec("180f32313030303430353132303130315a"),
6013 class Seq(Sequence):
6015 ("erste", GeneralizedTime()),
6018 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6019 self.assertSequenceEqual(
6021 hexdec("3011180f32303039313131353232353631365a"),
6024 self.assertSequenceEqual(
6025 BitString((1, b"\x80")).encode(),
6028 self.assertSequenceEqual(
6029 BitString((12, b"\x81\xF0")).encode(),
6030 hexdec("03030481f0"),
6033 self.assertSequenceEqual(
6034 ObjectIdentifier("1.2.3.4").encode(),
6035 hexdec("06032a0304"),
6037 self.assertSequenceEqual(
6038 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6039 hexdec("06092a864888932d010105"),
6041 self.assertSequenceEqual(
6042 ObjectIdentifier("2.100.3").encode(),
6043 hexdec("0603813403"),
6046 self.assertSequenceEqual(
6047 PrintableString("test").encode(),
6048 hexdec("130474657374"),
6050 self.assertSequenceEqual(
6051 PrintableString("x" * 127).encode(),
6052 hexdec("137F" + "78" * 127),
6054 self.assertSequenceEqual(
6055 PrintableString("x" * 128).encode(),
6056 hexdec("138180" + "78" * 128),
6058 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6060 class Seq(Sequence):
6062 ("erste", IA5String()),
6065 seq["erste"] = IA5String("test")
6066 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6068 class Seq(Sequence):
6070 ("erste", PrintableString()),
6073 seq["erste"] = PrintableString("test")
6074 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6075 # Asterisk is actually not allowable
6076 PrintableString._allowable_chars |= set(b"*")
6077 seq["erste"] = PrintableString("test*")
6078 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6079 PrintableString._allowable_chars -= set(b"*")
6081 class Seq(Sequence):
6083 ("erste", Any(optional=True)),
6084 ("zweite", Integer()),
6087 seq["zweite"] = Integer(64)
6088 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6093 seq.append(Integer(10))
6094 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6096 class _SeqOf(SequenceOf):
6097 schema = PrintableString()
6099 class SeqOf(SequenceOf):
6102 _seqof.append(PrintableString("1"))
6104 seqof.append(_seqof)
6105 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6107 class Seq(Sequence):
6109 ("erste", Integer(default=1)),
6112 seq["erste"] = Integer(0)
6113 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6114 seq["erste"] = Integer(1)
6115 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6116 seq["erste"] = Integer(2)
6117 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6120 class TestPP(TestCase):
6121 @given(data_strategy())
6122 def test_oid_printing(self, d):
6124 str(ObjectIdentifier(k)): v * 2
6125 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6127 chosen = d.draw(sampled_from(sorted(oids)))
6128 chosen_id = oids[chosen]
6129 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6130 self.assertNotIn(chosen_id, pp_console_row(pp))
6133 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6137 class TestAutoAddSlots(TestCase):
6139 class Inher(Integer):
6142 with self.assertRaises(AttributeError):
6144 inher.unexistent = "whatever"
6147 class TestOIDDefines(TestCase):
6148 @given(data_strategy())
6149 def runTest(self, d):
6150 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6151 value_name_chosen = d.draw(sampled_from(value_names))
6153 ObjectIdentifier(oid)
6154 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6156 oid_chosen = d.draw(sampled_from(oids))
6157 values = d.draw(lists(
6159 min_size=len(value_names),
6160 max_size=len(value_names),
6163 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6164 oid: Integer() for oid in oids[:-1]
6167 for i, value_name in enumerate(value_names):
6168 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6170 class Seq(Sequence):
6173 for value_name, value in zip(value_names, values):
6174 seq[value_name] = Any(Integer(value).encode())
6175 seq["type"] = oid_chosen
6176 seq, _ = Seq().decode(seq.encode())
6177 for value_name in value_names:
6178 if value_name == value_name_chosen:
6180 self.assertIsNone(seq[value_name].defined)
6181 if value_name_chosen in oids[:-1]:
6182 self.assertIsNotNone(seq[value_name_chosen].defined)
6183 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6184 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6187 pprint(seq, big_blobs=True, with_decode_path=True)
6190 class TestDefinesByPath(TestCase):
6191 def test_generated(self):
6192 class Seq(Sequence):
6194 ("type", ObjectIdentifier()),
6195 ("value", OctetString(expl=tag_ctxc(123))),
6198 class SeqInner(Sequence):
6200 ("typeInner", ObjectIdentifier()),
6201 ("valueInner", Any()),
6204 class PairValue(SetOf):
6207 class Pair(Sequence):
6209 ("type", ObjectIdentifier()),
6210 ("value", PairValue()),
6213 class Pairs(SequenceOf):
6220 type_octet_stringed,
6222 ObjectIdentifier(oid)
6223 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6225 seq_integered = Seq()
6226 seq_integered["type"] = type_integered
6227 seq_integered["value"] = OctetString(Integer(123).encode())
6228 seq_integered_raw = seq_integered.encode()
6232 (type_octet_stringed, OctetString(b"whatever")),
6233 (type_integered, Integer(123)),
6234 (type_octet_stringed, OctetString(b"whenever")),
6235 (type_integered, Integer(234)),
6237 for t, v in pairs_input:
6240 pair["value"] = PairValue((Any(v),))
6242 seq_inner = SeqInner()
6243 seq_inner["typeInner"] = type_innered
6244 seq_inner["valueInner"] = Any(pairs)
6245 seq_sequenced = Seq()
6246 seq_sequenced["type"] = type_sequenced
6247 seq_sequenced["value"] = OctetString(seq_inner.encode())
6248 seq_sequenced_raw = seq_sequenced.encode()
6250 list(seq_sequenced.pps())
6251 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6253 defines_by_path = []
6254 ctx_copied = deepcopy(ctx_dummy)
6255 seq_integered, _ = Seq().decode(
6259 self.assertDictEqual(ctx_copied, ctx_dummy)
6260 self.assertIsNone(seq_integered["value"].defined)
6261 defines_by_path.append(
6262 (("type",), ((("value",), {
6263 type_integered: Integer(),
6264 type_sequenced: SeqInner(),
6267 ctx_copied["defines_by_path"] = defines_by_path
6268 seq_integered, _ = Seq().decode(
6272 del ctx_copied["defines_by_path"]
6273 self.assertDictEqual(ctx_copied, ctx_dummy)
6274 self.assertIsNotNone(seq_integered["value"].defined)
6275 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6276 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6277 self.assertTrue(seq_integered_raw[
6278 seq_integered["value"].defined[1].offset:
6279 ].startswith(Integer(123).encode()))
6281 list(seq_integered.pps())
6282 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6284 ctx_copied["defines_by_path"] = defines_by_path
6285 seq_sequenced, _ = Seq().decode(
6289 del ctx_copied["defines_by_path"]
6290 self.assertDictEqual(ctx_copied, ctx_dummy)
6291 self.assertIsNotNone(seq_sequenced["value"].defined)
6292 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6293 seq_inner = seq_sequenced["value"].defined[1]
6294 self.assertIsNone(seq_inner["valueInner"].defined)
6296 list(seq_sequenced.pps())
6297 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6299 defines_by_path.append((
6300 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6301 ((("valueInner",), {type_innered: Pairs()}),),
6303 ctx_copied["defines_by_path"] = defines_by_path
6304 seq_sequenced, _ = Seq().decode(
6308 del ctx_copied["defines_by_path"]
6309 self.assertDictEqual(ctx_copied, ctx_dummy)
6310 self.assertIsNotNone(seq_sequenced["value"].defined)
6311 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6312 seq_inner = seq_sequenced["value"].defined[1]
6313 self.assertIsNotNone(seq_inner["valueInner"].defined)
6314 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6315 pairs = seq_inner["valueInner"].defined[1]
6317 self.assertIsNone(pair["value"][0].defined)
6319 list(seq_sequenced.pps())
6320 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6322 defines_by_path.append((
6325 DecodePathDefBy(type_sequenced),
6327 DecodePathDefBy(type_innered),
6332 type_integered: Integer(),
6333 type_octet_stringed: OctetString(),
6336 ctx_copied["defines_by_path"] = defines_by_path
6337 seq_sequenced, _ = Seq().decode(
6341 del ctx_copied["defines_by_path"]
6342 self.assertDictEqual(ctx_copied, ctx_dummy)
6343 self.assertIsNotNone(seq_sequenced["value"].defined)
6344 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6345 seq_inner = seq_sequenced["value"].defined[1]
6346 self.assertIsNotNone(seq_inner["valueInner"].defined)
6347 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6348 pairs_got = seq_inner["valueInner"].defined[1]
6349 for pair_input, pair_got in zip(pairs_input, pairs_got):
6350 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6351 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6353 list(seq_sequenced.pps())
6354 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6356 @given(oid_strategy(), integers())
6357 def test_simple(self, oid, tgt):
6358 class Inner(Sequence):
6360 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6361 ObjectIdentifier(oid): Integer(),
6365 class Outer(Sequence):
6368 ("tgt", OctetString()),
6372 inner["oid"] = ObjectIdentifier(oid)
6374 outer["inner"] = inner
6375 outer["tgt"] = OctetString(Integer(tgt).encode())
6376 decoded, _ = Outer().decode(outer.encode())
6377 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6380 class TestAbsDecodePath(TestCase):
6382 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6383 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6385 def test_concat(self, decode_path, rel_path):
6386 self.assertSequenceEqual(
6387 abs_decode_path(decode_path, rel_path),
6388 decode_path + rel_path,
6392 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6393 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6395 def test_abs(self, decode_path, rel_path):
6396 self.assertSequenceEqual(
6397 abs_decode_path(decode_path, ("/",) + rel_path),
6402 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6403 integers(min_value=1, max_value=3),
6404 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6406 def test_dots(self, decode_path, number_of_dots, rel_path):
6407 self.assertSequenceEqual(
6408 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6409 decode_path[:-number_of_dots] + rel_path,
6413 class TestStrictDefaultExistence(TestCase):
6414 @given(data_strategy())
6415 def runTest(self, d):
6416 count = d.draw(integers(min_value=1, max_value=10))
6417 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6419 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6420 for i in range(count)
6422 for klass in (Sequence, Set):
6426 for i in range(count):
6427 seq["int%d" % i] = Integer(123)
6429 chosen_choice = "int%d" % chosen
6430 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6431 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6433 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6434 self.assertTrue(decoded.ber_encoded)
6435 self.assertTrue(decoded.bered)
6436 decoded = decoded.copy()
6437 self.assertTrue(decoded.ber_encoded)
6438 self.assertTrue(decoded.bered)
6439 decoded, _ = seq.decode(raw, ctx={"bered": True})
6440 self.assertTrue(decoded.ber_encoded)
6441 self.assertTrue(decoded.bered)
6442 decoded = decoded.copy()
6443 self.assertTrue(decoded.ber_encoded)
6444 self.assertTrue(decoded.bered)
6447 class TestX690PrefixedType(TestCase):
6449 self.assertSequenceEqual(
6450 VisibleString("Jones").encode(),
6451 hexdec("1A054A6F6E6573"),
6453 self.assertSequenceEqual(
6456 impl=tag_encode(3, klass=TagClassApplication),
6458 hexdec("43054A6F6E6573"),
6460 self.assertSequenceEqual(
6464 impl=tag_encode(3, klass=TagClassApplication),
6468 hexdec("A20743054A6F6E6573"),
6470 self.assertSequenceEqual(
6474 impl=tag_encode(3, klass=TagClassApplication),
6476 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6478 hexdec("670743054A6F6E6573"),
6480 self.assertSequenceEqual(
6481 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6482 hexdec("82054A6F6E6573"),
6486 class TestExplOOB(TestCase):
6488 expl = tag_ctxc(123)
6489 raw = Integer(123).encode() + Integer(234).encode()
6490 raw = b"".join((expl, len_encode(len(raw)), raw))
6491 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6492 Integer(expl=expl).decode(raw)
6493 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})