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 if generation_choice == 2 or draw(booleans()):
1150 return draw(binary(max_size=len(schema) // 8))
1151 if 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 def test_nonnormalized_first_arc(self):
2746 ObjectIdentifier.tag_default +
2749 ObjectIdentifier((1, 0)).encode()[-1:]
2751 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2752 self.assertTrue(obj.ber_encoded)
2753 self.assertTrue(obj.bered)
2755 self.assertTrue(obj.ber_encoded)
2756 self.assertTrue(obj.bered)
2757 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2758 ObjectIdentifier().decode(tampered)
2760 @given(data_strategy())
2761 def test_nonnormalized_arcs(self, d):
2762 arcs = d.draw(lists(
2763 integers(min_value=0, max_value=100),
2767 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2768 _, _, lv = tag_strip(dered)
2769 _, _, v = len_decode(lv)
2770 v_no_first_arc = v[1:]
2771 idx_for_tamper = d.draw(integers(
2773 max_value=len(v_no_first_arc) - 1,
2775 tampered = list(bytearray(v_no_first_arc))
2776 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2777 tampered.insert(idx_for_tamper, 0x80)
2778 tampered = bytes(bytearray(tampered))
2780 ObjectIdentifier.tag_default +
2781 len_encode(len(tampered)) +
2784 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2785 self.assertTrue(obj.ber_encoded)
2786 self.assertTrue(obj.bered)
2788 self.assertTrue(obj.ber_encoded)
2789 self.assertTrue(obj.bered)
2790 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2791 ObjectIdentifier().decode(tampered)
2795 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2797 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2798 values = list(draw(sets(
2800 min_size=len(schema),
2801 max_size=len(schema),
2803 schema = list(zip(schema, values))
2804 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2808 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2810 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2811 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2812 optional = draw(one_of(none(), booleans()))
2814 draw(integers(min_value=0)),
2815 draw(integers(min_value=0)),
2816 draw(integers(min_value=0)),
2818 return (schema, value, impl, expl, default, optional, _decoded)
2821 class TestEnumerated(CommonMixin, TestCase):
2822 class EWhatever(Enumerated):
2823 schema = (("whatever", 0),)
2825 base_klass = EWhatever
2827 def test_schema_required(self):
2828 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2831 def test_invalid_value_type(self):
2832 with self.assertRaises(InvalidValueType) as err:
2833 self.base_klass((1, 2))
2836 @given(sets(text_letters(), min_size=2))
2837 def test_unknown_name(self, schema_input):
2838 missing = schema_input.pop()
2840 class E(Enumerated):
2841 schema = [(n, 123) for n in schema_input]
2842 with self.assertRaises(ObjUnknown) as err:
2847 sets(text_letters(), min_size=2),
2848 sets(integers(), min_size=2),
2850 def test_unknown_value(self, schema_input, values_input):
2852 missing_value = values_input.pop()
2853 _input = list(zip(schema_input, values_input))
2855 class E(Enumerated):
2857 with self.assertRaises(DecodeError) as err:
2862 def test_optional(self, optional):
2863 obj = self.base_klass(default="whatever", optional=optional)
2864 self.assertTrue(obj.optional)
2866 def test_ready(self):
2867 obj = self.base_klass()
2868 self.assertFalse(obj.ready)
2871 pprint(obj, big_blobs=True, with_decode_path=True)
2872 with self.assertRaises(ObjNotReady) as err:
2875 obj = self.base_klass("whatever")
2876 self.assertTrue(obj.ready)
2879 pprint(obj, big_blobs=True, with_decode_path=True)
2881 @given(integers(), integers(), binary(), binary())
2882 def test_comparison(self, value1, value2, tag1, tag2):
2883 class E(Enumerated):
2885 ("whatever0", value1),
2886 ("whatever1", value2),
2889 class EInherited(E):
2891 for klass in (E, EInherited):
2892 obj1 = klass(value1)
2893 obj2 = klass(value2)
2894 self.assertEqual(obj1 == obj2, value1 == value2)
2895 self.assertEqual(obj1 != obj2, value1 != value2)
2896 self.assertEqual(obj1 == int(obj2), value1 == value2)
2897 obj1 = klass(value1, impl=tag1)
2898 obj2 = klass(value1, impl=tag2)
2899 self.assertEqual(obj1 == obj2, tag1 == tag2)
2900 self.assertEqual(obj1 != obj2, tag1 != tag2)
2902 @given(data_strategy())
2903 def test_call(self, d):
2912 ) = d.draw(enumerated_values_strategy())
2914 class E(Enumerated):
2915 schema = schema_initial
2917 value=value_initial,
2920 default=default_initial,
2921 optional=optional_initial or False,
2922 _decoded=_decoded_initial,
2932 ) = d.draw(enumerated_values_strategy(
2933 schema=schema_initial,
2934 do_expl=impl_initial is None,
2944 value_expected = default if value is None else value
2946 default_initial if value_expected is None
2951 dict(schema_initial).get(value_expected, value_expected),
2953 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2954 self.assertEqual(obj.expl_tag, expl or expl_initial)
2957 default_initial if default is None else default,
2959 if obj.default is None:
2960 optional = optional_initial if optional is None else optional
2961 optional = False if optional is None else optional
2964 self.assertEqual(obj.optional, optional)
2965 self.assertEqual(obj.specs, dict(schema_initial))
2967 @given(enumerated_values_strategy())
2968 def test_copy(self, values):
2969 schema_input, value, impl, expl, default, optional, _decoded = values
2971 class E(Enumerated):
2972 schema = schema_input
2981 obj_copied = obj.copy()
2982 self.assert_copied_basic_fields(obj, obj_copied)
2983 self.assertEqual(obj.specs, obj_copied.specs)
2985 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2986 @given(data_strategy())
2987 def test_symmetric(self, d):
2988 schema_input, _, _, _, default, optional, _decoded = d.draw(
2989 enumerated_values_strategy(),
2991 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2992 offset = d.draw(integers(min_value=0))
2993 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2994 tail_junk = d.draw(binary(max_size=5))
2996 class E(Enumerated):
2997 schema = schema_input
3006 pprint(obj, big_blobs=True, with_decode_path=True)
3007 self.assertFalse(obj.expled)
3008 obj_encoded = obj.encode()
3009 obj_expled = obj(value, expl=tag_expl)
3010 self.assertTrue(obj_expled.expled)
3012 list(obj_expled.pps())
3013 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3014 obj_expled_encoded = obj_expled.encode()
3015 ctx_copied = deepcopy(ctx_dummy)
3016 obj_decoded, tail = obj_expled.decode(
3017 obj_expled_encoded + tail_junk,
3021 self.assertDictEqual(ctx_copied, ctx_dummy)
3023 list(obj_decoded.pps())
3024 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3025 self.assertEqual(tail, tail_junk)
3026 self.assertEqual(obj_decoded, obj_expled)
3027 self.assertNotEqual(obj_decoded, obj)
3028 self.assertEqual(int(obj_decoded), int(obj_expled))
3029 self.assertEqual(int(obj_decoded), int(obj))
3030 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3031 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3032 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3034 obj_decoded.expl_llen,
3035 len(len_encode(len(obj_encoded))),
3037 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3038 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3041 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3043 self.assertEqual(obj_decoded.expl_offset, offset)
3047 def string_values_strategy(draw, alphabet, do_expl=False):
3048 bound_min, bound_max = sorted(draw(sets(
3049 integers(min_value=0, max_value=1 << 7),
3053 value = draw(one_of(
3055 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3057 default = draw(one_of(
3059 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3062 if draw(booleans()):
3063 bounds = (bound_min, bound_max)
3067 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3069 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3070 optional = draw(one_of(none(), booleans()))
3072 draw(integers(min_value=0)),
3073 draw(integers(min_value=0)),
3074 draw(integers(min_value=0)),
3076 return (value, bounds, impl, expl, default, optional, _decoded)
3079 class StringMixin(object):
3080 def test_invalid_value_type(self):
3081 with self.assertRaises(InvalidValueType) as err:
3082 self.base_klass((1, 2))
3085 def text_alphabet(self):
3086 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3087 return printable + whitespace
3091 def test_optional(self, optional):
3092 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3093 self.assertTrue(obj.optional)
3095 @given(data_strategy())
3096 def test_ready(self, d):
3097 obj = self.base_klass()
3098 self.assertFalse(obj.ready)
3101 pprint(obj, big_blobs=True, with_decode_path=True)
3103 with self.assertRaises(ObjNotReady) as err:
3106 value = d.draw(text(alphabet=self.text_alphabet()))
3107 obj = self.base_klass(value)
3108 self.assertTrue(obj.ready)
3111 pprint(obj, big_blobs=True, with_decode_path=True)
3114 @given(data_strategy())
3115 def test_comparison(self, d):
3116 value1 = d.draw(text(alphabet=self.text_alphabet()))
3117 value2 = d.draw(text(alphabet=self.text_alphabet()))
3118 tag1 = d.draw(binary(min_size=1))
3119 tag2 = d.draw(binary(min_size=1))
3120 obj1 = self.base_klass(value1)
3121 obj2 = self.base_klass(value2)
3122 self.assertEqual(obj1 == obj2, value1 == value2)
3123 self.assertEqual(obj1 != obj2, value1 != value2)
3124 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3125 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3126 obj1 = self.base_klass(value1, impl=tag1)
3127 obj2 = self.base_klass(value1, impl=tag2)
3128 self.assertEqual(obj1 == obj2, tag1 == tag2)
3129 self.assertEqual(obj1 != obj2, tag1 != tag2)
3131 @given(data_strategy())
3132 def test_bounds_satisfied(self, d):
3133 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3134 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3135 value = d.draw(text(
3136 alphabet=self.text_alphabet(),
3140 self.base_klass(value=value, bounds=(bound_min, bound_max))
3142 @given(data_strategy())
3143 def test_bounds_unsatisfied(self, d):
3144 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3145 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3146 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3147 with self.assertRaises(BoundsError) as err:
3148 self.base_klass(value=value, bounds=(bound_min, bound_max))
3150 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3151 self.base_klass(bounds=(bound_min, bound_max)).decode(
3152 self.base_klass(value).encode()
3155 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3156 with self.assertRaises(BoundsError) as err:
3157 self.base_klass(value=value, bounds=(bound_min, bound_max))
3159 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3160 self.base_klass(bounds=(bound_min, bound_max)).decode(
3161 self.base_klass(value).encode()
3165 @given(data_strategy())
3166 def test_call(self, d):
3175 ) = d.draw(string_values_strategy(self.text_alphabet()))
3176 obj_initial = self.base_klass(
3182 optional_initial or False,
3193 ) = d.draw(string_values_strategy(
3194 self.text_alphabet(),
3195 do_expl=impl_initial is None,
3197 if (default is None) and (obj_initial.default is not None):
3200 (bounds is None) and
3201 (value is not None) and
3202 (bounds_initial is not None) and
3203 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3207 (bounds is None) and
3208 (default is not None) and
3209 (bounds_initial is not None) and
3210 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3213 obj = obj_initial(value, bounds, impl, expl, default, optional)
3215 value_expected = default if value is None else value
3217 default_initial if value_expected is None
3220 self.assertEqual(obj, value_expected)
3221 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3222 self.assertEqual(obj.expl_tag, expl or expl_initial)
3225 default_initial if default is None else default,
3227 if obj.default is None:
3228 optional = optional_initial if optional is None else optional
3229 optional = False if optional is None else optional
3232 self.assertEqual(obj.optional, optional)
3234 (obj._bound_min, obj._bound_max),
3235 bounds or bounds_initial or (0, float("+inf")),
3238 @given(data_strategy())
3239 def test_copy(self, d):
3240 values = d.draw(string_values_strategy(self.text_alphabet()))
3241 obj = self.base_klass(*values)
3242 obj_copied = obj.copy()
3243 self.assert_copied_basic_fields(obj, obj_copied)
3244 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3245 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3246 self.assertEqual(obj._value, obj_copied._value)
3248 @given(data_strategy())
3249 def test_stripped(self, d):
3250 value = d.draw(text(alphabet=self.text_alphabet()))
3251 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3252 obj = self.base_klass(value, impl=tag_impl)
3253 with self.assertRaises(NotEnoughData):
3254 obj.decode(obj.encode()[:-1])
3256 @given(data_strategy())
3257 def test_stripped_expl(self, d):
3258 value = d.draw(text(alphabet=self.text_alphabet()))
3259 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3260 obj = self.base_klass(value, expl=tag_expl)
3261 with self.assertRaises(NotEnoughData):
3262 obj.decode(obj.encode()[:-1])
3265 integers(min_value=31),
3266 integers(min_value=0),
3269 def test_bad_tag(self, tag, offset, decode_path):
3270 with self.assertRaises(DecodeError) as err:
3271 self.base_klass().decode(
3272 tag_encode(tag)[:-1],
3274 decode_path=decode_path,
3277 self.assertEqual(err.exception.offset, offset)
3278 self.assertEqual(err.exception.decode_path, decode_path)
3281 integers(min_value=128),
3282 integers(min_value=0),
3285 def test_bad_len(self, l, offset, decode_path):
3286 with self.assertRaises(DecodeError) as err:
3287 self.base_klass().decode(
3288 self.base_klass.tag_default + len_encode(l)[:-1],
3290 decode_path=decode_path,
3293 self.assertEqual(err.exception.offset, offset)
3294 self.assertEqual(err.exception.decode_path, decode_path)
3297 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3298 integers(min_value=0),
3301 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3302 value, bound_min = list(sorted(ints))
3304 class String(self.base_klass):
3305 # Multiply this value by four, to satisfy UTF-32 bounds
3306 # (4 bytes per character) validation
3307 bounds = (bound_min * 4, bound_min * 4)
3308 with self.assertRaises(DecodeError) as err:
3310 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3312 decode_path=decode_path,
3315 self.assertEqual(err.exception.offset, offset)
3316 self.assertEqual(err.exception.decode_path, decode_path)
3318 @given(data_strategy())
3319 def test_symmetric(self, d):
3320 values = d.draw(string_values_strategy(self.text_alphabet()))
3321 value = d.draw(text(alphabet=self.text_alphabet()))
3322 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3323 offset = d.draw(integers(min_value=0))
3324 tail_junk = d.draw(binary(max_size=5))
3325 _, _, _, _, default, optional, _decoded = values
3326 obj = self.base_klass(
3334 pprint(obj, big_blobs=True, with_decode_path=True)
3335 self.assertFalse(obj.expled)
3336 obj_encoded = obj.encode()
3337 obj_expled = obj(value, expl=tag_expl)
3338 self.assertTrue(obj_expled.expled)
3340 list(obj_expled.pps())
3341 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3342 obj_expled_encoded = obj_expled.encode()
3343 ctx_copied = deepcopy(ctx_dummy)
3344 obj_decoded, tail = obj_expled.decode(
3345 obj_expled_encoded + tail_junk,
3349 self.assertDictEqual(ctx_copied, ctx_dummy)
3351 list(obj_decoded.pps())
3352 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3353 self.assertEqual(tail, tail_junk)
3354 self.assertEqual(obj_decoded, obj_expled)
3355 self.assertNotEqual(obj_decoded, obj)
3356 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3357 self.assertEqual(bytes(obj_decoded), bytes(obj))
3358 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3359 self.assertEqual(text_type(obj_decoded), text_type(obj))
3360 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3361 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3362 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3364 obj_decoded.expl_llen,
3365 len(len_encode(len(obj_encoded))),
3367 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3368 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3371 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3373 self.assertEqual(obj_decoded.expl_offset, offset)
3376 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3377 base_klass = UTF8String
3380 cyrillic_letters = text(
3381 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3387 class UnicodeDecodeErrorMixin(object):
3388 @given(cyrillic_letters)
3389 def test_unicode_decode_error(self, cyrillic_text):
3390 with self.assertRaises(DecodeError):
3391 self.base_klass(cyrillic_text)
3394 class TestNumericString(StringMixin, CommonMixin, TestCase):
3395 base_klass = NumericString
3397 def text_alphabet(self):
3400 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3401 def test_non_numeric(self, non_numeric_text):
3402 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3403 self.base_klass(non_numeric_text)
3406 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3407 integers(min_value=0),
3410 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3411 value, bound_min = list(sorted(ints))
3413 class String(self.base_klass):
3414 bounds = (bound_min, bound_min)
3415 with self.assertRaises(DecodeError) as err:
3417 self.base_klass(b"1" * value).encode(),
3419 decode_path=decode_path,
3422 self.assertEqual(err.exception.offset, offset)
3423 self.assertEqual(err.exception.decode_path, decode_path)
3426 class TestPrintableString(
3427 UnicodeDecodeErrorMixin,
3432 base_klass = PrintableString
3434 def text_alphabet(self):
3435 return ascii_letters + digits + " '()+,-./:=?"
3437 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3438 def test_non_printable(self, non_printable_text):
3439 with assertRaisesRegex(self, DecodeError, "non-printable"):
3440 self.base_klass(non_printable_text)
3443 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3444 integers(min_value=0),
3447 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3448 value, bound_min = list(sorted(ints))
3450 class String(self.base_klass):
3451 bounds = (bound_min, bound_min)
3452 with self.assertRaises(DecodeError) as err:
3454 self.base_klass(b"1" * value).encode(),
3456 decode_path=decode_path,
3459 self.assertEqual(err.exception.offset, offset)
3460 self.assertEqual(err.exception.decode_path, decode_path)
3463 class TestTeletexString(
3464 UnicodeDecodeErrorMixin,
3469 base_klass = TeletexString
3472 class TestVideotexString(
3473 UnicodeDecodeErrorMixin,
3478 base_klass = VideotexString
3481 class TestIA5String(
3482 UnicodeDecodeErrorMixin,
3487 base_klass = IA5String
3490 class TestGraphicString(
3491 UnicodeDecodeErrorMixin,
3496 base_klass = GraphicString
3499 class TestVisibleString(
3500 UnicodeDecodeErrorMixin,
3505 base_klass = VisibleString
3507 def test_x690_vector(self):
3508 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3509 self.assertSequenceEqual(tail, b"")
3510 self.assertEqual(str(obj), "Jones")
3511 self.assertFalse(obj.ber_encoded)
3512 self.assertFalse(obj.lenindef)
3513 self.assertFalse(obj.bered)
3515 obj, tail = VisibleString().decode(
3516 hexdec("3A0904034A6F6E04026573"),
3517 ctx={"bered": True},
3519 self.assertSequenceEqual(tail, b"")
3520 self.assertEqual(str(obj), "Jones")
3521 self.assertTrue(obj.ber_encoded)
3522 self.assertFalse(obj.lenindef)
3523 self.assertTrue(obj.bered)
3525 self.assertTrue(obj.ber_encoded)
3526 self.assertFalse(obj.lenindef)
3527 self.assertTrue(obj.bered)
3529 obj, tail = VisibleString().decode(
3530 hexdec("3A8004034A6F6E040265730000"),
3531 ctx={"bered": True},
3533 self.assertSequenceEqual(tail, b"")
3534 self.assertEqual(str(obj), "Jones")
3535 self.assertTrue(obj.ber_encoded)
3536 self.assertTrue(obj.lenindef)
3537 self.assertTrue(obj.bered)
3539 self.assertTrue(obj.ber_encoded)
3540 self.assertTrue(obj.lenindef)
3541 self.assertTrue(obj.bered)
3544 class TestGeneralString(
3545 UnicodeDecodeErrorMixin,
3550 base_klass = GeneralString
3553 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3554 base_klass = UniversalString
3557 class TestBMPString(StringMixin, CommonMixin, TestCase):
3558 base_klass = BMPString
3562 def generalized_time_values_strategy(
3570 if draw(booleans()):
3571 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3573 value = value.replace(microsecond=0)
3575 if draw(booleans()):
3576 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3578 default = default.replace(microsecond=0)
3582 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3584 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3585 optional = draw(one_of(none(), booleans()))
3587 draw(integers(min_value=0)),
3588 draw(integers(min_value=0)),
3589 draw(integers(min_value=0)),
3591 return (value, impl, expl, default, optional, _decoded)
3594 class TimeMixin(object):
3595 def test_invalid_value_type(self):
3596 with self.assertRaises(InvalidValueType) as err:
3597 self.base_klass(datetime.now().timetuple())
3600 @given(data_strategy())
3601 def test_optional(self, d):
3602 default = d.draw(datetimes(
3603 min_value=self.min_datetime,
3604 max_value=self.max_datetime,
3606 optional = d.draw(booleans())
3607 obj = self.base_klass(default=default, optional=optional)
3608 self.assertTrue(obj.optional)
3610 @given(data_strategy())
3611 def test_ready(self, d):
3612 obj = self.base_klass()
3613 self.assertFalse(obj.ready)
3616 pprint(obj, big_blobs=True, with_decode_path=True)
3617 with self.assertRaises(ObjNotReady) as err:
3620 value = d.draw(datetimes(min_value=self.min_datetime))
3621 obj = self.base_klass(value)
3622 self.assertTrue(obj.ready)
3625 pprint(obj, big_blobs=True, with_decode_path=True)
3627 @given(data_strategy())
3628 def test_comparison(self, d):
3629 value1 = d.draw(datetimes(
3630 min_value=self.min_datetime,
3631 max_value=self.max_datetime,
3633 value2 = d.draw(datetimes(
3634 min_value=self.min_datetime,
3635 max_value=self.max_datetime,
3637 tag1 = d.draw(binary(min_size=1))
3638 tag2 = d.draw(binary(min_size=1))
3640 value1 = value1.replace(microsecond=0)
3641 value2 = value2.replace(microsecond=0)
3642 obj1 = self.base_klass(value1)
3643 obj2 = self.base_klass(value2)
3644 self.assertEqual(obj1 == obj2, value1 == value2)
3645 self.assertEqual(obj1 != obj2, value1 != value2)
3646 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3647 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3648 obj1 = self.base_klass(value1, impl=tag1)
3649 obj2 = self.base_klass(value1, impl=tag2)
3650 self.assertEqual(obj1 == obj2, tag1 == tag2)
3651 self.assertEqual(obj1 != obj2, tag1 != tag2)
3653 @given(data_strategy())
3654 def test_call(self, d):
3662 ) = d.draw(generalized_time_values_strategy(
3663 min_datetime=self.min_datetime,
3664 max_datetime=self.max_datetime,
3665 omit_ms=self.omit_ms,
3667 obj_initial = self.base_klass(
3668 value=value_initial,
3671 default=default_initial,
3672 optional=optional_initial or False,
3673 _decoded=_decoded_initial,
3682 ) = d.draw(generalized_time_values_strategy(
3683 min_datetime=self.min_datetime,
3684 max_datetime=self.max_datetime,
3685 omit_ms=self.omit_ms,
3686 do_expl=impl_initial is None,
3696 value_expected = default if value is None else value
3698 default_initial if value_expected is None
3701 self.assertEqual(obj, value_expected)
3702 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3703 self.assertEqual(obj.expl_tag, expl or expl_initial)
3706 default_initial if default is None else default,
3708 if obj.default is None:
3709 optional = optional_initial if optional is None else optional
3710 optional = False if optional is None else optional
3713 self.assertEqual(obj.optional, optional)
3715 @given(data_strategy())
3716 def test_copy(self, d):
3717 values = d.draw(generalized_time_values_strategy(
3718 min_datetime=self.min_datetime,
3719 max_datetime=self.max_datetime,
3721 obj = self.base_klass(*values)
3722 obj_copied = obj.copy()
3723 self.assert_copied_basic_fields(obj, obj_copied)
3724 self.assertEqual(obj._value, obj_copied._value)
3726 @given(data_strategy())
3727 def test_stripped(self, d):
3728 value = d.draw(datetimes(
3729 min_value=self.min_datetime,
3730 max_value=self.max_datetime,
3732 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3733 obj = self.base_klass(value, impl=tag_impl)
3734 with self.assertRaises(NotEnoughData):
3735 obj.decode(obj.encode()[:-1])
3737 @given(data_strategy())
3738 def test_stripped_expl(self, d):
3739 value = d.draw(datetimes(
3740 min_value=self.min_datetime,
3741 max_value=self.max_datetime,
3743 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3744 obj = self.base_klass(value, expl=tag_expl)
3745 with self.assertRaises(NotEnoughData):
3746 obj.decode(obj.encode()[:-1])
3748 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3749 @given(data_strategy())
3750 def test_symmetric(self, d):
3751 values = d.draw(generalized_time_values_strategy(
3752 min_datetime=self.min_datetime,
3753 max_datetime=self.max_datetime,
3755 value = d.draw(datetimes(
3756 min_value=self.min_datetime,
3757 max_value=self.max_datetime,
3759 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3760 offset = d.draw(integers(min_value=0))
3761 tail_junk = d.draw(binary(max_size=5))
3762 _, _, _, default, optional, _decoded = values
3763 obj = self.base_klass(
3771 pprint(obj, big_blobs=True, with_decode_path=True)
3772 self.assertFalse(obj.expled)
3773 obj_encoded = obj.encode()
3774 self.additional_symmetric_check(value, obj_encoded)
3775 obj_expled = obj(value, expl=tag_expl)
3776 self.assertTrue(obj_expled.expled)
3778 list(obj_expled.pps())
3779 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3780 obj_expled_encoded = obj_expled.encode()
3781 ctx_copied = deepcopy(ctx_dummy)
3782 obj_decoded, tail = obj_expled.decode(
3783 obj_expled_encoded + tail_junk,
3787 self.assertDictEqual(ctx_copied, ctx_dummy)
3789 list(obj_decoded.pps())
3790 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3791 self.assertEqual(tail, tail_junk)
3792 self.assertEqual(obj_decoded, obj_expled)
3793 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3794 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3795 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3796 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3797 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3799 obj_decoded.expl_llen,
3800 len(len_encode(len(obj_encoded))),
3802 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3803 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3806 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3808 self.assertEqual(obj_decoded.expl_offset, offset)
3811 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3812 base_klass = GeneralizedTime
3814 min_datetime = datetime(1900, 1, 1)
3815 max_datetime = datetime(9999, 12, 31)
3817 def additional_symmetric_check(self, value, obj_encoded):
3818 if value.microsecond > 0:
3819 self.assertFalse(obj_encoded.endswith(b"0Z"))
3821 def test_x690_vector_valid(self):
3825 b"19920722132100.3Z",
3827 GeneralizedTime(data)
3829 def test_x690_vector_invalid(self):
3832 b"19920622123421.0Z",
3833 b"19920722132100.30Z",
3835 with self.assertRaises(DecodeError) as err:
3836 GeneralizedTime(data)
3839 def test_go_vectors_invalid(self):
3851 b"-20100102030410Z",
3852 b"2010-0102030410Z",
3853 b"2010-0002030410Z",
3854 b"201001-02030410Z",
3855 b"20100102-030410Z",
3856 b"2010010203-0410Z",
3857 b"201001020304-10Z",
3858 # These ones are INVALID in *DER*, but accepted
3859 # by Go's encoding/asn1
3860 b"20100102030405+0607",
3861 b"20100102030405-0607",
3863 with self.assertRaises(DecodeError) as err:
3864 GeneralizedTime(data)
3867 def test_go_vectors_valid(self):
3869 GeneralizedTime(b"20100102030405Z").todatetime(),
3870 datetime(2010, 1, 2, 3, 4, 5, 0),
3875 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3876 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3878 binary(min_size=1, max_size=1),
3880 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3881 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3884 def test_junk(self, part0, part1, part2):
3885 junk = part0 + part1 + part2
3886 assume(not (set(junk) <= set(digits.encode("ascii"))))
3887 with self.assertRaises(DecodeError):
3888 GeneralizedTime().decode(
3889 GeneralizedTime.tag_default +
3890 len_encode(len(junk)) +
3896 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3897 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3899 binary(min_size=1, max_size=1),
3901 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3902 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3905 def test_junk_dm(self, part0, part1, part2):
3906 junk = part0 + part1 + part2
3907 assume(not (set(junk) <= set(digits.encode("ascii"))))
3908 with self.assertRaises(DecodeError):
3909 GeneralizedTime().decode(
3910 GeneralizedTime.tag_default +
3911 len_encode(len(junk)) +
3915 def test_ns_fractions(self):
3916 GeneralizedTime(b"20010101000000.000001Z")
3917 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
3918 GeneralizedTime(b"20010101000000.0000001Z")
3921 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3922 base_klass = UTCTime
3924 min_datetime = datetime(2000, 1, 1)
3925 max_datetime = datetime(2049, 12, 31)
3927 def additional_symmetric_check(self, value, obj_encoded):
3930 def test_x690_vector_valid(self):
3938 def test_x690_vector_invalid(self):
3943 with self.assertRaises(DecodeError) as err:
3947 def test_go_vectors_invalid(self):
3973 # These ones are INVALID in *DER*, but accepted
3974 # by Go's encoding/asn1
3975 b"910506164540-0700",
3976 b"910506164540+0730",
3980 with self.assertRaises(DecodeError) as err:
3984 def test_go_vectors_valid(self):
3986 UTCTime(b"910506234540Z").todatetime(),
3987 datetime(1991, 5, 6, 23, 45, 40, 0),
3990 @given(integers(min_value=0, max_value=49))
3991 def test_pre50(self, year):
3993 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3997 @given(integers(min_value=50, max_value=99))
3998 def test_post50(self, year):
4000 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4006 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4007 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4009 binary(min_size=1, max_size=1),
4011 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4012 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4015 def test_junk(self, part0, part1, part2):
4016 junk = part0 + part1 + part2
4017 assume(not (set(junk) <= set(digits.encode("ascii"))))
4018 with self.assertRaises(DecodeError):
4020 UTCTime.tag_default +
4021 len_encode(len(junk)) +
4027 def any_values_strategy(draw, do_expl=False):
4028 value = draw(one_of(none(), binary()))
4031 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4032 optional = draw(one_of(none(), booleans()))
4034 draw(integers(min_value=0)),
4035 draw(integers(min_value=0)),
4036 draw(integers(min_value=0)),
4038 return (value, expl, optional, _decoded)
4041 class AnyInherited(Any):
4045 class TestAny(CommonMixin, TestCase):
4048 def test_invalid_value_type(self):
4049 with self.assertRaises(InvalidValueType) as err:
4054 def test_optional(self, optional):
4055 obj = Any(optional=optional)
4056 self.assertEqual(obj.optional, optional)
4059 def test_ready(self, value):
4061 self.assertFalse(obj.ready)
4064 pprint(obj, big_blobs=True, with_decode_path=True)
4065 with self.assertRaises(ObjNotReady) as err:
4069 self.assertTrue(obj.ready)
4072 pprint(obj, big_blobs=True, with_decode_path=True)
4075 def test_basic(self, value):
4076 integer_encoded = Integer(value).encode()
4078 Any(integer_encoded),
4079 Any(Integer(value)),
4080 Any(Any(Integer(value))),
4082 self.assertSequenceEqual(bytes(obj), integer_encoded)
4084 obj.decode(obj.encode())[0].vlen,
4085 len(integer_encoded),
4089 pprint(obj, big_blobs=True, with_decode_path=True)
4090 self.assertSequenceEqual(obj.encode(), integer_encoded)
4092 @given(binary(), binary())
4093 def test_comparison(self, value1, value2):
4094 for klass in (Any, AnyInherited):
4095 obj1 = klass(value1)
4096 obj2 = klass(value2)
4097 self.assertEqual(obj1 == obj2, value1 == value2)
4098 self.assertEqual(obj1 != obj2, value1 != value2)
4099 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4101 @given(data_strategy())
4102 def test_call(self, d):
4103 for klass in (Any, AnyInherited):
4109 ) = d.draw(any_values_strategy())
4110 obj_initial = klass(
4113 optional_initial or False,
4121 ) = d.draw(any_values_strategy(do_expl=True))
4122 obj = obj_initial(value, expl, optional)
4124 value_expected = None if value is None else value
4125 self.assertEqual(obj, value_expected)
4126 self.assertEqual(obj.expl_tag, expl or expl_initial)
4127 if obj.default is None:
4128 optional = optional_initial if optional is None else optional
4129 optional = False if optional is None else optional
4130 self.assertEqual(obj.optional, optional)
4132 def test_simultaneous_impl_expl(self):
4133 # override it, as Any does not have implicit tag
4136 def test_decoded(self):
4137 # override it, as Any does not have implicit tag
4140 @given(any_values_strategy())
4141 def test_copy(self, values):
4142 for klass in (Any, AnyInherited):
4143 obj = klass(*values)
4144 obj_copied = obj.copy()
4145 self.assert_copied_basic_fields(obj, obj_copied)
4146 self.assertEqual(obj._value, obj_copied._value)
4148 @given(binary().map(OctetString))
4149 def test_stripped(self, value):
4151 with self.assertRaises(NotEnoughData):
4152 obj.decode(obj.encode()[:-1])
4156 integers(min_value=1).map(tag_ctxc),
4158 def test_stripped_expl(self, value, tag_expl):
4159 obj = Any(value, expl=tag_expl)
4160 with self.assertRaises(NotEnoughData):
4161 obj.decode(obj.encode()[:-1])
4164 integers(min_value=31),
4165 integers(min_value=0),
4168 def test_bad_tag(self, tag, offset, decode_path):
4169 with self.assertRaises(DecodeError) as err:
4171 tag_encode(tag)[:-1],
4173 decode_path=decode_path,
4176 self.assertEqual(err.exception.offset, offset)
4177 self.assertEqual(err.exception.decode_path, decode_path)
4180 integers(min_value=128),
4181 integers(min_value=0),
4184 def test_bad_len(self, l, offset, decode_path):
4185 with self.assertRaises(DecodeError) as err:
4187 Any.tag_default + len_encode(l)[:-1],
4189 decode_path=decode_path,
4192 self.assertEqual(err.exception.offset, offset)
4193 self.assertEqual(err.exception.decode_path, decode_path)
4195 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4197 any_values_strategy(),
4198 integers().map(lambda x: Integer(x).encode()),
4199 integers(min_value=1).map(tag_ctxc),
4200 integers(min_value=0),
4203 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4204 for klass in (Any, AnyInherited):
4205 _, _, optional, _decoded = values
4206 obj = klass(value=value, optional=optional, _decoded=_decoded)
4209 pprint(obj, big_blobs=True, with_decode_path=True)
4210 self.assertFalse(obj.expled)
4211 obj_encoded = obj.encode()
4212 obj_expled = obj(value, expl=tag_expl)
4213 self.assertTrue(obj_expled.expled)
4215 list(obj_expled.pps())
4216 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4217 obj_expled_encoded = obj_expled.encode()
4218 ctx_copied = deepcopy(ctx_dummy)
4219 obj_decoded, tail = obj_expled.decode(
4220 obj_expled_encoded + tail_junk,
4224 self.assertDictEqual(ctx_copied, ctx_dummy)
4226 list(obj_decoded.pps())
4227 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4228 self.assertEqual(tail, tail_junk)
4229 self.assertEqual(obj_decoded, obj_expled)
4230 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4231 self.assertEqual(bytes(obj_decoded), bytes(obj))
4232 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4233 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4234 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4236 obj_decoded.expl_llen,
4237 len(len_encode(len(obj_encoded))),
4239 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4240 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4243 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4245 self.assertEqual(obj_decoded.expl_offset, offset)
4246 self.assertEqual(obj_decoded.tlen, 0)
4247 self.assertEqual(obj_decoded.llen, 0)
4248 self.assertEqual(obj_decoded.vlen, len(value))
4251 integers(min_value=1).map(tag_ctxc),
4252 integers(min_value=0, max_value=3),
4253 integers(min_value=0),
4257 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4258 chunk = Boolean(False, expl=expl).encode()
4260 OctetString.tag_default +
4262 b"".join([chunk] * chunks) +
4265 with self.assertRaises(LenIndefForm):
4269 decode_path=decode_path,
4271 obj, tail = Any().decode(
4274 decode_path=decode_path,
4275 ctx={"bered": True},
4277 self.assertSequenceEqual(tail, junk)
4278 self.assertEqual(obj.offset, offset)
4279 self.assertEqual(obj.tlvlen, len(encoded))
4280 self.assertTrue(obj.lenindef)
4281 self.assertFalse(obj.ber_encoded)
4282 self.assertTrue(obj.bered)
4284 self.assertTrue(obj.lenindef)
4285 self.assertFalse(obj.ber_encoded)
4286 self.assertTrue(obj.bered)
4289 pprint(obj, big_blobs=True, with_decode_path=True)
4290 with self.assertRaises(NotEnoughData) as err:
4294 decode_path=decode_path,
4295 ctx={"bered": True},
4297 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4298 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4300 class SeqOf(SequenceOf):
4301 schema = Boolean(expl=expl)
4303 class Seq(Sequence):
4305 ("type", ObjectIdentifier(defines=((("value",), {
4306 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4311 ("type", ObjectIdentifier("1.2.3")),
4312 ("value", Any(encoded)),
4314 seq_encoded = seq.encode()
4315 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4316 self.assertIsNotNone(seq_decoded["value"].defined)
4318 list(seq_decoded.pps())
4319 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4320 self.assertTrue(seq_decoded.bered)
4321 self.assertFalse(seq_decoded["type"].bered)
4322 self.assertTrue(seq_decoded["value"].bered)
4324 chunk = chunk[:-1] + b"\x01"
4325 chunks = b"".join([chunk] * (chunks + 1))
4326 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4328 ("type", ObjectIdentifier("1.2.3")),
4329 ("value", Any(encoded)),
4331 seq_encoded = seq.encode()
4332 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4333 self.assertIsNotNone(seq_decoded["value"].defined)
4335 list(seq_decoded.pps())
4336 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4337 self.assertTrue(seq_decoded.bered)
4338 self.assertFalse(seq_decoded["type"].bered)
4339 self.assertTrue(seq_decoded["value"].bered)
4343 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4345 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4346 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4348 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4349 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4351 min_size=len(names),
4352 max_size=len(names),
4355 (name, Integer(**tag_kwargs))
4356 for name, tag_kwargs in zip(names, tags)
4359 if value_required or draw(booleans()):
4360 value = draw(tuples(
4361 sampled_from([name for name, _ in schema]),
4362 integers().map(Integer),
4366 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4367 default = draw(one_of(
4369 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4371 optional = draw(one_of(none(), booleans()))
4373 draw(integers(min_value=0)),
4374 draw(integers(min_value=0)),
4375 draw(integers(min_value=0)),
4377 return (schema, value, expl, default, optional, _decoded)
4380 class ChoiceInherited(Choice):
4384 class TestChoice(CommonMixin, TestCase):
4386 schema = (("whatever", Boolean()),)
4389 def test_schema_required(self):
4390 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4393 def test_impl_forbidden(self):
4394 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4395 Choice(impl=b"whatever")
4397 def test_invalid_value_type(self):
4398 with self.assertRaises(InvalidValueType) as err:
4399 self.base_klass(123)
4401 with self.assertRaises(ObjUnknown) as err:
4402 self.base_klass(("whenever", Boolean(False)))
4404 with self.assertRaises(InvalidValueType) as err:
4405 self.base_klass(("whatever", Integer(123)))
4409 def test_optional(self, optional):
4410 obj = self.base_klass(
4411 default=self.base_klass(("whatever", Boolean(False))),
4414 self.assertTrue(obj.optional)
4417 def test_ready(self, value):
4418 obj = self.base_klass()
4419 self.assertFalse(obj.ready)
4422 pprint(obj, big_blobs=True, with_decode_path=True)
4423 self.assertIsNone(obj["whatever"])
4424 with self.assertRaises(ObjNotReady) as err:
4427 obj["whatever"] = Boolean()
4428 self.assertFalse(obj.ready)
4431 pprint(obj, big_blobs=True, with_decode_path=True)
4432 obj["whatever"] = Boolean(value)
4433 self.assertTrue(obj.ready)
4436 pprint(obj, big_blobs=True, with_decode_path=True)
4438 @given(booleans(), booleans())
4439 def test_comparison(self, value1, value2):
4440 class WahlInherited(self.base_klass):
4442 for klass in (self.base_klass, WahlInherited):
4443 obj1 = klass(("whatever", Boolean(value1)))
4444 obj2 = klass(("whatever", Boolean(value2)))
4445 self.assertEqual(obj1 == obj2, value1 == value2)
4446 self.assertEqual(obj1 != obj2, value1 != value2)
4447 self.assertEqual(obj1 == obj2._value, value1 == value2)
4448 self.assertFalse(obj1 == obj2._value[1])
4450 @given(data_strategy())
4451 def test_call(self, d):
4452 for klass in (Choice, ChoiceInherited):
4460 ) = d.draw(choice_values_strategy())
4463 schema = schema_initial
4465 value=value_initial,
4467 default=default_initial,
4468 optional=optional_initial or False,
4469 _decoded=_decoded_initial,
4478 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4479 obj = obj_initial(value, expl, default, optional)
4481 value_expected = default if value is None else value
4483 default_initial if value_expected is None
4486 self.assertEqual(obj.choice, value_expected[0])
4487 self.assertEqual(obj.value, int(value_expected[1]))
4488 self.assertEqual(obj.expl_tag, expl or expl_initial)
4489 default_expect = default_initial if default is None else default
4490 if default_expect is not None:
4491 self.assertEqual(obj.default.choice, default_expect[0])
4492 self.assertEqual(obj.default.value, int(default_expect[1]))
4493 if obj.default is None:
4494 optional = optional_initial if optional is None else optional
4495 optional = False if optional is None else optional
4498 self.assertEqual(obj.optional, optional)
4499 self.assertEqual(obj.specs, obj_initial.specs)
4501 def test_simultaneous_impl_expl(self):
4502 # override it, as Any does not have implicit tag
4505 def test_decoded(self):
4506 # override it, as Any does not have implicit tag
4509 @given(choice_values_strategy())
4510 def test_copy(self, values):
4511 _schema, value, expl, default, optional, _decoded = values
4513 class Wahl(self.base_klass):
4519 optional=optional or False,
4522 obj_copied = obj.copy()
4523 self.assertIsNone(obj.tag)
4524 self.assertIsNone(obj_copied.tag)
4525 # hack for assert_copied_basic_fields
4526 obj.tag = "whatever"
4527 obj_copied.tag = "whatever"
4528 self.assert_copied_basic_fields(obj, obj_copied)
4529 self.assertEqual(obj._value, obj_copied._value)
4530 self.assertEqual(obj.specs, obj_copied.specs)
4533 def test_stripped(self, value):
4534 obj = self.base_klass(("whatever", Boolean(value)))
4535 with self.assertRaises(NotEnoughData):
4536 obj.decode(obj.encode()[:-1])
4540 integers(min_value=1).map(tag_ctxc),
4542 def test_stripped_expl(self, value, tag_expl):
4543 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4544 with self.assertRaises(NotEnoughData):
4545 obj.decode(obj.encode()[:-1])
4547 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4548 @given(data_strategy())
4549 def test_symmetric(self, d):
4550 _schema, value, _, default, optional, _decoded = d.draw(
4551 choice_values_strategy(value_required=True)
4553 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4554 offset = d.draw(integers(min_value=0))
4555 tail_junk = d.draw(binary(max_size=5))
4557 class Wahl(self.base_klass):
4567 pprint(obj, big_blobs=True, with_decode_path=True)
4568 self.assertFalse(obj.expled)
4569 obj_encoded = obj.encode()
4570 obj_expled = obj(value, expl=tag_expl)
4571 self.assertTrue(obj_expled.expled)
4573 list(obj_expled.pps())
4574 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4575 obj_expled_encoded = obj_expled.encode()
4576 ctx_copied = deepcopy(ctx_dummy)
4577 obj_decoded, tail = obj_expled.decode(
4578 obj_expled_encoded + tail_junk,
4582 self.assertDictEqual(ctx_copied, ctx_dummy)
4584 list(obj_decoded.pps())
4585 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4586 self.assertEqual(tail, tail_junk)
4587 self.assertEqual(obj_decoded, obj_expled)
4588 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4589 self.assertEqual(obj_decoded.value, obj_expled.value)
4590 self.assertEqual(obj_decoded.choice, obj.choice)
4591 self.assertEqual(obj_decoded.value, obj.value)
4592 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4593 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4594 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4596 obj_decoded.expl_llen,
4597 len(len_encode(len(obj_encoded))),
4599 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4600 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4603 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4605 self.assertEqual(obj_decoded.expl_offset, offset)
4606 self.assertSequenceEqual(
4608 obj_decoded.value.fulloffset - offset:
4609 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4615 def test_set_get(self, value):
4618 ("erste", Boolean()),
4619 ("zweite", Integer()),
4622 with self.assertRaises(ObjUnknown) as err:
4623 obj["whatever"] = "whenever"
4624 with self.assertRaises(InvalidValueType) as err:
4625 obj["zweite"] = Boolean(False)
4626 obj["zweite"] = Integer(value)
4628 with self.assertRaises(ObjUnknown) as err:
4631 self.assertIsNone(obj["erste"])
4632 self.assertEqual(obj["zweite"], Integer(value))
4634 def test_tag_mismatch(self):
4637 ("erste", Boolean()),
4639 int_encoded = Integer(123).encode()
4640 bool_encoded = Boolean(False).encode()
4642 obj.decode(bool_encoded)
4643 with self.assertRaises(TagMismatch):
4644 obj.decode(int_encoded)
4646 def test_tag_mismatch_underlying(self):
4647 class SeqOfBoolean(SequenceOf):
4650 class SeqOfInteger(SequenceOf):
4655 ("erste", SeqOfBoolean()),
4658 int_encoded = SeqOfInteger((Integer(123),)).encode()
4659 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4661 obj.decode(bool_encoded)
4662 with self.assertRaises(TagMismatch) as err:
4663 obj.decode(int_encoded)
4664 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4668 def seq_values_strategy(draw, seq_klass, do_expl=False):
4670 if draw(booleans()):
4672 value._value = draw(dictionaries(
4675 booleans().map(Boolean),
4676 integers().map(Integer),
4680 if draw(booleans()):
4681 schema = list(draw(dictionaries(
4684 booleans().map(Boolean),
4685 integers().map(Integer),
4691 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4693 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4695 if draw(booleans()):
4696 default = seq_klass()
4697 default._value = draw(dictionaries(
4700 booleans().map(Boolean),
4701 integers().map(Integer),
4704 optional = draw(one_of(none(), booleans()))
4706 draw(integers(min_value=0)),
4707 draw(integers(min_value=0)),
4708 draw(integers(min_value=0)),
4710 return (value, schema, impl, expl, default, optional, _decoded)
4714 def sequence_strategy(draw, seq_klass):
4715 inputs = draw(lists(
4717 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4718 tuples(just(Integer), integers(), one_of(none(), integers())),
4723 integers(min_value=1),
4724 min_size=len(inputs),
4725 max_size=len(inputs),
4728 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4729 for tag, expled in zip(tags, draw(lists(
4731 min_size=len(inputs),
4732 max_size=len(inputs),
4736 for i, optional in enumerate(draw(lists(
4737 sampled_from(("required", "optional", "empty")),
4738 min_size=len(inputs),
4739 max_size=len(inputs),
4741 if optional in ("optional", "empty"):
4742 inits[i]["optional"] = True
4743 if optional == "empty":
4745 empties = set(empties)
4746 names = list(draw(sets(
4748 min_size=len(inputs),
4749 max_size=len(inputs),
4752 for i, (klass, value, default) in enumerate(inputs):
4753 schema.append((names[i], klass(default=default, **inits[i])))
4754 seq_name = draw(text_letters())
4755 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4758 for i, (klass, value, default) in enumerate(inputs):
4765 "default_value": None if spec.default is None else default,
4769 expect["optional"] = True
4771 expect["presented"] = True
4772 expect["value"] = value
4774 expect["optional"] = True
4775 if default is not None and default == value:
4776 expect["presented"] = False
4777 seq[name] = klass(value)
4778 expects.append(expect)
4783 def sequences_strategy(draw, seq_klass):
4784 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4786 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4787 for tag, expled in zip(tags, draw(lists(
4794 i for i, is_default in enumerate(draw(lists(
4800 names = list(draw(sets(
4805 seq_expectses = draw(lists(
4806 sequence_strategy(seq_klass=seq_klass),
4810 seqs = [seq for seq, _ in seq_expectses]
4812 for i, (name, seq) in enumerate(zip(names, seqs)):
4815 seq(default=(seq if i in defaulted else None), **inits[i]),
4817 seq_name = draw(text_letters())
4818 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4821 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4824 "expects": expects_inner,
4827 seq_outer[name] = seq_inner
4828 if seq_outer.specs[name].default is None:
4829 expect["presented"] = True
4830 expect_outers.append(expect)
4831 return seq_outer, expect_outers
4834 class SeqMixing(object):
4835 def test_invalid_value_type(self):
4836 with self.assertRaises(InvalidValueType) as err:
4837 self.base_klass(123)
4840 def test_invalid_value_type_set(self):
4841 class Seq(self.base_klass):
4842 schema = (("whatever", Boolean()),)
4844 with self.assertRaises(InvalidValueType) as err:
4845 seq["whatever"] = Integer(123)
4849 def test_optional(self, optional):
4850 obj = self.base_klass(default=self.base_klass(), optional=optional)
4851 self.assertTrue(obj.optional)
4853 @given(data_strategy())
4854 def test_ready(self, d):
4856 str(i): v for i, v in enumerate(d.draw(lists(
4863 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4870 for name in d.draw(permutations(
4871 list(ready.keys()) + list(non_ready.keys()),
4873 schema_input.append((name, Boolean()))
4875 class Seq(self.base_klass):
4876 schema = tuple(schema_input)
4878 for name in ready.keys():
4880 seq[name] = Boolean()
4881 self.assertFalse(seq.ready)
4884 pprint(seq, big_blobs=True, with_decode_path=True)
4885 for name, value in ready.items():
4886 seq[name] = Boolean(value)
4887 self.assertFalse(seq.ready)
4890 pprint(seq, big_blobs=True, with_decode_path=True)
4891 with self.assertRaises(ObjNotReady) as err:
4894 for name, value in non_ready.items():
4895 seq[name] = Boolean(value)
4896 self.assertTrue(seq.ready)
4899 pprint(seq, big_blobs=True, with_decode_path=True)
4901 @given(data_strategy())
4902 def test_call(self, d):
4903 class SeqInherited(self.base_klass):
4905 for klass in (self.base_klass, SeqInherited):
4914 ) = d.draw(seq_values_strategy(seq_klass=klass))
4915 obj_initial = klass(
4921 optional_initial or False,
4932 ) = d.draw(seq_values_strategy(
4934 do_expl=impl_initial is None,
4936 obj = obj_initial(value, impl, expl, default, optional)
4937 value_expected = default if value is None else value
4939 default_initial if value_expected is None
4942 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4943 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4944 self.assertEqual(obj.expl_tag, expl or expl_initial)
4946 {} if obj.default is None else obj.default._value,
4947 getattr(default_initial if default is None else default, "_value", {}),
4949 if obj.default is None:
4950 optional = optional_initial if optional is None else optional
4951 optional = False if optional is None else optional
4954 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4955 self.assertEqual(obj.optional, optional)
4957 @given(data_strategy())
4958 def test_copy(self, d):
4959 class SeqInherited(self.base_klass):
4961 for klass in (self.base_klass, SeqInherited):
4962 values = d.draw(seq_values_strategy(seq_klass=klass))
4963 obj = klass(*values)
4964 obj_copied = obj.copy()
4965 self.assert_copied_basic_fields(obj, obj_copied)
4966 self.assertEqual(obj.specs, obj_copied.specs)
4967 self.assertEqual(obj._value, obj_copied._value)
4969 @given(data_strategy())
4970 def test_stripped(self, d):
4971 value = d.draw(integers())
4972 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4974 class Seq(self.base_klass):
4976 schema = (("whatever", Integer()),)
4978 seq["whatever"] = Integer(value)
4979 with self.assertRaises(NotEnoughData):
4980 seq.decode(seq.encode()[:-1])
4982 @given(data_strategy())
4983 def test_stripped_expl(self, d):
4984 value = d.draw(integers())
4985 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4987 class Seq(self.base_klass):
4989 schema = (("whatever", Integer()),)
4991 seq["whatever"] = Integer(value)
4992 with self.assertRaises(NotEnoughData):
4993 seq.decode(seq.encode()[:-1])
4995 @given(binary(min_size=2))
4996 def test_non_tag_mismatch_raised(self, junk):
4998 _, _, len_encoded = tag_strip(memoryview(junk))
4999 len_decode(len_encoded)
5005 class Seq(self.base_klass):
5007 ("whatever", Integer()),
5009 ("whenever", Integer()),
5012 seq["whatever"] = Integer(123)
5013 seq["junk"] = Any(junk)
5014 seq["whenever"] = Integer(123)
5015 with self.assertRaises(DecodeError):
5016 seq.decode(seq.encode())
5019 integers(min_value=31),
5020 integers(min_value=0),
5023 def test_bad_tag(self, tag, offset, decode_path):
5024 with self.assertRaises(DecodeError) as err:
5025 self.base_klass().decode(
5026 tag_encode(tag)[:-1],
5028 decode_path=decode_path,
5031 self.assertEqual(err.exception.offset, offset)
5032 self.assertEqual(err.exception.decode_path, decode_path)
5035 integers(min_value=128),
5036 integers(min_value=0),
5039 def test_bad_len(self, l, offset, decode_path):
5040 with self.assertRaises(DecodeError) as err:
5041 self.base_klass().decode(
5042 self.base_klass.tag_default + len_encode(l)[:-1],
5044 decode_path=decode_path,
5047 self.assertEqual(err.exception.offset, offset)
5048 self.assertEqual(err.exception.decode_path, decode_path)
5050 def _assert_expects(self, seq, expects):
5051 for expect in expects:
5053 seq.specs[expect["name"]].optional,
5056 if expect["default_value"] is not None:
5058 seq.specs[expect["name"]].default,
5059 expect["default_value"],
5061 if expect["presented"]:
5062 self.assertIn(expect["name"], seq)
5063 self.assertEqual(seq[expect["name"]], expect["value"])
5065 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5066 @given(data_strategy())
5067 def test_symmetric(self, d):
5068 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5069 tail_junk = d.draw(binary(max_size=5))
5070 self.assertTrue(seq.ready)
5071 self.assertFalse(seq.decoded)
5072 self._assert_expects(seq, expects)
5075 pprint(seq, big_blobs=True, with_decode_path=True)
5076 self.assertTrue(seq.ready)
5077 seq_encoded = seq.encode()
5078 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5079 self.assertFalse(seq_decoded.lenindef)
5080 self.assertFalse(seq_decoded.ber_encoded)
5081 self.assertFalse(seq_decoded.bered)
5083 t, _, lv = tag_strip(seq_encoded)
5084 _, _, v = len_decode(lv)
5085 seq_encoded_lenindef = t + LENINDEF + v + EOC
5086 ctx_copied = deepcopy(ctx_dummy)
5087 ctx_copied["bered"] = True
5088 seq_decoded_lenindef, tail_lenindef = seq.decode(
5089 seq_encoded_lenindef + tail_junk,
5092 del ctx_copied["bered"]
5093 self.assertDictEqual(ctx_copied, ctx_dummy)
5094 self.assertTrue(seq_decoded_lenindef.lenindef)
5095 self.assertTrue(seq_decoded_lenindef.bered)
5096 seq_decoded_lenindef = seq_decoded_lenindef.copy()
5097 self.assertTrue(seq_decoded_lenindef.lenindef)
5098 self.assertTrue(seq_decoded_lenindef.bered)
5099 with self.assertRaises(DecodeError):
5100 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5101 with self.assertRaises(DecodeError):
5102 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5103 repr(seq_decoded_lenindef)
5104 list(seq_decoded_lenindef.pps())
5105 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5106 self.assertTrue(seq_decoded_lenindef.ready)
5108 for decoded, decoded_tail, encoded in (
5109 (seq_decoded, tail, seq_encoded),
5110 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5112 self.assertEqual(decoded_tail, tail_junk)
5113 self._assert_expects(decoded, expects)
5114 self.assertEqual(seq, decoded)
5115 self.assertEqual(decoded.encode(), seq_encoded)
5116 self.assertEqual(decoded.tlvlen, len(encoded))
5117 for expect in expects:
5118 if not expect["presented"]:
5119 self.assertNotIn(expect["name"], decoded)
5121 self.assertIn(expect["name"], decoded)
5122 obj = decoded[expect["name"]]
5123 self.assertTrue(obj.decoded)
5124 offset = obj.expl_offset if obj.expled else obj.offset
5125 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5126 self.assertSequenceEqual(
5127 seq_encoded[offset:offset + tlvlen],
5131 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5132 @given(data_strategy())
5133 def test_symmetric_with_seq(self, d):
5134 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5135 self.assertTrue(seq.ready)
5136 seq_encoded = seq.encode()
5137 seq_decoded, tail = seq.decode(seq_encoded)
5138 self.assertEqual(tail, b"")
5139 self.assertTrue(seq.ready)
5140 self.assertEqual(seq, seq_decoded)
5141 self.assertEqual(seq_decoded.encode(), seq_encoded)
5142 for expect_outer in expect_outers:
5143 if not expect_outer["presented"]:
5144 self.assertNotIn(expect_outer["name"], seq_decoded)
5146 self.assertIn(expect_outer["name"], seq_decoded)
5147 obj = seq_decoded[expect_outer["name"]]
5148 self.assertTrue(obj.decoded)
5149 offset = obj.expl_offset if obj.expled else obj.offset
5150 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5151 self.assertSequenceEqual(
5152 seq_encoded[offset:offset + tlvlen],
5155 self._assert_expects(obj, expect_outer["expects"])
5157 @given(data_strategy())
5158 def test_default_disappears(self, d):
5159 _schema = list(d.draw(dictionaries(
5161 sets(integers(), min_size=2, max_size=2),
5165 class Seq(self.base_klass):
5167 (n, Integer(default=d))
5168 for n, (_, d) in _schema
5171 for name, (value, _) in _schema:
5172 seq[name] = Integer(value)
5173 self.assertEqual(len(seq._value), len(_schema))
5174 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5175 self.assertGreater(len(seq.encode()), len(empty_seq))
5176 for name, (_, default) in _schema:
5177 seq[name] = Integer(default)
5178 self.assertEqual(len(seq._value), 0)
5179 self.assertSequenceEqual(seq.encode(), empty_seq)
5181 @given(data_strategy())
5182 def test_encoded_default_not_accepted(self, d):
5183 _schema = list(d.draw(dictionaries(
5188 tags = [tag_encode(tag) for tag in d.draw(sets(
5189 integers(min_value=0),
5190 min_size=len(_schema),
5191 max_size=len(_schema),
5194 class SeqWithoutDefault(self.base_klass):
5196 (n, Integer(impl=t))
5197 for (n, _), t in zip(_schema, tags)
5199 seq_without_default = SeqWithoutDefault()
5200 for name, value in _schema:
5201 seq_without_default[name] = Integer(value)
5202 seq_encoded = seq_without_default.encode()
5204 class SeqWithDefault(self.base_klass):
5206 (n, Integer(default=v, impl=t))
5207 for (n, v), t in zip(_schema, tags)
5209 seq_with_default = SeqWithDefault()
5210 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5211 seq_with_default.decode(seq_encoded)
5212 for ctx in ({"bered": True}, {"allow_default_values": True}):
5213 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5214 self.assertTrue(seq_decoded.ber_encoded)
5215 self.assertTrue(seq_decoded.bered)
5216 seq_decoded = seq_decoded.copy()
5217 self.assertTrue(seq_decoded.ber_encoded)
5218 self.assertTrue(seq_decoded.bered)
5219 for name, value in _schema:
5220 self.assertEqual(seq_decoded[name], seq_with_default[name])
5221 self.assertEqual(seq_decoded[name], value)
5223 @given(data_strategy())
5224 def test_missing_from_spec(self, d):
5225 names = list(d.draw(sets(text_letters(), min_size=2)))
5226 tags = [tag_encode(tag) for tag in d.draw(sets(
5227 integers(min_value=0),
5228 min_size=len(names),
5229 max_size=len(names),
5231 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5233 class SeqFull(self.base_klass):
5234 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5235 seq_full = SeqFull()
5236 for i, name in enumerate(names):
5237 seq_full[name] = Integer(i)
5238 seq_encoded = seq_full.encode()
5239 altered = names_tags[:-2] + names_tags[-1:]
5241 class SeqMissing(self.base_klass):
5242 schema = [(n, Integer(impl=t)) for n, t in altered]
5243 seq_missing = SeqMissing()
5244 with self.assertRaises(TagMismatch):
5245 seq_missing.decode(seq_encoded)
5247 def test_bered(self):
5248 class Seq(self.base_klass):
5249 schema = (("underlying", Boolean()),)
5250 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5251 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5252 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5253 self.assertFalse(decoded.ber_encoded)
5254 self.assertFalse(decoded.lenindef)
5255 self.assertTrue(decoded.bered)
5256 decoded = decoded.copy()
5257 self.assertFalse(decoded.ber_encoded)
5258 self.assertFalse(decoded.lenindef)
5259 self.assertTrue(decoded.bered)
5261 class Seq(self.base_klass):
5262 schema = (("underlying", OctetString()),)
5264 tag_encode(form=TagFormConstructed, num=4) +
5266 OctetString(b"whatever").encode() +
5269 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5270 with self.assertRaises(DecodeError):
5271 Seq().decode(encoded)
5272 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5273 self.assertFalse(decoded.ber_encoded)
5274 self.assertFalse(decoded.lenindef)
5275 self.assertTrue(decoded.bered)
5276 decoded = decoded.copy()
5277 self.assertFalse(decoded.ber_encoded)
5278 self.assertFalse(decoded.lenindef)
5279 self.assertTrue(decoded.bered)
5282 class TestSequence(SeqMixing, CommonMixin, TestCase):
5283 base_klass = Sequence
5289 def test_remaining(self, value, junk):
5290 class Seq(Sequence):
5292 ("whatever", Integer()),
5294 int_encoded = Integer(value).encode()
5296 Sequence.tag_default,
5297 len_encode(len(int_encoded + junk)),
5300 with assertRaisesRegex(self, DecodeError, "remaining"):
5301 Seq().decode(junked)
5303 @given(sets(text_letters(), min_size=2))
5304 def test_obj_unknown(self, names):
5305 missing = names.pop()
5307 class Seq(Sequence):
5308 schema = [(n, Boolean()) for n in names]
5310 with self.assertRaises(ObjUnknown) as err:
5313 with self.assertRaises(ObjUnknown) as err:
5314 seq[missing] = Boolean()
5317 def test_x690_vector(self):
5318 class Seq(Sequence):
5320 ("name", IA5String()),
5323 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5324 self.assertEqual(seq["name"], "Smith")
5325 self.assertEqual(seq["ok"], True)
5328 class TestSet(SeqMixing, CommonMixin, TestCase):
5331 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5332 @given(data_strategy())
5333 def test_sorted(self, d):
5335 tag_encode(tag) for tag in
5336 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5340 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5342 for name, _ in Seq.schema:
5343 seq[name] = OctetString(b"")
5344 seq_encoded = seq.encode()
5345 seq_decoded, _ = seq.decode(seq_encoded)
5346 self.assertSequenceEqual(
5347 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5348 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5351 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5352 @given(data_strategy())
5353 def test_unsorted(self, d):
5355 tag_encode(tag) for tag in
5356 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5358 tags = d.draw(permutations(tags))
5359 assume(tags != sorted(tags))
5360 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5361 seq_encoded = b"".join((
5363 len_encode(len(encoded)),
5368 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5370 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5371 seq.decode(seq_encoded)
5372 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5373 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5374 self.assertTrue(seq_decoded.ber_encoded)
5375 self.assertTrue(seq_decoded.bered)
5376 seq_decoded = seq_decoded.copy()
5377 self.assertTrue(seq_decoded.ber_encoded)
5378 self.assertTrue(seq_decoded.bered)
5379 self.assertSequenceEqual(
5380 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5386 def seqof_values_strategy(draw, schema=None, do_expl=False):
5388 schema = draw(sampled_from((Boolean(), Integer())))
5389 bound_min, bound_max = sorted(draw(sets(
5390 integers(min_value=0, max_value=10),
5394 if isinstance(schema, Boolean):
5395 values_generator = booleans().map(Boolean)
5396 elif isinstance(schema, Integer):
5397 values_generator = integers().map(Integer)
5398 values_generator = lists(
5403 values = draw(one_of(none(), values_generator))
5407 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5409 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5410 default = draw(one_of(none(), values_generator))
5411 optional = draw(one_of(none(), booleans()))
5413 draw(integers(min_value=0)),
5414 draw(integers(min_value=0)),
5415 draw(integers(min_value=0)),
5420 (bound_min, bound_max),
5429 class SeqOfMixing(object):
5430 def test_invalid_value_type(self):
5431 with self.assertRaises(InvalidValueType) as err:
5432 self.base_klass(123)
5435 def test_invalid_values_type(self):
5436 class SeqOf(self.base_klass):
5438 with self.assertRaises(InvalidValueType) as err:
5439 SeqOf([Integer(123), Boolean(False), Integer(234)])
5442 def test_schema_required(self):
5443 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5444 self.base_klass.__mro__[1]()
5446 @given(booleans(), booleans(), binary(), binary())
5447 def test_comparison(self, value1, value2, tag1, tag2):
5448 class SeqOf(self.base_klass):
5450 obj1 = SeqOf([Boolean(value1)])
5451 obj2 = SeqOf([Boolean(value2)])
5452 self.assertEqual(obj1 == obj2, value1 == value2)
5453 self.assertEqual(obj1 != obj2, value1 != value2)
5454 self.assertEqual(obj1 == list(obj2), value1 == value2)
5455 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5456 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5457 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5458 self.assertEqual(obj1 == obj2, tag1 == tag2)
5459 self.assertEqual(obj1 != obj2, tag1 != tag2)
5461 @given(lists(booleans()))
5462 def test_iter(self, values):
5463 class SeqOf(self.base_klass):
5465 obj = SeqOf([Boolean(value) for value in values])
5466 self.assertEqual(len(obj), len(values))
5467 for i, value in enumerate(obj):
5468 self.assertEqual(value, values[i])
5470 @given(data_strategy())
5471 def test_ready(self, d):
5472 ready = [Integer(v) for v in d.draw(lists(
5479 range(d.draw(integers(min_value=1, max_value=5)))
5482 class SeqOf(self.base_klass):
5484 values = d.draw(permutations(ready + non_ready))
5486 for value in values:
5488 self.assertFalse(seqof.ready)
5491 pprint(seqof, big_blobs=True, with_decode_path=True)
5492 with self.assertRaises(ObjNotReady) as err:
5495 for i, value in enumerate(values):
5496 self.assertEqual(seqof[i], value)
5497 if not seqof[i].ready:
5498 seqof[i] = Integer(i)
5499 self.assertTrue(seqof.ready)
5502 pprint(seqof, big_blobs=True, with_decode_path=True)
5504 def test_spec_mismatch(self):
5505 class SeqOf(self.base_klass):
5508 seqof.append(Integer(123))
5509 with self.assertRaises(ValueError):
5510 seqof.append(Boolean(False))
5511 with self.assertRaises(ValueError):
5512 seqof[0] = Boolean(False)
5514 @given(data_strategy())
5515 def test_bounds_satisfied(self, d):
5516 class SeqOf(self.base_klass):
5518 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5519 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5520 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5521 SeqOf(value=value, bounds=(bound_min, bound_max))
5523 @given(data_strategy())
5524 def test_bounds_unsatisfied(self, d):
5525 class SeqOf(self.base_klass):
5527 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5528 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5529 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5530 with self.assertRaises(BoundsError) as err:
5531 SeqOf(value=value, bounds=(bound_min, bound_max))
5533 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5534 SeqOf(bounds=(bound_min, bound_max)).decode(
5535 SeqOf(value).encode()
5538 value = [Boolean(True)] * d.draw(integers(
5539 min_value=bound_max + 1,
5540 max_value=bound_max + 10,
5542 with self.assertRaises(BoundsError) as err:
5543 SeqOf(value=value, bounds=(bound_min, bound_max))
5545 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5546 SeqOf(bounds=(bound_min, bound_max)).decode(
5547 SeqOf(value).encode()
5551 @given(integers(min_value=1, max_value=10))
5552 def test_out_of_bounds(self, bound_max):
5553 class SeqOf(self.base_klass):
5555 bounds = (0, bound_max)
5557 for _ in range(bound_max):
5558 seqof.append(Integer(123))
5559 with self.assertRaises(BoundsError):
5560 seqof.append(Integer(123))
5562 @given(data_strategy())
5563 def test_call(self, d):
5573 ) = d.draw(seqof_values_strategy())
5575 class SeqOf(self.base_klass):
5576 schema = schema_initial
5577 obj_initial = SeqOf(
5578 value=value_initial,
5579 bounds=bounds_initial,
5582 default=default_initial,
5583 optional=optional_initial or False,
5584 _decoded=_decoded_initial,
5595 ) = d.draw(seqof_values_strategy(
5596 schema=schema_initial,
5597 do_expl=impl_initial is None,
5599 if (default is None) and (obj_initial.default is not None):
5602 (bounds is None) and
5603 (value is not None) and
5604 (bounds_initial is not None) and
5605 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5609 (bounds is None) and
5610 (default is not None) and
5611 (bounds_initial is not None) and
5612 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5624 value_expected = default if value is None else value
5626 default_initial if value_expected is None
5629 value_expected = () if value_expected is None else value_expected
5630 self.assertEqual(obj, value_expected)
5631 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5632 self.assertEqual(obj.expl_tag, expl or expl_initial)
5635 default_initial if default is None else default,
5637 if obj.default is None:
5638 optional = optional_initial if optional is None else optional
5639 optional = False if optional is None else optional
5642 self.assertEqual(obj.optional, optional)
5644 (obj._bound_min, obj._bound_max),
5645 bounds or bounds_initial or (0, float("+inf")),
5648 @given(seqof_values_strategy())
5649 def test_copy(self, values):
5650 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5652 class SeqOf(self.base_klass):
5660 optional=optional or False,
5663 obj_copied = obj.copy()
5664 self.assert_copied_basic_fields(obj, obj_copied)
5665 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5666 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5667 self.assertEqual(obj._value, obj_copied._value)
5671 integers(min_value=1).map(tag_encode),
5673 def test_stripped(self, values, tag_impl):
5674 class SeqOf(self.base_klass):
5675 schema = OctetString()
5676 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5677 with self.assertRaises(NotEnoughData):
5678 obj.decode(obj.encode()[:-1])
5682 integers(min_value=1).map(tag_ctxc),
5684 def test_stripped_expl(self, values, tag_expl):
5685 class SeqOf(self.base_klass):
5686 schema = OctetString()
5687 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5688 with self.assertRaises(NotEnoughData):
5689 obj.decode(obj.encode()[:-1])
5692 integers(min_value=31),
5693 integers(min_value=0),
5696 def test_bad_tag(self, tag, offset, decode_path):
5697 with self.assertRaises(DecodeError) as err:
5698 self.base_klass().decode(
5699 tag_encode(tag)[:-1],
5701 decode_path=decode_path,
5704 self.assertEqual(err.exception.offset, offset)
5705 self.assertEqual(err.exception.decode_path, decode_path)
5708 integers(min_value=128),
5709 integers(min_value=0),
5712 def test_bad_len(self, l, offset, decode_path):
5713 with self.assertRaises(DecodeError) as err:
5714 self.base_klass().decode(
5715 self.base_klass.tag_default + len_encode(l)[:-1],
5717 decode_path=decode_path,
5720 self.assertEqual(err.exception.offset, offset)
5721 self.assertEqual(err.exception.decode_path, decode_path)
5723 @given(binary(min_size=1))
5724 def test_tag_mismatch(self, impl):
5725 assume(impl != self.base_klass.tag_default)
5726 with self.assertRaises(TagMismatch):
5727 self.base_klass(impl=impl).decode(self.base_klass().encode())
5729 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5731 seqof_values_strategy(schema=Integer()),
5732 lists(integers().map(Integer)),
5733 integers(min_value=1).map(tag_ctxc),
5734 integers(min_value=0),
5737 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5738 _, _, _, _, _, default, optional, _decoded = values
5740 class SeqOf(self.base_klass):
5750 pprint(obj, big_blobs=True, with_decode_path=True)
5751 self.assertFalse(obj.expled)
5752 obj_encoded = obj.encode()
5753 obj_expled = obj(value, expl=tag_expl)
5754 self.assertTrue(obj_expled.expled)
5756 list(obj_expled.pps())
5757 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5758 obj_expled_encoded = obj_expled.encode()
5759 ctx_copied = deepcopy(ctx_dummy)
5760 obj_decoded, tail = obj_expled.decode(
5761 obj_expled_encoded + tail_junk,
5765 self.assertDictEqual(ctx_copied, ctx_dummy)
5767 list(obj_decoded.pps())
5768 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5769 self.assertEqual(tail, tail_junk)
5770 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5771 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5772 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5773 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5775 obj_decoded.expl_llen,
5776 len(len_encode(len(obj_encoded))),
5778 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5779 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5782 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5784 self.assertEqual(obj_decoded.expl_offset, offset)
5785 for obj_inner in obj_decoded:
5786 self.assertIn(obj_inner, obj_decoded)
5787 self.assertSequenceEqual(
5790 obj_inner.offset - offset:
5791 obj_inner.offset + obj_inner.tlvlen - offset
5795 t, _, lv = tag_strip(obj_encoded)
5796 _, _, v = len_decode(lv)
5797 obj_encoded_lenindef = t + LENINDEF + v + EOC
5798 obj_decoded_lenindef, tail_lenindef = obj.decode(
5799 obj_encoded_lenindef + tail_junk,
5800 ctx={"bered": True},
5802 self.assertTrue(obj_decoded_lenindef.lenindef)
5803 self.assertTrue(obj_decoded_lenindef.bered)
5804 obj_decoded_lenindef = obj_decoded_lenindef.copy()
5805 self.assertTrue(obj_decoded_lenindef.lenindef)
5806 self.assertTrue(obj_decoded_lenindef.bered)
5807 repr(obj_decoded_lenindef)
5808 list(obj_decoded_lenindef.pps())
5809 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5810 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5811 with self.assertRaises(DecodeError):
5812 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5813 with self.assertRaises(DecodeError):
5814 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5816 def test_bered(self):
5817 class SeqOf(self.base_klass):
5819 encoded = Boolean(False).encode()
5820 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5821 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5822 with self.assertRaises(DecodeError):
5823 SeqOf().decode(encoded)
5824 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5825 self.assertFalse(decoded.ber_encoded)
5826 self.assertFalse(decoded.lenindef)
5827 self.assertTrue(decoded.bered)
5828 decoded = decoded.copy()
5829 self.assertFalse(decoded.ber_encoded)
5830 self.assertFalse(decoded.lenindef)
5831 self.assertTrue(decoded.bered)
5833 class SeqOf(self.base_klass):
5834 schema = OctetString()
5835 encoded = OctetString(b"whatever").encode()
5837 tag_encode(form=TagFormConstructed, num=4) +
5839 OctetString(b"whatever").encode() +
5842 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5843 with self.assertRaises(DecodeError):
5844 SeqOf().decode(encoded)
5845 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5846 self.assertFalse(decoded.ber_encoded)
5847 self.assertFalse(decoded.lenindef)
5848 self.assertTrue(decoded.bered)
5849 decoded = decoded.copy()
5850 self.assertFalse(decoded.ber_encoded)
5851 self.assertFalse(decoded.lenindef)
5852 self.assertTrue(decoded.bered)
5855 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5856 class SeqOf(SequenceOf):
5860 def _test_symmetric_compare_objs(self, obj1, obj2):
5861 self.assertEqual(obj1, obj2)
5862 self.assertSequenceEqual(list(obj1), list(obj2))
5865 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5870 def _test_symmetric_compare_objs(self, obj1, obj2):
5871 self.assertSetEqual(
5872 set(int(v) for v in obj1),
5873 set(int(v) for v in obj2),
5876 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5877 @given(data_strategy())
5878 def test_sorted(self, d):
5879 values = [OctetString(v) for v in d.draw(lists(binary()))]
5882 schema = OctetString()
5884 seq_encoded = seq.encode()
5885 seq_decoded, _ = seq.decode(seq_encoded)
5886 self.assertSequenceEqual(
5887 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5888 b"".join(sorted([v.encode() for v in values])),
5891 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5892 @given(data_strategy())
5893 def test_unsorted(self, d):
5894 values = [OctetString(v).encode() for v in d.draw(sets(
5895 binary(min_size=1, max_size=5),
5899 values = d.draw(permutations(values))
5900 assume(values != sorted(values))
5901 encoded = b"".join(values)
5902 seq_encoded = b"".join((
5904 len_encode(len(encoded)),
5909 schema = OctetString()
5911 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5912 seq.decode(seq_encoded)
5914 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5915 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5916 self.assertTrue(seq_decoded.ber_encoded)
5917 self.assertTrue(seq_decoded.bered)
5918 seq_decoded = seq_decoded.copy()
5919 self.assertTrue(seq_decoded.ber_encoded)
5920 self.assertTrue(seq_decoded.bered)
5921 self.assertSequenceEqual(
5922 [obj.encode() for obj in seq_decoded],
5927 class TestGoMarshalVectors(TestCase):
5929 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5930 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5931 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5932 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5933 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5935 class Seq(Sequence):
5937 ("erste", Integer()),
5938 ("zweite", Integer(optional=True))
5941 seq["erste"] = Integer(64)
5942 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5943 seq["erste"] = Integer(0x123456)
5944 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5945 seq["erste"] = Integer(64)
5946 seq["zweite"] = Integer(65)
5947 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5949 class NestedSeq(Sequence):
5953 seq["erste"] = Integer(127)
5954 seq["zweite"] = None
5955 nested = NestedSeq()
5956 nested["nest"] = seq
5957 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5959 self.assertSequenceEqual(
5960 OctetString(b"\x01\x02\x03").encode(),
5961 hexdec("0403010203"),
5964 class Seq(Sequence):
5966 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5969 seq["erste"] = Integer(64)
5970 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5972 class Seq(Sequence):
5974 ("erste", Integer(expl=tag_ctxc(5))),
5977 seq["erste"] = Integer(64)
5978 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5980 class Seq(Sequence):
5983 impl=tag_encode(0, klass=TagClassContext),
5988 seq["erste"] = Null()
5989 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5991 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5993 self.assertSequenceEqual(
5994 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5995 hexdec("170d3730303130313030303030305a"),
5997 self.assertSequenceEqual(
5998 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5999 hexdec("170d3039313131353232353631365a"),
6001 self.assertSequenceEqual(
6002 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6003 hexdec("180f32313030303430353132303130315a"),
6006 class Seq(Sequence):
6008 ("erste", GeneralizedTime()),
6011 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6012 self.assertSequenceEqual(
6014 hexdec("3011180f32303039313131353232353631365a"),
6017 self.assertSequenceEqual(
6018 BitString((1, b"\x80")).encode(),
6021 self.assertSequenceEqual(
6022 BitString((12, b"\x81\xF0")).encode(),
6023 hexdec("03030481f0"),
6026 self.assertSequenceEqual(
6027 ObjectIdentifier("1.2.3.4").encode(),
6028 hexdec("06032a0304"),
6030 self.assertSequenceEqual(
6031 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6032 hexdec("06092a864888932d010105"),
6034 self.assertSequenceEqual(
6035 ObjectIdentifier("2.100.3").encode(),
6036 hexdec("0603813403"),
6039 self.assertSequenceEqual(
6040 PrintableString("test").encode(),
6041 hexdec("130474657374"),
6043 self.assertSequenceEqual(
6044 PrintableString("x" * 127).encode(),
6045 hexdec("137F" + "78" * 127),
6047 self.assertSequenceEqual(
6048 PrintableString("x" * 128).encode(),
6049 hexdec("138180" + "78" * 128),
6051 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6053 class Seq(Sequence):
6055 ("erste", IA5String()),
6058 seq["erste"] = IA5String("test")
6059 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6061 class Seq(Sequence):
6063 ("erste", PrintableString()),
6066 seq["erste"] = PrintableString("test")
6067 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6068 # Asterisk is actually not allowable
6069 PrintableString._allowable_chars |= set(b"*")
6070 seq["erste"] = PrintableString("test*")
6071 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6072 PrintableString._allowable_chars -= set(b"*")
6074 class Seq(Sequence):
6076 ("erste", Any(optional=True)),
6077 ("zweite", Integer()),
6080 seq["zweite"] = Integer(64)
6081 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6086 seq.append(Integer(10))
6087 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6089 class _SeqOf(SequenceOf):
6090 schema = PrintableString()
6092 class SeqOf(SequenceOf):
6095 _seqof.append(PrintableString("1"))
6097 seqof.append(_seqof)
6098 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6100 class Seq(Sequence):
6102 ("erste", Integer(default=1)),
6105 seq["erste"] = Integer(0)
6106 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6107 seq["erste"] = Integer(1)
6108 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6109 seq["erste"] = Integer(2)
6110 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6113 class TestPP(TestCase):
6114 @given(data_strategy())
6115 def test_oid_printing(self, d):
6117 str(ObjectIdentifier(k)): v * 2
6118 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6120 chosen = d.draw(sampled_from(sorted(oids)))
6121 chosen_id = oids[chosen]
6122 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6123 self.assertNotIn(chosen_id, pp_console_row(pp))
6126 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6130 class TestAutoAddSlots(TestCase):
6132 class Inher(Integer):
6135 with self.assertRaises(AttributeError):
6137 inher.unexistent = "whatever"
6140 class TestOIDDefines(TestCase):
6141 @given(data_strategy())
6142 def runTest(self, d):
6143 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6144 value_name_chosen = d.draw(sampled_from(value_names))
6146 ObjectIdentifier(oid)
6147 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6149 oid_chosen = d.draw(sampled_from(oids))
6150 values = d.draw(lists(
6152 min_size=len(value_names),
6153 max_size=len(value_names),
6156 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6157 oid: Integer() for oid in oids[:-1]
6160 for i, value_name in enumerate(value_names):
6161 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6163 class Seq(Sequence):
6166 for value_name, value in zip(value_names, values):
6167 seq[value_name] = Any(Integer(value).encode())
6168 seq["type"] = oid_chosen
6169 seq, _ = Seq().decode(seq.encode())
6170 for value_name in value_names:
6171 if value_name == value_name_chosen:
6173 self.assertIsNone(seq[value_name].defined)
6174 if value_name_chosen in oids[:-1]:
6175 self.assertIsNotNone(seq[value_name_chosen].defined)
6176 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6177 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6180 pprint(seq, big_blobs=True, with_decode_path=True)
6183 class TestDefinesByPath(TestCase):
6184 def test_generated(self):
6185 class Seq(Sequence):
6187 ("type", ObjectIdentifier()),
6188 ("value", OctetString(expl=tag_ctxc(123))),
6191 class SeqInner(Sequence):
6193 ("typeInner", ObjectIdentifier()),
6194 ("valueInner", Any()),
6197 class PairValue(SetOf):
6200 class Pair(Sequence):
6202 ("type", ObjectIdentifier()),
6203 ("value", PairValue()),
6206 class Pairs(SequenceOf):
6213 type_octet_stringed,
6215 ObjectIdentifier(oid)
6216 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6218 seq_integered = Seq()
6219 seq_integered["type"] = type_integered
6220 seq_integered["value"] = OctetString(Integer(123).encode())
6221 seq_integered_raw = seq_integered.encode()
6225 (type_octet_stringed, OctetString(b"whatever")),
6226 (type_integered, Integer(123)),
6227 (type_octet_stringed, OctetString(b"whenever")),
6228 (type_integered, Integer(234)),
6230 for t, v in pairs_input:
6233 pair["value"] = PairValue((Any(v),))
6235 seq_inner = SeqInner()
6236 seq_inner["typeInner"] = type_innered
6237 seq_inner["valueInner"] = Any(pairs)
6238 seq_sequenced = Seq()
6239 seq_sequenced["type"] = type_sequenced
6240 seq_sequenced["value"] = OctetString(seq_inner.encode())
6241 seq_sequenced_raw = seq_sequenced.encode()
6243 list(seq_sequenced.pps())
6244 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6246 defines_by_path = []
6247 ctx_copied = deepcopy(ctx_dummy)
6248 seq_integered, _ = Seq().decode(
6252 self.assertDictEqual(ctx_copied, ctx_dummy)
6253 self.assertIsNone(seq_integered["value"].defined)
6254 defines_by_path.append(
6255 (("type",), ((("value",), {
6256 type_integered: Integer(),
6257 type_sequenced: SeqInner(),
6260 ctx_copied["defines_by_path"] = defines_by_path
6261 seq_integered, _ = Seq().decode(
6265 del ctx_copied["defines_by_path"]
6266 self.assertDictEqual(ctx_copied, ctx_dummy)
6267 self.assertIsNotNone(seq_integered["value"].defined)
6268 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6269 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6270 self.assertTrue(seq_integered_raw[
6271 seq_integered["value"].defined[1].offset:
6272 ].startswith(Integer(123).encode()))
6274 list(seq_integered.pps())
6275 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6277 ctx_copied["defines_by_path"] = defines_by_path
6278 seq_sequenced, _ = Seq().decode(
6282 del ctx_copied["defines_by_path"]
6283 self.assertDictEqual(ctx_copied, ctx_dummy)
6284 self.assertIsNotNone(seq_sequenced["value"].defined)
6285 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6286 seq_inner = seq_sequenced["value"].defined[1]
6287 self.assertIsNone(seq_inner["valueInner"].defined)
6289 list(seq_sequenced.pps())
6290 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6292 defines_by_path.append((
6293 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6294 ((("valueInner",), {type_innered: Pairs()}),),
6296 ctx_copied["defines_by_path"] = defines_by_path
6297 seq_sequenced, _ = Seq().decode(
6301 del ctx_copied["defines_by_path"]
6302 self.assertDictEqual(ctx_copied, ctx_dummy)
6303 self.assertIsNotNone(seq_sequenced["value"].defined)
6304 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6305 seq_inner = seq_sequenced["value"].defined[1]
6306 self.assertIsNotNone(seq_inner["valueInner"].defined)
6307 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6308 pairs = seq_inner["valueInner"].defined[1]
6310 self.assertIsNone(pair["value"][0].defined)
6312 list(seq_sequenced.pps())
6313 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6315 defines_by_path.append((
6318 DecodePathDefBy(type_sequenced),
6320 DecodePathDefBy(type_innered),
6325 type_integered: Integer(),
6326 type_octet_stringed: OctetString(),
6329 ctx_copied["defines_by_path"] = defines_by_path
6330 seq_sequenced, _ = Seq().decode(
6334 del ctx_copied["defines_by_path"]
6335 self.assertDictEqual(ctx_copied, ctx_dummy)
6336 self.assertIsNotNone(seq_sequenced["value"].defined)
6337 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6338 seq_inner = seq_sequenced["value"].defined[1]
6339 self.assertIsNotNone(seq_inner["valueInner"].defined)
6340 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6341 pairs_got = seq_inner["valueInner"].defined[1]
6342 for pair_input, pair_got in zip(pairs_input, pairs_got):
6343 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6344 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6346 list(seq_sequenced.pps())
6347 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6349 @given(oid_strategy(), integers())
6350 def test_simple(self, oid, tgt):
6351 class Inner(Sequence):
6353 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6354 ObjectIdentifier(oid): Integer(),
6358 class Outer(Sequence):
6361 ("tgt", OctetString()),
6365 inner["oid"] = ObjectIdentifier(oid)
6367 outer["inner"] = inner
6368 outer["tgt"] = OctetString(Integer(tgt).encode())
6369 decoded, _ = Outer().decode(outer.encode())
6370 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6373 class TestAbsDecodePath(TestCase):
6375 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6376 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6378 def test_concat(self, decode_path, rel_path):
6379 self.assertSequenceEqual(
6380 abs_decode_path(decode_path, rel_path),
6381 decode_path + rel_path,
6385 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6386 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6388 def test_abs(self, decode_path, rel_path):
6389 self.assertSequenceEqual(
6390 abs_decode_path(decode_path, ("/",) + rel_path),
6395 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6396 integers(min_value=1, max_value=3),
6397 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6399 def test_dots(self, decode_path, number_of_dots, rel_path):
6400 self.assertSequenceEqual(
6401 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6402 decode_path[:-number_of_dots] + rel_path,
6406 class TestStrictDefaultExistence(TestCase):
6407 @given(data_strategy())
6408 def runTest(self, d):
6409 count = d.draw(integers(min_value=1, max_value=10))
6410 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6412 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6413 for i in range(count)
6415 for klass in (Sequence, Set):
6419 for i in range(count):
6420 seq["int%d" % i] = Integer(123)
6422 chosen_choice = "int%d" % chosen
6423 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6424 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6426 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6427 self.assertTrue(decoded.ber_encoded)
6428 self.assertTrue(decoded.bered)
6429 decoded = decoded.copy()
6430 self.assertTrue(decoded.ber_encoded)
6431 self.assertTrue(decoded.bered)
6432 decoded, _ = seq.decode(raw, ctx={"bered": True})
6433 self.assertTrue(decoded.ber_encoded)
6434 self.assertTrue(decoded.bered)
6435 decoded = decoded.copy()
6436 self.assertTrue(decoded.ber_encoded)
6437 self.assertTrue(decoded.bered)
6440 class TestX690PrefixedType(TestCase):
6442 self.assertSequenceEqual(
6443 VisibleString("Jones").encode(),
6444 hexdec("1A054A6F6E6573"),
6446 self.assertSequenceEqual(
6449 impl=tag_encode(3, klass=TagClassApplication),
6451 hexdec("43054A6F6E6573"),
6453 self.assertSequenceEqual(
6457 impl=tag_encode(3, klass=TagClassApplication),
6461 hexdec("A20743054A6F6E6573"),
6463 self.assertSequenceEqual(
6467 impl=tag_encode(3, klass=TagClassApplication),
6469 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6471 hexdec("670743054A6F6E6573"),
6473 self.assertSequenceEqual(
6474 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6475 hexdec("82054A6F6E6573"),
6479 class TestExplOOB(TestCase):
6481 expl = tag_ctxc(123)
6482 raw = Integer(123).encode() + Integer(234).encode()
6483 raw = b"".join((expl, len_encode(len(raw)), raw))
6484 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6485 Integer(expl=expl).decode(raw)
6486 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})