2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2019 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, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from copy import deepcopy
20 from datetime import datetime
21 from string import ascii_letters
22 from string import digits
23 from string import printable
24 from string import whitespace
25 from unittest import TestCase
27 from hypothesis import assume
28 from hypothesis import given
29 from hypothesis import settings
30 from hypothesis.strategies import binary
31 from hypothesis.strategies import booleans
32 from hypothesis.strategies import composite
33 from hypothesis.strategies import data as data_strategy
34 from hypothesis.strategies import datetimes
35 from hypothesis.strategies import dictionaries
36 from hypothesis.strategies import integers
37 from hypothesis.strategies import just
38 from hypothesis.strategies import lists
39 from hypothesis.strategies import none
40 from hypothesis.strategies import one_of
41 from hypothesis.strategies import permutations
42 from hypothesis.strategies import sampled_from
43 from hypothesis.strategies import sets
44 from hypothesis.strategies import text
45 from hypothesis.strategies import tuples
46 from six import assertRaisesRegex
47 from six import binary_type
48 from six import byte2int
49 from six import indexbytes
50 from six import int2byte
51 from six import iterbytes
53 from six import text_type
54 from six import unichr as six_unichr
56 from pyderasn import _pp
57 from pyderasn import abs_decode_path
58 from pyderasn import Any
59 from pyderasn import BitString
60 from pyderasn import BMPString
61 from pyderasn import Boolean
62 from pyderasn import BoundsError
63 from pyderasn import Choice
64 from pyderasn import DecodeError
65 from pyderasn import DecodePathDefBy
66 from pyderasn import Enumerated
67 from pyderasn import EOC
68 from pyderasn import EOC_LEN
69 from pyderasn import GeneralizedTime
70 from pyderasn import GeneralString
71 from pyderasn import GraphicString
72 from pyderasn import hexdec
73 from pyderasn import hexenc
74 from pyderasn import IA5String
75 from pyderasn import Integer
76 from pyderasn import InvalidLength
77 from pyderasn import InvalidOID
78 from pyderasn import InvalidValueType
79 from pyderasn import len_decode
80 from pyderasn import len_encode
81 from pyderasn import LEN_YYMMDDHHMMSSZ
82 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
83 from pyderasn import LEN_YYYYMMDDHHMMSSZ
84 from pyderasn import LENINDEF
85 from pyderasn import LenIndefForm
86 from pyderasn import NotEnoughData
87 from pyderasn import Null
88 from pyderasn import NumericString
89 from pyderasn import ObjectIdentifier
90 from pyderasn import ObjNotReady
91 from pyderasn import ObjUnknown
92 from pyderasn import OctetString
93 from pyderasn import pp_console_row
94 from pyderasn import pprint
95 from pyderasn import PrintableString
96 from pyderasn import Sequence
97 from pyderasn import SequenceOf
98 from pyderasn import Set
99 from pyderasn import SetOf
100 from pyderasn import tag_ctxc
101 from pyderasn import tag_ctxp
102 from pyderasn import tag_decode
103 from pyderasn import tag_encode
104 from pyderasn import tag_strip
105 from pyderasn import TagClassApplication
106 from pyderasn import TagClassContext
107 from pyderasn import TagClassPrivate
108 from pyderasn import TagClassUniversal
109 from pyderasn import TagFormConstructed
110 from pyderasn import TagFormPrimitive
111 from pyderasn import TagMismatch
112 from pyderasn import TeletexString
113 from pyderasn import UniversalString
114 from pyderasn import UTCTime
115 from pyderasn import UTF8String
116 from pyderasn import VideotexString
117 from pyderasn import VisibleString
120 settings.register_profile("local", settings(
123 settings.load_profile("local")
124 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
126 tag_classes = sampled_from((
132 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
133 decode_path_strat = lists(integers(), max_size=3).map(
134 lambda decode_path: tuple(str(dp) for dp in decode_path)
136 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
139 class TestHex(TestCase):
141 def test_symmetric(self, data):
142 self.assertEqual(hexdec(hexenc(data)), data)
145 class TestTagCoder(TestCase):
146 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
150 integers(min_value=0, max_value=30),
153 def test_short(self, klass, form, num, junk):
154 raw = tag_encode(klass=klass, form=form, num=num)
155 self.assertEqual(tag_decode(raw), (klass, form, num))
156 self.assertEqual(len(raw), 1)
158 byte2int(tag_encode(klass=klass, form=form, num=0)),
159 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
161 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
162 self.assertSequenceEqual(stripped.tobytes(), raw)
163 self.assertEqual(tlen, len(raw))
164 self.assertSequenceEqual(tail, junk)
166 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
170 integers(min_value=31),
173 def test_long(self, klass, form, num, junk):
174 raw = tag_encode(klass=klass, form=form, num=num)
175 self.assertEqual(tag_decode(raw), (klass, form, num))
176 self.assertGreater(len(raw), 1)
178 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
181 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
182 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
183 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
184 self.assertSequenceEqual(stripped.tobytes(), raw)
185 self.assertEqual(tlen, len(raw))
186 self.assertSequenceEqual(tail, junk)
188 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
189 @given(integers(min_value=31))
190 def test_unfinished_tag(self, num):
191 raw = bytearray(tag_encode(num=num))
192 for i in range(1, len(raw)):
194 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
195 tag_strip(bytes(raw))
197 def test_go_vectors_valid(self):
198 for data, (eklass, etag, elen, eform) in (
199 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
200 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
201 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
202 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
203 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
204 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
205 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
206 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
207 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
208 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
210 tag, _, len_encoded = tag_strip(memoryview(data))
211 klass, form, num = tag_decode(tag)
212 _len, _, tail = len_decode(len_encoded)
213 self.assertSequenceEqual(tail, b"")
214 self.assertEqual(klass, eklass)
215 self.assertEqual(num, etag)
216 self.assertEqual(_len, elen)
217 self.assertEqual(form, eform)
219 def test_go_vectors_invalid(self):
227 with self.assertRaises(DecodeError):
228 _, _, len_encoded = tag_strip(memoryview(data))
229 len_decode(len_encoded)
232 integers(min_value=0, max_value=127),
233 integers(min_value=0, max_value=2),
235 def test_long_instead_of_short(self, l, dummy_num):
236 octets = (b"\x00" * dummy_num) + int2byte(l)
237 octets = int2byte((dummy_num + 1) | 0x80) + octets
238 with self.assertRaises(DecodeError):
242 class TestLenCoder(TestCase):
243 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
245 integers(min_value=0, max_value=127),
248 def test_short(self, l, junk):
249 raw = len_encode(l) + junk
250 decoded, llen, tail = len_decode(memoryview(raw))
251 self.assertEqual(decoded, l)
252 self.assertEqual(llen, 1)
253 self.assertEqual(len(raw), 1 + len(junk))
254 self.assertEqual(tail.tobytes(), junk)
256 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
258 integers(min_value=128),
261 def test_long(self, l, junk):
262 raw = len_encode(l) + junk
263 decoded, llen, tail = len_decode(memoryview(raw))
264 self.assertEqual(decoded, l)
265 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
266 self.assertEqual(llen, len(raw) - len(junk))
267 self.assertNotEqual(indexbytes(raw, 1), 0)
268 self.assertSequenceEqual(tail.tobytes(), junk)
270 def test_empty(self):
271 with self.assertRaises(NotEnoughData):
274 @given(integers(min_value=128))
275 def test_stripped(self, _len):
276 with self.assertRaises(NotEnoughData):
277 len_decode(len_encode(_len)[:-1])
280 text_printable = text(alphabet=printable, min_size=1)
284 def text_letters(draw):
285 result = draw(text(alphabet=ascii_letters, min_size=1))
287 result = result.encode("ascii")
291 class CommonMixin(object):
292 def test_tag_default(self):
293 obj = self.base_klass()
294 self.assertEqual(obj.tag, obj.tag_default)
296 def test_simultaneous_impl_expl(self):
297 with self.assertRaises(ValueError):
298 self.base_klass(impl=b"whatever", expl=b"whenever")
300 @given(binary(min_size=1), integers(), integers(), integers())
301 def test_decoded(self, impl, offset, llen, vlen):
302 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
303 self.assertEqual(obj.offset, offset)
304 self.assertEqual(obj.llen, llen)
305 self.assertEqual(obj.vlen, vlen)
306 self.assertEqual(obj.tlen, len(impl))
307 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
309 @given(binary(min_size=1))
310 def test_impl_inherited(self, impl_tag):
311 class Inherited(self.base_klass):
314 self.assertSequenceEqual(obj.impl, impl_tag)
315 self.assertFalse(obj.expled)
318 def test_expl_inherited(self, expl_tag):
319 class Inherited(self.base_klass):
322 self.assertSequenceEqual(obj.expl, expl_tag)
323 self.assertTrue(obj.expled)
325 def assert_copied_basic_fields(self, obj, obj_copied):
326 self.assertEqual(obj, obj_copied)
327 self.assertSequenceEqual(obj.tag, obj_copied.tag)
328 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
329 self.assertEqual(obj.default, obj_copied.default)
330 self.assertEqual(obj.optional, obj_copied.optional)
331 self.assertEqual(obj.offset, obj_copied.offset)
332 self.assertEqual(obj.llen, obj_copied.llen)
333 self.assertEqual(obj.vlen, obj_copied.vlen)
337 def boolean_values_strategy(draw, do_expl=False):
338 value = draw(one_of(none(), booleans()))
342 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
344 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
345 default = draw(one_of(none(), booleans()))
346 optional = draw(one_of(none(), booleans()))
348 draw(integers(min_value=0)),
349 draw(integers(min_value=0)),
350 draw(integers(min_value=0)),
352 return (value, impl, expl, default, optional, _decoded)
355 class BooleanInherited(Boolean):
359 class TestBoolean(CommonMixin, TestCase):
362 def test_invalid_value_type(self):
363 with self.assertRaises(InvalidValueType) as err:
368 def test_optional(self, optional):
369 obj = Boolean(default=Boolean(False), optional=optional)
370 self.assertTrue(obj.optional)
373 def test_ready(self, value):
375 self.assertFalse(obj.ready)
378 pprint(obj, big_blobs=True, with_decode_path=True)
379 with self.assertRaises(ObjNotReady) as err:
383 self.assertTrue(obj.ready)
386 pprint(obj, big_blobs=True, with_decode_path=True)
388 @given(booleans(), booleans(), binary(), binary())
389 def test_comparison(self, value1, value2, tag1, tag2):
390 for klass in (Boolean, BooleanInherited):
393 self.assertEqual(obj1 == obj2, value1 == value2)
394 self.assertEqual(obj1 != obj2, value1 != value2)
395 self.assertEqual(obj1 == bool(obj2), value1 == value2)
396 obj1 = klass(value1, impl=tag1)
397 obj2 = klass(value1, impl=tag2)
398 self.assertEqual(obj1 == obj2, tag1 == tag2)
399 self.assertEqual(obj1 != obj2, tag1 != tag2)
401 @given(data_strategy())
402 def test_call(self, d):
403 for klass in (Boolean, BooleanInherited):
411 ) = d.draw(boolean_values_strategy())
417 optional_initial or False,
427 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
428 obj = obj_initial(value, impl, expl, default, optional)
430 value_expected = default if value is None else value
432 default_initial if value_expected is None
435 self.assertEqual(obj, value_expected)
436 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
437 self.assertEqual(obj.expl_tag, expl or expl_initial)
440 default_initial if default is None else default,
442 if obj.default is None:
443 optional = optional_initial if optional is None else optional
444 optional = False if optional is None else optional
447 self.assertEqual(obj.optional, optional)
449 @given(boolean_values_strategy())
450 def test_copy(self, values):
451 for klass in (Boolean, BooleanInherited):
453 obj_copied = obj.copy()
454 self.assert_copied_basic_fields(obj, obj_copied)
458 integers(min_value=1).map(tag_encode),
460 def test_stripped(self, value, tag_impl):
461 obj = Boolean(value, impl=tag_impl)
462 with self.assertRaises(NotEnoughData):
463 obj.decode(obj.encode()[:-1])
467 integers(min_value=1).map(tag_ctxc),
469 def test_stripped_expl(self, value, tag_expl):
470 obj = Boolean(value, expl=tag_expl)
471 with self.assertRaises(NotEnoughData):
472 obj.decode(obj.encode()[:-1])
475 integers(min_value=31),
476 integers(min_value=0),
479 def test_bad_tag(self, tag, offset, decode_path):
480 with self.assertRaises(DecodeError) as err:
482 tag_encode(tag)[:-1],
484 decode_path=decode_path,
487 self.assertEqual(err.exception.offset, offset)
488 self.assertEqual(err.exception.decode_path, decode_path)
491 integers(min_value=31),
492 integers(min_value=0),
495 def test_bad_expl_tag(self, tag, offset, decode_path):
496 with self.assertRaises(DecodeError) as err:
497 Boolean(expl=Boolean.tag_default).decode(
498 tag_encode(tag)[:-1],
500 decode_path=decode_path,
503 self.assertEqual(err.exception.offset, offset)
504 self.assertEqual(err.exception.decode_path, decode_path)
507 integers(min_value=128),
508 integers(min_value=0),
511 def test_bad_len(self, l, offset, decode_path):
512 with self.assertRaises(DecodeError) as err:
514 Boolean.tag_default + len_encode(l)[:-1],
516 decode_path=decode_path,
519 self.assertEqual(err.exception.offset, offset)
520 self.assertEqual(err.exception.decode_path, decode_path)
523 integers(min_value=128),
524 integers(min_value=0),
527 def test_bad_expl_len(self, l, offset, decode_path):
528 with self.assertRaises(DecodeError) as err:
529 Boolean(expl=Boolean.tag_default).decode(
530 Boolean.tag_default + len_encode(l)[:-1],
532 decode_path=decode_path,
535 self.assertEqual(err.exception.offset, offset)
536 self.assertEqual(err.exception.decode_path, decode_path)
538 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
540 boolean_values_strategy(),
542 integers(min_value=1).map(tag_ctxc),
543 integers(min_value=0),
546 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
547 for klass in (Boolean, BooleanInherited):
548 _, _, _, default, optional, _decoded = values
557 pprint(obj, big_blobs=True, with_decode_path=True)
558 self.assertFalse(obj.expled)
559 obj_encoded = obj.encode()
560 obj_expled = obj(value, expl=tag_expl)
561 self.assertTrue(obj_expled.expled)
563 list(obj_expled.pps())
564 pprint(obj_expled, big_blobs=True, with_decode_path=True)
565 obj_expled_encoded = obj_expled.encode()
566 ctx_copied = deepcopy(ctx_dummy)
567 obj_decoded, tail = obj_expled.decode(
568 obj_expled_encoded + tail_junk,
572 self.assertDictEqual(ctx_copied, ctx_dummy)
574 list(obj_decoded.pps())
575 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
576 self.assertEqual(tail, tail_junk)
577 self.assertEqual(obj_decoded, obj_expled)
578 self.assertNotEqual(obj_decoded, obj)
579 self.assertEqual(bool(obj_decoded), bool(obj_expled))
580 self.assertEqual(bool(obj_decoded), bool(obj))
581 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
582 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
583 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
585 obj_decoded.expl_llen,
586 len(len_encode(len(obj_encoded))),
588 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
589 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
592 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
594 self.assertEqual(obj_decoded.expl_offset, offset)
596 @given(integers(min_value=2))
597 def test_invalid_len(self, l):
598 with self.assertRaises(InvalidLength):
599 Boolean().decode(b"".join((
605 @given(integers(min_value=0 + 1, max_value=255 - 1))
606 def test_ber_value(self, value):
607 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
608 Boolean().decode(b"".join((
613 obj, _ = Boolean().decode(
621 self.assertTrue(bool(obj))
622 self.assertTrue(obj.ber_encoded)
623 self.assertFalse(obj.lenindef)
624 self.assertTrue(obj.bered)
627 integers(min_value=1).map(tag_ctxc),
628 binary().filter(lambda x: not x.startswith(EOC)),
630 def test_ber_expl_no_eoc(self, expl, junk):
631 encoded = expl + LENINDEF + Boolean(False).encode()
632 with self.assertRaises(LenIndefForm):
633 Boolean(expl=expl).decode(encoded + junk)
634 with assertRaisesRegex(self, DecodeError, "no EOC"):
635 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
636 obj, tail = Boolean(expl=expl).decode(
637 encoded + EOC + junk,
640 self.assertTrue(obj.expl_lenindef)
641 self.assertFalse(obj.lenindef)
642 self.assertFalse(obj.ber_encoded)
643 self.assertTrue(obj.bered)
644 self.assertSequenceEqual(tail, junk)
647 pprint(obj, big_blobs=True, with_decode_path=True)
650 integers(min_value=1).map(tag_ctxc),
657 def test_ber_expl(self, expl, values):
663 Boolean(value).encode() +
666 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
668 class SeqOf(SequenceOf):
669 schema = Boolean(expl=expl)
670 with self.assertRaises(LenIndefForm):
671 SeqOf().decode(encoded)
672 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
673 self.assertSequenceEqual(tail, b"")
674 self.assertSequenceEqual([bool(v) for v in seqof], values)
690 len(expl) + 1 + 3 + EOC_LEN,
701 pprint(seqof, big_blobs=True, with_decode_path=True)
705 def integer_values_strategy(draw, do_expl=False):
706 bound_min, value, default, bound_max = sorted(draw(sets(
715 _specs = draw(sets(text_letters()))
718 min_size=len(_specs),
719 max_size=len(_specs),
721 _specs = list(zip(_specs, values))
724 bounds = (bound_min, bound_max)
728 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
730 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
733 optional = draw(one_of(none(), booleans()))
735 draw(integers(min_value=0)),
736 draw(integers(min_value=0)),
737 draw(integers(min_value=0)),
739 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
742 class IntegerInherited(Integer):
746 class TestInteger(CommonMixin, TestCase):
749 def test_invalid_value_type(self):
750 with self.assertRaises(InvalidValueType) as err:
754 @given(sets(text_letters(), min_size=2))
755 def test_unknown_name(self, names_input):
756 missing = names_input.pop()
759 schema = [(n, 123) for n in names_input]
760 with self.assertRaises(ObjUnknown) as err:
764 @given(sets(text_letters(), min_size=2))
765 def test_known_name(self, names_input):
767 schema = [(n, 123) for n in names_input]
768 Int(names_input.pop())
771 def test_optional(self, optional):
772 obj = Integer(default=Integer(0), optional=optional)
773 self.assertTrue(obj.optional)
776 def test_ready(self, value):
778 self.assertFalse(obj.ready)
781 pprint(obj, big_blobs=True, with_decode_path=True)
782 with self.assertRaises(ObjNotReady) as err:
786 self.assertTrue(obj.ready)
789 pprint(obj, big_blobs=True, with_decode_path=True)
792 @given(integers(), integers(), binary(), binary())
793 def test_comparison(self, value1, value2, tag1, tag2):
794 for klass in (Integer, IntegerInherited):
797 self.assertEqual(obj1 == obj2, value1 == value2)
798 self.assertEqual(obj1 != obj2, value1 != value2)
799 self.assertEqual(obj1 == int(obj2), value1 == value2)
800 obj1 = klass(value1, impl=tag1)
801 obj2 = klass(value1, impl=tag2)
802 self.assertEqual(obj1 == obj2, tag1 == tag2)
803 self.assertEqual(obj1 != obj2, tag1 != tag2)
805 @given(lists(integers()))
806 def test_sorted_works(self, values):
807 self.assertSequenceEqual(
808 [int(v) for v in sorted(Integer(v) for v in values)],
812 @given(data_strategy())
813 def test_named(self, d):
814 names_input = list(d.draw(sets(text_letters(), min_size=1)))
815 values_input = list(d.draw(sets(
817 min_size=len(names_input),
818 max_size=len(names_input),
820 chosen_name = d.draw(sampled_from(names_input))
821 names_input = dict(zip(names_input, values_input))
825 _int = Int(chosen_name)
826 self.assertEqual(_int.named, chosen_name)
827 self.assertEqual(int(_int), names_input[chosen_name])
829 @given(integers(), integers(min_value=0), integers(min_value=0))
830 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
831 value = bound_min + value_delta
832 bound_max = value + bound_delta
833 Integer(value=value, bounds=(bound_min, bound_max))
835 @given(sets(integers(), min_size=3, max_size=3))
836 def test_bounds_unsatisfied(self, values):
837 values = sorted(values)
838 with self.assertRaises(BoundsError) as err:
839 Integer(value=values[0], bounds=(values[1], values[2]))
841 with assertRaisesRegex(self, DecodeError, "bounds") as err:
842 Integer(bounds=(values[1], values[2])).decode(
843 Integer(values[0]).encode()
846 with self.assertRaises(BoundsError) as err:
847 Integer(value=values[2], bounds=(values[0], values[1]))
849 with assertRaisesRegex(self, DecodeError, "bounds") as err:
850 Integer(bounds=(values[0], values[1])).decode(
851 Integer(values[2]).encode()
855 @given(data_strategy())
856 def test_call(self, d):
857 for klass in (Integer, IntegerInherited):
867 ) = d.draw(integer_values_strategy())
874 optional_initial or False,
887 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
888 if (default is None) and (obj_initial.default is not None):
892 (value is not None) and
893 (bounds_initial is not None) and
894 not (bounds_initial[0] <= value <= bounds_initial[1])
899 (default is not None) and
900 (bounds_initial is not None) and
901 not (bounds_initial[0] <= default <= bounds_initial[1])
904 obj = obj_initial(value, bounds, impl, expl, default, optional)
906 value_expected = default if value is None else value
908 default_initial if value_expected is None
911 self.assertEqual(obj, value_expected)
912 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
913 self.assertEqual(obj.expl_tag, expl or expl_initial)
916 default_initial if default is None else default,
918 if obj.default is None:
919 optional = optional_initial if optional is None else optional
920 optional = False if optional is None else optional
923 self.assertEqual(obj.optional, optional)
925 (obj._bound_min, obj._bound_max),
926 bounds or bounds_initial or (float("-inf"), float("+inf")),
930 {} if _specs_initial is None else dict(_specs_initial),
933 @given(integer_values_strategy())
934 def test_copy(self, values):
935 for klass in (Integer, IntegerInherited):
937 obj_copied = obj.copy()
938 self.assert_copied_basic_fields(obj, obj_copied)
939 self.assertEqual(obj.specs, obj_copied.specs)
940 self.assertEqual(obj._bound_min, obj_copied._bound_min)
941 self.assertEqual(obj._bound_max, obj_copied._bound_max)
942 self.assertEqual(obj._value, obj_copied._value)
946 integers(min_value=1).map(tag_encode),
948 def test_stripped(self, value, tag_impl):
949 obj = Integer(value, impl=tag_impl)
950 with self.assertRaises(NotEnoughData):
951 obj.decode(obj.encode()[:-1])
955 integers(min_value=1).map(tag_ctxc),
957 def test_stripped_expl(self, value, tag_expl):
958 obj = Integer(value, expl=tag_expl)
959 with self.assertRaises(NotEnoughData):
960 obj.decode(obj.encode()[:-1])
962 def test_zero_len(self):
963 with self.assertRaises(NotEnoughData):
964 Integer().decode(b"".join((
970 integers(min_value=31),
971 integers(min_value=0),
974 def test_bad_tag(self, tag, offset, decode_path):
975 with self.assertRaises(DecodeError) as err:
977 tag_encode(tag)[:-1],
979 decode_path=decode_path,
982 self.assertEqual(err.exception.offset, offset)
983 self.assertEqual(err.exception.decode_path, decode_path)
986 integers(min_value=128),
987 integers(min_value=0),
990 def test_bad_len(self, l, offset, decode_path):
991 with self.assertRaises(DecodeError) as err:
993 Integer.tag_default + len_encode(l)[:-1],
995 decode_path=decode_path,
998 self.assertEqual(err.exception.offset, offset)
999 self.assertEqual(err.exception.decode_path, decode_path)
1002 sets(integers(), min_size=2, max_size=2),
1003 integers(min_value=0),
1006 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1007 value, bound_min = list(sorted(ints))
1010 bounds = (bound_min, bound_min)
1011 with self.assertRaises(DecodeError) as err:
1013 Integer(value).encode(),
1015 decode_path=decode_path,
1018 self.assertEqual(err.exception.offset, offset)
1019 self.assertEqual(err.exception.decode_path, decode_path)
1021 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1023 integer_values_strategy(),
1025 integers(min_value=1).map(tag_ctxc),
1026 integers(min_value=0),
1029 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1030 for klass in (Integer, IntegerInherited):
1031 _, _, _, _, default, optional, _, _decoded = values
1040 pprint(obj, big_blobs=True, with_decode_path=True)
1041 self.assertFalse(obj.expled)
1042 obj_encoded = obj.encode()
1043 obj_expled = obj(value, expl=tag_expl)
1044 self.assertTrue(obj_expled.expled)
1046 list(obj_expled.pps())
1047 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1048 obj_expled_encoded = obj_expled.encode()
1049 ctx_copied = deepcopy(ctx_dummy)
1050 obj_decoded, tail = obj_expled.decode(
1051 obj_expled_encoded + tail_junk,
1055 self.assertDictEqual(ctx_copied, ctx_dummy)
1057 list(obj_decoded.pps())
1058 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1059 self.assertEqual(tail, tail_junk)
1060 self.assertEqual(obj_decoded, obj_expled)
1061 self.assertNotEqual(obj_decoded, obj)
1062 self.assertEqual(int(obj_decoded), int(obj_expled))
1063 self.assertEqual(int(obj_decoded), int(obj))
1064 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1065 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1066 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1068 obj_decoded.expl_llen,
1069 len(len_encode(len(obj_encoded))),
1071 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1072 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1075 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1077 self.assertEqual(obj_decoded.expl_offset, offset)
1079 def test_go_vectors_valid(self):
1080 for data, expect in ((
1084 (b"\xff\x7f", -129),
1088 (b"\xff\x00", -256),
1092 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1093 (b"\x80\x00\x00\x00", -2147483648),
1096 Integer().decode(b"".join((
1097 Integer.tag_default,
1098 len_encode(len(data)),
1104 def test_go_vectors_invalid(self):
1109 with self.assertRaises(DecodeError):
1110 Integer().decode(b"".join((
1111 Integer.tag_default,
1112 len_encode(len(data)),
1118 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1121 if draw(booleans()):
1122 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1124 integers(min_value=0, max_value=255),
1125 min_size=len(schema),
1126 max_size=len(schema),
1128 schema = list(zip(schema, bits))
1130 def _value(value_required):
1131 if not value_required and draw(booleans()):
1133 generation_choice = 0
1135 generation_choice = draw(sampled_from((1, 2, 3)))
1136 if generation_choice == 1 or draw(booleans()):
1137 return "'%s'B" % "".join(draw(lists(
1138 sampled_from(("0", "1")),
1139 max_size=len(schema),
1141 elif generation_choice == 2 or draw(booleans()):
1142 return draw(binary(max_size=len(schema) // 8))
1143 elif generation_choice == 3 or draw(booleans()):
1144 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1146 value = _value(value_required)
1147 default = _value(value_required=False)
1151 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1153 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1154 optional = draw(one_of(none(), booleans()))
1156 draw(integers(min_value=0)),
1157 draw(integers(min_value=0)),
1158 draw(integers(min_value=0)),
1160 return (schema, value, impl, expl, default, optional, _decoded)
1163 class BitStringInherited(BitString):
1167 class TestBitString(CommonMixin, TestCase):
1168 base_klass = BitString
1170 @given(lists(booleans()))
1171 def test_b_encoding(self, bits):
1172 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1173 self.assertEqual(obj.bit_len, len(bits))
1174 self.assertSequenceEqual(list(obj), bits)
1175 for i, bit in enumerate(bits):
1176 self.assertEqual(obj[i], bit)
1178 @given(lists(booleans()))
1179 def test_out_of_bounds_bits(self, bits):
1180 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1181 for i in range(len(bits), len(bits) * 2):
1182 self.assertFalse(obj[i])
1184 def test_bad_b_encoding(self):
1185 with self.assertRaises(ValueError):
1186 BitString("'010120101'B")
1189 integers(min_value=1, max_value=255),
1190 integers(min_value=1, max_value=255),
1192 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1193 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1194 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1195 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1197 class BS(BitString):
1198 schema = (("whatever", 0),)
1199 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1200 self.assertEqual(obj.bit_len, leading_zeros + 1)
1201 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1203 def test_zero_len(self):
1204 with self.assertRaises(NotEnoughData):
1205 BitString().decode(b"".join((
1206 BitString.tag_default,
1210 def test_invalid_value_type(self):
1211 with self.assertRaises(InvalidValueType) as err:
1214 with self.assertRaises(InvalidValueType) as err:
1218 def test_obj_unknown(self):
1219 with self.assertRaises(ObjUnknown) as err:
1220 BitString(b"whatever")["whenever"]
1223 def test_get_invalid_type(self):
1224 with self.assertRaises(InvalidValueType) as err:
1225 BitString(b"whatever")[(1, 2, 3)]
1228 @given(data_strategy())
1229 def test_unknown_name(self, d):
1230 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1231 missing = _schema.pop()
1233 class BS(BitString):
1234 schema = [(n, i) for i, n in enumerate(_schema)]
1235 with self.assertRaises(ObjUnknown) as err:
1240 def test_optional(self, optional):
1241 obj = BitString(default=BitString(b""), optional=optional)
1242 self.assertTrue(obj.optional)
1245 def test_ready(self, value):
1247 self.assertFalse(obj.ready)
1250 pprint(obj, big_blobs=True, with_decode_path=True)
1251 with self.assertRaises(ObjNotReady) as err:
1254 obj = BitString(value)
1255 self.assertTrue(obj.ready)
1258 pprint(obj, big_blobs=True, with_decode_path=True)
1261 tuples(integers(min_value=0), binary()),
1262 tuples(integers(min_value=0), binary()),
1266 def test_comparison(self, value1, value2, tag1, tag2):
1267 for klass in (BitString, BitStringInherited):
1268 obj1 = klass(value1)
1269 obj2 = klass(value2)
1270 self.assertEqual(obj1 == obj2, value1 == value2)
1271 self.assertEqual(obj1 != obj2, value1 != value2)
1272 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1273 obj1 = klass(value1, impl=tag1)
1274 obj2 = klass(value1, impl=tag2)
1275 self.assertEqual(obj1 == obj2, tag1 == tag2)
1276 self.assertEqual(obj1 != obj2, tag1 != tag2)
1278 @given(data_strategy())
1279 def test_call(self, d):
1280 for klass in (BitString, BitStringInherited):
1289 ) = d.draw(bit_string_values_strategy())
1292 schema = schema_initial
1294 value=value_initial,
1297 default=default_initial,
1298 optional=optional_initial or False,
1299 _decoded=_decoded_initial,
1309 ) = d.draw(bit_string_values_strategy(
1310 schema=schema_initial,
1311 do_expl=impl_initial is None,
1320 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1321 self.assertEqual(obj.expl_tag, expl or expl_initial)
1322 if obj.default is None:
1323 optional = optional_initial if optional is None else optional
1324 optional = False if optional is None else optional
1327 self.assertEqual(obj.optional, optional)
1328 self.assertEqual(obj.specs, obj_initial.specs)
1330 @given(bit_string_values_strategy())
1331 def test_copy(self, values):
1332 for klass in (BitString, BitStringInherited):
1333 _schema, value, impl, expl, default, optional, _decoded = values
1342 optional=optional or False,
1345 obj_copied = obj.copy()
1346 self.assert_copied_basic_fields(obj, obj_copied)
1347 self.assertEqual(obj.specs, obj_copied.specs)
1348 self.assertEqual(obj._value, obj_copied._value)
1352 integers(min_value=1).map(tag_encode),
1354 def test_stripped(self, value, tag_impl):
1355 obj = BitString(value, impl=tag_impl)
1356 with self.assertRaises(NotEnoughData):
1357 obj.decode(obj.encode()[:-1])
1361 integers(min_value=1).map(tag_ctxc),
1363 def test_stripped_expl(self, value, tag_expl):
1364 obj = BitString(value, expl=tag_expl)
1365 with self.assertRaises(NotEnoughData):
1366 obj.decode(obj.encode()[:-1])
1369 integers(min_value=31),
1370 integers(min_value=0),
1373 def test_bad_tag(self, tag, offset, decode_path):
1374 with self.assertRaises(DecodeError) as err:
1376 tag_encode(tag)[:-1],
1378 decode_path=decode_path,
1381 self.assertEqual(err.exception.offset, offset)
1382 self.assertEqual(err.exception.decode_path, decode_path)
1385 integers(min_value=128),
1386 integers(min_value=0),
1389 def test_bad_len(self, l, offset, decode_path):
1390 with self.assertRaises(DecodeError) as err:
1392 BitString.tag_default + len_encode(l)[:-1],
1394 decode_path=decode_path,
1397 self.assertEqual(err.exception.offset, offset)
1398 self.assertEqual(err.exception.decode_path, decode_path)
1400 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1401 @given(data_strategy())
1402 def test_symmetric(self, d):
1411 ) = d.draw(bit_string_values_strategy(value_required=True))
1412 tail_junk = d.draw(binary(max_size=5))
1413 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1414 offset = d.draw(integers(min_value=0))
1415 for klass in (BitString, BitStringInherited):
1426 pprint(obj, big_blobs=True, with_decode_path=True)
1427 self.assertFalse(obj.expled)
1428 obj_encoded = obj.encode()
1429 obj_expled = obj(value, expl=tag_expl)
1430 self.assertTrue(obj_expled.expled)
1432 list(obj_expled.pps())
1433 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1434 obj_expled_encoded = obj_expled.encode()
1435 ctx_copied = deepcopy(ctx_dummy)
1436 obj_decoded, tail = obj_expled.decode(
1437 obj_expled_encoded + tail_junk,
1441 self.assertDictEqual(ctx_copied, ctx_dummy)
1443 list(obj_decoded.pps())
1444 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1445 self.assertEqual(tail, tail_junk)
1446 self.assertEqual(obj_decoded, obj_expled)
1447 self.assertNotEqual(obj_decoded, obj)
1448 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1449 self.assertEqual(bytes(obj_decoded), bytes(obj))
1450 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1451 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1452 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1454 obj_decoded.expl_llen,
1455 len(len_encode(len(obj_encoded))),
1457 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1458 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1461 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1463 self.assertEqual(obj_decoded.expl_offset, offset)
1464 if isinstance(value, tuple):
1465 self.assertSetEqual(set(value), set(obj_decoded.named))
1469 @given(integers(min_value=1, max_value=255))
1470 def test_bad_zero_value(self, pad_size):
1471 with self.assertRaises(DecodeError):
1472 BitString().decode(b"".join((
1473 BitString.tag_default,
1478 def test_go_vectors_invalid(self):
1484 with self.assertRaises(DecodeError):
1485 BitString().decode(b"".join((
1486 BitString.tag_default,
1491 def test_go_vectors_valid(self):
1492 obj, _ = BitString().decode(b"".join((
1493 BitString.tag_default,
1497 self.assertEqual(bytes(obj), b"")
1498 self.assertEqual(obj.bit_len, 0)
1500 obj, _ = BitString().decode(b"".join((
1501 BitString.tag_default,
1505 self.assertEqual(bytes(obj), b"\x00")
1506 self.assertEqual(obj.bit_len, 1)
1508 obj = BitString((16, b"\x82\x40"))
1509 self.assertTrue(obj[0])
1510 self.assertFalse(obj[1])
1511 self.assertTrue(obj[6])
1512 self.assertTrue(obj[9])
1513 self.assertFalse(obj[17])
1516 integers(min_value=1, max_value=30),
1519 binary(min_size=1, max_size=5),
1521 binary(min_size=1, max_size=5),
1529 lists(booleans(), min_size=1),
1532 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1533 def chunk_constructed(contents):
1535 tag_encode(form=TagFormConstructed, num=3) +
1537 b"".join(BitString(content).encode() for content in contents) +
1541 payload_expected = b""
1542 bit_len_expected = 0
1543 for chunk_input in chunk_inputs:
1544 if isinstance(chunk_input, binary_type):
1545 chunks.append(BitString(chunk_input).encode())
1546 payload_expected += chunk_input
1547 bit_len_expected += len(chunk_input) * 8
1549 chunks.append(chunk_constructed(chunk_input))
1550 payload = b"".join(chunk_input)
1551 payload_expected += payload
1552 bit_len_expected += len(payload) * 8
1553 chunk_last = BitString("'%s'B" % "".join(
1554 "1" if bit else "0" for bit in chunk_last_bits
1556 payload_expected += bytes(chunk_last)
1557 bit_len_expected += chunk_last.bit_len
1558 encoded_indefinite = (
1559 tag_encode(form=TagFormConstructed, num=impl) +
1562 chunk_last.encode() +
1565 encoded_definite = (
1566 tag_encode(form=TagFormConstructed, num=impl) +
1567 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1571 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1572 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1573 for lenindef_expected, encoded in (
1574 (True, encoded_indefinite),
1575 (False, encoded_definite),
1577 obj, tail = BitString(impl=tag_encode(impl)).decode(
1579 ctx={"bered": True},
1581 self.assertSequenceEqual(tail, junk)
1582 self.assertEqual(obj.bit_len, bit_len_expected)
1583 self.assertSequenceEqual(bytes(obj), payload_expected)
1584 self.assertTrue(obj.ber_encoded)
1585 self.assertEqual(obj.lenindef, lenindef_expected)
1586 self.assertTrue(obj.bered)
1587 self.assertEqual(len(encoded), obj.tlvlen)
1590 integers(min_value=0),
1593 def test_ber_definite_too_short(self, offset, decode_path):
1594 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1596 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1598 decode_path=decode_path,
1599 ctx={"bered": True},
1601 self.assertEqual(err.exception.decode_path, decode_path)
1602 self.assertEqual(err.exception.offset, offset)
1605 integers(min_value=0),
1608 def test_ber_definite_no_data(self, offset, decode_path):
1609 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1611 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1613 decode_path=decode_path,
1614 ctx={"bered": True},
1616 self.assertEqual(err.exception.decode_path, decode_path)
1617 self.assertEqual(err.exception.offset, offset)
1620 integers(min_value=0),
1622 integers(min_value=1, max_value=3),
1624 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1625 bs = BitString(b"data").encode()
1626 with self.assertRaises(NotEnoughData) as err:
1628 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1630 decode_path=decode_path,
1631 ctx={"bered": True},
1633 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1634 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1637 integers(min_value=0),
1639 integers(min_value=1, max_value=3),
1641 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1642 bs = BitString(b"data").encode()
1643 bs_longer = BitString(b"data-longer").encode()
1644 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1647 tag_encode(3, form=TagFormConstructed) +
1648 len_encode((chunks + 1) * len(bs)) +
1653 decode_path=decode_path,
1654 ctx={"bered": True},
1656 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1657 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1660 integers(min_value=0),
1663 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1664 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1666 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1668 decode_path=decode_path,
1669 ctx={"bered": True},
1671 self.assertEqual(err.exception.decode_path, decode_path)
1672 self.assertEqual(err.exception.offset, offset)
1674 @given(data_strategy())
1675 def test_ber_indefinite_not_multiple(self, d):
1676 bs_short = BitString("'A'H").encode()
1677 bs_full = BitString("'AA'H").encode()
1678 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1679 chunks.append(bs_short)
1680 d.draw(permutations(chunks))
1681 chunks.append(bs_short)
1682 offset = d.draw(integers(min_value=0))
1683 decode_path = d.draw(decode_path_strat)
1684 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1687 tag_encode(3, form=TagFormConstructed) +
1693 decode_path=decode_path,
1694 ctx={"bered": True},
1697 err.exception.decode_path,
1698 decode_path + (str(chunks.index(bs_short)),),
1701 err.exception.offset,
1702 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1705 def test_x690_vector(self):
1706 vector = BitString("'0A3B5F291CD'H")
1707 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1708 self.assertSequenceEqual(tail, b"")
1709 self.assertEqual(obj, vector)
1710 obj, tail = BitString().decode(
1711 hexdec("23800303000A3B0305045F291CD00000"),
1712 ctx={"bered": True},
1714 self.assertSequenceEqual(tail, b"")
1715 self.assertEqual(obj, vector)
1716 self.assertTrue(obj.ber_encoded)
1717 self.assertTrue(obj.lenindef)
1718 self.assertTrue(obj.bered)
1722 def octet_string_values_strategy(draw, do_expl=False):
1723 bound_min, bound_max = sorted(draw(sets(
1724 integers(min_value=0, max_value=1 << 7),
1728 value = draw(one_of(
1730 binary(min_size=bound_min, max_size=bound_max),
1732 default = draw(one_of(
1734 binary(min_size=bound_min, max_size=bound_max),
1737 if draw(booleans()):
1738 bounds = (bound_min, bound_max)
1742 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1744 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1745 optional = draw(one_of(none(), booleans()))
1747 draw(integers(min_value=0)),
1748 draw(integers(min_value=0)),
1749 draw(integers(min_value=0)),
1751 return (value, bounds, impl, expl, default, optional, _decoded)
1754 class OctetStringInherited(OctetString):
1758 class TestOctetString(CommonMixin, TestCase):
1759 base_klass = OctetString
1761 def test_invalid_value_type(self):
1762 with self.assertRaises(InvalidValueType) as err:
1763 OctetString(text_type(123))
1767 def test_optional(self, optional):
1768 obj = OctetString(default=OctetString(b""), optional=optional)
1769 self.assertTrue(obj.optional)
1772 def test_ready(self, value):
1774 self.assertFalse(obj.ready)
1777 pprint(obj, big_blobs=True, with_decode_path=True)
1778 with self.assertRaises(ObjNotReady) as err:
1781 obj = OctetString(value)
1782 self.assertTrue(obj.ready)
1785 pprint(obj, big_blobs=True, with_decode_path=True)
1787 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1788 def test_comparison(self, value1, value2, tag1, tag2):
1789 for klass in (OctetString, OctetStringInherited):
1790 obj1 = klass(value1)
1791 obj2 = klass(value2)
1792 self.assertEqual(obj1 == obj2, value1 == value2)
1793 self.assertEqual(obj1 != obj2, value1 != value2)
1794 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1795 obj1 = klass(value1, impl=tag1)
1796 obj2 = klass(value1, impl=tag2)
1797 self.assertEqual(obj1 == obj2, tag1 == tag2)
1798 self.assertEqual(obj1 != obj2, tag1 != tag2)
1800 @given(lists(binary()))
1801 def test_sorted_works(self, values):
1802 self.assertSequenceEqual(
1803 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1807 @given(data_strategy())
1808 def test_bounds_satisfied(self, d):
1809 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1810 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1811 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1812 OctetString(value=value, bounds=(bound_min, bound_max))
1814 @given(data_strategy())
1815 def test_bounds_unsatisfied(self, d):
1816 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1817 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1818 value = d.draw(binary(max_size=bound_min - 1))
1819 with self.assertRaises(BoundsError) as err:
1820 OctetString(value=value, bounds=(bound_min, bound_max))
1822 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1823 OctetString(bounds=(bound_min, bound_max)).decode(
1824 OctetString(value).encode()
1827 value = d.draw(binary(min_size=bound_max + 1))
1828 with self.assertRaises(BoundsError) as err:
1829 OctetString(value=value, bounds=(bound_min, bound_max))
1831 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1832 OctetString(bounds=(bound_min, bound_max)).decode(
1833 OctetString(value).encode()
1837 @given(data_strategy())
1838 def test_call(self, d):
1839 for klass in (OctetString, OctetStringInherited):
1848 ) = d.draw(octet_string_values_strategy())
1849 obj_initial = klass(
1855 optional_initial or False,
1866 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1867 if (default is None) and (obj_initial.default is not None):
1870 (bounds is None) and
1871 (value is not None) and
1872 (bounds_initial is not None) and
1873 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1877 (bounds is None) and
1878 (default is not None) and
1879 (bounds_initial is not None) and
1880 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1883 obj = obj_initial(value, bounds, impl, expl, default, optional)
1885 value_expected = default if value is None else value
1887 default_initial if value_expected is None
1890 self.assertEqual(obj, value_expected)
1891 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1892 self.assertEqual(obj.expl_tag, expl or expl_initial)
1895 default_initial if default is None else default,
1897 if obj.default is None:
1898 optional = optional_initial if optional is None else optional
1899 optional = False if optional is None else optional
1902 self.assertEqual(obj.optional, optional)
1904 (obj._bound_min, obj._bound_max),
1905 bounds or bounds_initial or (0, float("+inf")),
1908 @given(octet_string_values_strategy())
1909 def test_copy(self, values):
1910 for klass in (OctetString, OctetStringInherited):
1911 obj = klass(*values)
1912 obj_copied = obj.copy()
1913 self.assert_copied_basic_fields(obj, obj_copied)
1914 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1915 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1916 self.assertEqual(obj._value, obj_copied._value)
1920 integers(min_value=1).map(tag_encode),
1922 def test_stripped(self, value, tag_impl):
1923 obj = OctetString(value, impl=tag_impl)
1924 with self.assertRaises(NotEnoughData):
1925 obj.decode(obj.encode()[:-1])
1929 integers(min_value=1).map(tag_ctxc),
1931 def test_stripped_expl(self, value, tag_expl):
1932 obj = OctetString(value, expl=tag_expl)
1933 with self.assertRaises(NotEnoughData):
1934 obj.decode(obj.encode()[:-1])
1937 integers(min_value=31),
1938 integers(min_value=0),
1941 def test_bad_tag(self, tag, offset, decode_path):
1942 with self.assertRaises(DecodeError) as err:
1943 OctetString().decode(
1944 tag_encode(tag)[:-1],
1946 decode_path=decode_path,
1949 self.assertEqual(err.exception.offset, offset)
1950 self.assertEqual(err.exception.decode_path, decode_path)
1953 integers(min_value=128),
1954 integers(min_value=0),
1957 def test_bad_len(self, l, offset, decode_path):
1958 with self.assertRaises(DecodeError) as err:
1959 OctetString().decode(
1960 OctetString.tag_default + len_encode(l)[:-1],
1962 decode_path=decode_path,
1965 self.assertEqual(err.exception.offset, offset)
1966 self.assertEqual(err.exception.decode_path, decode_path)
1969 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1970 integers(min_value=0),
1973 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1974 value, bound_min = list(sorted(ints))
1976 class String(OctetString):
1977 bounds = (bound_min, bound_min)
1978 with self.assertRaises(DecodeError) as err:
1980 OctetString(b"\x00" * value).encode(),
1982 decode_path=decode_path,
1985 self.assertEqual(err.exception.offset, offset)
1986 self.assertEqual(err.exception.decode_path, decode_path)
1988 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1990 octet_string_values_strategy(),
1992 integers(min_value=1).map(tag_ctxc),
1993 integers(min_value=0),
1996 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1997 for klass in (OctetString, OctetStringInherited):
1998 _, _, _, _, default, optional, _decoded = values
2007 pprint(obj, big_blobs=True, with_decode_path=True)
2008 self.assertFalse(obj.expled)
2009 obj_encoded = obj.encode()
2010 obj_expled = obj(value, expl=tag_expl)
2011 self.assertTrue(obj_expled.expled)
2013 list(obj_expled.pps())
2014 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2015 obj_expled_encoded = obj_expled.encode()
2016 ctx_copied = deepcopy(ctx_dummy)
2017 obj_decoded, tail = obj_expled.decode(
2018 obj_expled_encoded + tail_junk,
2022 self.assertDictEqual(ctx_copied, ctx_dummy)
2024 list(obj_decoded.pps())
2025 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2026 self.assertEqual(tail, tail_junk)
2027 self.assertEqual(obj_decoded, obj_expled)
2028 self.assertNotEqual(obj_decoded, obj)
2029 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2030 self.assertEqual(bytes(obj_decoded), bytes(obj))
2031 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2032 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2033 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2035 obj_decoded.expl_llen,
2036 len(len_encode(len(obj_encoded))),
2038 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2039 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2042 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2044 self.assertEqual(obj_decoded.expl_offset, offset)
2047 integers(min_value=1, max_value=30),
2050 binary(min_size=1, max_size=5),
2052 binary(min_size=1, max_size=5),
2062 def test_constructed(self, impl, chunk_inputs, junk):
2063 def chunk_constructed(contents):
2065 tag_encode(form=TagFormConstructed, num=4) +
2067 b"".join(OctetString(content).encode() for content in contents) +
2071 payload_expected = b""
2072 for chunk_input in chunk_inputs:
2073 if isinstance(chunk_input, binary_type):
2074 chunks.append(OctetString(chunk_input).encode())
2075 payload_expected += chunk_input
2077 chunks.append(chunk_constructed(chunk_input))
2078 payload = b"".join(chunk_input)
2079 payload_expected += payload
2080 encoded_indefinite = (
2081 tag_encode(form=TagFormConstructed, num=impl) +
2086 encoded_definite = (
2087 tag_encode(form=TagFormConstructed, num=impl) +
2088 len_encode(len(b"".join(chunks))) +
2091 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2092 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2093 for lenindef_expected, encoded in (
2094 (True, encoded_indefinite),
2095 (False, encoded_definite),
2097 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2099 ctx={"bered": True},
2101 self.assertSequenceEqual(tail, junk)
2102 self.assertSequenceEqual(bytes(obj), payload_expected)
2103 self.assertTrue(obj.ber_encoded)
2104 self.assertEqual(obj.lenindef, lenindef_expected)
2105 self.assertTrue(obj.bered)
2106 self.assertEqual(len(encoded), obj.tlvlen)
2109 integers(min_value=0),
2112 def test_ber_definite_too_short(self, offset, decode_path):
2113 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2114 OctetString().decode(
2115 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2117 decode_path=decode_path,
2118 ctx={"bered": True},
2120 self.assertEqual(err.exception.decode_path, decode_path)
2121 self.assertEqual(err.exception.offset, offset)
2124 integers(min_value=0),
2126 integers(min_value=1, max_value=3),
2128 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2129 bs = OctetString(b"data").encode()
2130 with self.assertRaises(NotEnoughData) as err:
2131 OctetString().decode(
2132 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2134 decode_path=decode_path,
2135 ctx={"bered": True},
2137 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2138 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2141 integers(min_value=0),
2143 integers(min_value=1, max_value=3),
2145 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2146 bs = OctetString(b"data").encode()
2147 bs_longer = OctetString(b"data-longer").encode()
2148 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2149 OctetString().decode(
2151 tag_encode(4, form=TagFormConstructed) +
2152 len_encode((chunks + 1) * len(bs)) +
2157 decode_path=decode_path,
2158 ctx={"bered": True},
2160 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2161 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2165 def null_values_strategy(draw, do_expl=False):
2169 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2171 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2172 optional = draw(one_of(none(), booleans()))
2174 draw(integers(min_value=0)),
2175 draw(integers(min_value=0)),
2176 draw(integers(min_value=0)),
2178 return (impl, expl, optional, _decoded)
2181 class NullInherited(Null):
2185 class TestNull(CommonMixin, TestCase):
2188 def test_ready(self):
2190 self.assertTrue(obj.ready)
2193 pprint(obj, big_blobs=True, with_decode_path=True)
2195 @given(binary(), binary())
2196 def test_comparison(self, tag1, tag2):
2197 for klass in (Null, NullInherited):
2198 obj1 = klass(impl=tag1)
2199 obj2 = klass(impl=tag2)
2200 self.assertEqual(obj1 == obj2, tag1 == tag2)
2201 self.assertEqual(obj1 != obj2, tag1 != tag2)
2202 self.assertNotEqual(obj1, tag2)
2204 @given(data_strategy())
2205 def test_call(self, d):
2206 for klass in (Null, NullInherited):
2212 ) = d.draw(null_values_strategy())
2213 obj_initial = klass(
2216 optional=optional_initial or False,
2217 _decoded=_decoded_initial,
2224 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2225 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2226 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2227 self.assertEqual(obj.expl_tag, expl or expl_initial)
2228 optional = optional_initial if optional is None else optional
2229 optional = False if optional is None else optional
2230 self.assertEqual(obj.optional, optional)
2232 @given(null_values_strategy())
2233 def test_copy(self, values):
2234 for klass in (Null, NullInherited):
2235 impl, expl, optional, _decoded = values
2239 optional=optional or False,
2242 obj_copied = obj.copy()
2243 self.assert_copied_basic_fields(obj, obj_copied)
2245 @given(integers(min_value=1).map(tag_encode))
2246 def test_stripped(self, tag_impl):
2247 obj = Null(impl=tag_impl)
2248 with self.assertRaises(NotEnoughData):
2249 obj.decode(obj.encode()[:-1])
2251 @given(integers(min_value=1).map(tag_ctxc))
2252 def test_stripped_expl(self, tag_expl):
2253 obj = Null(expl=tag_expl)
2254 with self.assertRaises(NotEnoughData):
2255 obj.decode(obj.encode()[:-1])
2258 integers(min_value=31),
2259 integers(min_value=0),
2262 def test_bad_tag(self, tag, offset, decode_path):
2263 with self.assertRaises(DecodeError) as err:
2265 tag_encode(tag)[:-1],
2267 decode_path=decode_path,
2270 self.assertEqual(err.exception.offset, offset)
2271 self.assertEqual(err.exception.decode_path, decode_path)
2274 integers(min_value=128),
2275 integers(min_value=0),
2278 def test_bad_len(self, l, offset, decode_path):
2279 with self.assertRaises(DecodeError) as err:
2281 Null.tag_default + len_encode(l)[:-1],
2283 decode_path=decode_path,
2286 self.assertEqual(err.exception.offset, offset)
2287 self.assertEqual(err.exception.decode_path, decode_path)
2289 @given(binary(min_size=1))
2290 def test_tag_mismatch(self, impl):
2291 assume(impl != Null.tag_default)
2292 with self.assertRaises(TagMismatch):
2293 Null(impl=impl).decode(Null().encode())
2296 null_values_strategy(),
2297 integers(min_value=1).map(tag_ctxc),
2298 integers(min_value=0),
2301 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2302 for klass in (Null, NullInherited):
2303 _, _, optional, _decoded = values
2304 obj = klass(optional=optional, _decoded=_decoded)
2307 pprint(obj, big_blobs=True, with_decode_path=True)
2308 self.assertFalse(obj.expled)
2309 obj_encoded = obj.encode()
2310 obj_expled = obj(expl=tag_expl)
2311 self.assertTrue(obj_expled.expled)
2313 list(obj_expled.pps())
2314 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2315 obj_expled_encoded = obj_expled.encode()
2316 ctx_copied = deepcopy(ctx_dummy)
2317 obj_decoded, tail = obj_expled.decode(
2318 obj_expled_encoded + tail_junk,
2322 self.assertDictEqual(ctx_copied, ctx_dummy)
2324 list(obj_decoded.pps())
2325 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2326 self.assertEqual(tail, tail_junk)
2327 self.assertEqual(obj_decoded, obj_expled)
2328 self.assertNotEqual(obj_decoded, obj)
2329 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2330 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2331 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2333 obj_decoded.expl_llen,
2334 len(len_encode(len(obj_encoded))),
2336 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2337 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2340 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2342 self.assertEqual(obj_decoded.expl_offset, offset)
2344 @given(integers(min_value=1))
2345 def test_invalid_len(self, l):
2346 with self.assertRaises(InvalidLength):
2347 Null().decode(b"".join((
2354 def oid_strategy(draw):
2355 first_arc = draw(integers(min_value=0, max_value=2))
2357 if first_arc in (0, 1):
2358 second_arc = draw(integers(min_value=0, max_value=39))
2360 second_arc = draw(integers(min_value=0))
2361 other_arcs = draw(lists(integers(min_value=0)))
2362 return tuple([first_arc, second_arc] + other_arcs)
2366 def oid_values_strategy(draw, do_expl=False):
2367 value = draw(one_of(none(), oid_strategy()))
2371 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2373 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2374 default = draw(one_of(none(), oid_strategy()))
2375 optional = draw(one_of(none(), booleans()))
2377 draw(integers(min_value=0)),
2378 draw(integers(min_value=0)),
2379 draw(integers(min_value=0)),
2381 return (value, impl, expl, default, optional, _decoded)
2384 class ObjectIdentifierInherited(ObjectIdentifier):
2388 class TestObjectIdentifier(CommonMixin, TestCase):
2389 base_klass = ObjectIdentifier
2391 def test_invalid_value_type(self):
2392 with self.assertRaises(InvalidValueType) as err:
2393 ObjectIdentifier(123)
2397 def test_optional(self, optional):
2398 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2399 self.assertTrue(obj.optional)
2401 @given(oid_strategy())
2402 def test_ready(self, value):
2403 obj = ObjectIdentifier()
2404 self.assertFalse(obj.ready)
2407 pprint(obj, big_blobs=True, with_decode_path=True)
2408 with self.assertRaises(ObjNotReady) as err:
2411 obj = ObjectIdentifier(value)
2412 self.assertTrue(obj.ready)
2415 pprint(obj, big_blobs=True, with_decode_path=True)
2418 @given(oid_strategy(), oid_strategy(), binary(), binary())
2419 def test_comparison(self, value1, value2, tag1, tag2):
2420 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2421 obj1 = klass(value1)
2422 obj2 = klass(value2)
2423 self.assertEqual(obj1 == obj2, value1 == value2)
2424 self.assertEqual(obj1 != obj2, value1 != value2)
2425 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2426 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2427 obj1 = klass(value1, impl=tag1)
2428 obj2 = klass(value1, impl=tag2)
2429 self.assertEqual(obj1 == obj2, tag1 == tag2)
2430 self.assertEqual(obj1 != obj2, tag1 != tag2)
2432 @given(lists(oid_strategy()))
2433 def test_sorted_works(self, values):
2434 self.assertSequenceEqual(
2435 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2439 @given(data_strategy())
2440 def test_call(self, d):
2441 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2449 ) = d.draw(oid_values_strategy())
2450 obj_initial = klass(
2451 value=value_initial,
2454 default=default_initial,
2455 optional=optional_initial or False,
2456 _decoded=_decoded_initial,
2465 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2474 value_expected = default if value is None else value
2476 default_initial if value_expected is None
2479 self.assertEqual(obj, value_expected)
2480 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2481 self.assertEqual(obj.expl_tag, expl or expl_initial)
2484 default_initial if default is None else default,
2486 if obj.default is None:
2487 optional = optional_initial if optional is None else optional
2488 optional = False if optional is None else optional
2491 self.assertEqual(obj.optional, optional)
2493 @given(oid_values_strategy())
2494 def test_copy(self, values):
2495 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2512 obj_copied = obj.copy()
2513 self.assert_copied_basic_fields(obj, obj_copied)
2514 self.assertEqual(obj._value, obj_copied._value)
2516 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2519 integers(min_value=1).map(tag_encode),
2521 def test_stripped(self, value, tag_impl):
2522 obj = ObjectIdentifier(value, impl=tag_impl)
2523 with self.assertRaises(NotEnoughData):
2524 obj.decode(obj.encode()[:-1])
2528 integers(min_value=1).map(tag_ctxc),
2530 def test_stripped_expl(self, value, tag_expl):
2531 obj = ObjectIdentifier(value, expl=tag_expl)
2532 with self.assertRaises(NotEnoughData):
2533 obj.decode(obj.encode()[:-1])
2536 integers(min_value=31),
2537 integers(min_value=0),
2540 def test_bad_tag(self, tag, offset, decode_path):
2541 with self.assertRaises(DecodeError) as err:
2542 ObjectIdentifier().decode(
2543 tag_encode(tag)[:-1],
2545 decode_path=decode_path,
2548 self.assertEqual(err.exception.offset, offset)
2549 self.assertEqual(err.exception.decode_path, decode_path)
2552 integers(min_value=128),
2553 integers(min_value=0),
2556 def test_bad_len(self, l, offset, decode_path):
2557 with self.assertRaises(DecodeError) as err:
2558 ObjectIdentifier().decode(
2559 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2561 decode_path=decode_path,
2564 self.assertEqual(err.exception.offset, offset)
2565 self.assertEqual(err.exception.decode_path, decode_path)
2567 def test_zero_oid(self):
2568 with self.assertRaises(NotEnoughData):
2569 ObjectIdentifier().decode(
2570 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2573 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2574 @given(oid_strategy())
2575 def test_unfinished_oid(self, value):
2576 assume(list(value)[-1] > 255)
2577 obj_encoded = ObjectIdentifier(value).encode()
2578 obj, _ = ObjectIdentifier().decode(obj_encoded)
2579 data = obj_encoded[obj.tlen + obj.llen:-1]
2581 ObjectIdentifier.tag_default,
2582 len_encode(len(data)),
2585 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2588 @given(integers(min_value=0))
2589 def test_invalid_short(self, value):
2590 with self.assertRaises(InvalidOID):
2591 ObjectIdentifier((value,))
2592 with self.assertRaises(InvalidOID):
2593 ObjectIdentifier("%d" % value)
2595 @given(integers(min_value=3), integers(min_value=0))
2596 def test_invalid_first_arc(self, first_arc, second_arc):
2597 with self.assertRaises(InvalidOID):
2598 ObjectIdentifier((first_arc, second_arc))
2599 with self.assertRaises(InvalidOID):
2600 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2602 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2603 def test_invalid_second_arc(self, first_arc, second_arc):
2604 with self.assertRaises(InvalidOID):
2605 ObjectIdentifier((first_arc, second_arc))
2606 with self.assertRaises(InvalidOID):
2607 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2609 @given(text(alphabet=ascii_letters + ".", min_size=1))
2610 def test_junk(self, oid):
2611 with self.assertRaises(InvalidOID):
2612 ObjectIdentifier(oid)
2614 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2615 @given(oid_strategy())
2616 def test_validness(self, oid):
2617 obj = ObjectIdentifier(oid)
2618 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2621 pprint(obj, big_blobs=True, with_decode_path=True)
2623 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2625 oid_values_strategy(),
2627 integers(min_value=1).map(tag_ctxc),
2628 integers(min_value=0),
2631 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2632 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2633 _, _, _, default, optional, _decoded = values
2642 pprint(obj, big_blobs=True, with_decode_path=True)
2643 self.assertFalse(obj.expled)
2644 obj_encoded = obj.encode()
2645 obj_expled = obj(value, expl=tag_expl)
2646 self.assertTrue(obj_expled.expled)
2648 list(obj_expled.pps())
2649 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2650 obj_expled_encoded = obj_expled.encode()
2651 ctx_copied = deepcopy(ctx_dummy)
2652 obj_decoded, tail = obj_expled.decode(
2653 obj_expled_encoded + tail_junk,
2657 self.assertDictEqual(ctx_copied, ctx_dummy)
2659 list(obj_decoded.pps())
2660 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2661 self.assertEqual(tail, tail_junk)
2662 self.assertEqual(obj_decoded, obj_expled)
2663 self.assertNotEqual(obj_decoded, obj)
2664 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2665 self.assertEqual(tuple(obj_decoded), tuple(obj))
2666 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2667 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2668 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2670 obj_decoded.expl_llen,
2671 len(len_encode(len(obj_encoded))),
2673 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2674 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2677 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2679 self.assertEqual(obj_decoded.expl_offset, offset)
2682 oid_strategy().map(ObjectIdentifier),
2683 oid_strategy().map(ObjectIdentifier),
2685 def test_add(self, oid1, oid2):
2686 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2687 for oid_to_add in (oid2, tuple(oid2)):
2688 self.assertEqual(oid1 + oid_to_add, oid_expect)
2689 with self.assertRaises(InvalidValueType):
2692 def test_go_vectors_valid(self):
2693 for data, expect in (
2695 (b"\x55\x02", (2, 5, 2)),
2696 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2697 (b"\x81\x34\x03", (2, 100, 3)),
2700 ObjectIdentifier().decode(b"".join((
2701 ObjectIdentifier.tag_default,
2702 len_encode(len(data)),
2708 def test_go_vectors_invalid(self):
2709 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2710 with self.assertRaises(DecodeError):
2711 ObjectIdentifier().decode(b"".join((
2712 Integer.tag_default,
2713 len_encode(len(data)),
2717 def test_x690_vector(self):
2719 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2720 ObjectIdentifier((2, 999, 3)),
2723 @given(data_strategy())
2724 def test_nonnormalized_first_arc(self, d):
2726 ObjectIdentifier.tag_default +
2729 ObjectIdentifier((1, 0)).encode()[-1:]
2731 ObjectIdentifier().decode(tampered, ctx={"bered": True})
2732 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2733 ObjectIdentifier().decode(tampered)
2735 @given(data_strategy())
2736 def test_nonnormalized_arcs(self, d):
2737 arcs = d.draw(lists(
2738 integers(min_value=0, max_value=100),
2742 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2743 _, tlen, lv = tag_strip(dered)
2744 _, llen, v = len_decode(lv)
2745 v_no_first_arc = v[1:]
2746 idx_for_tamper = d.draw(integers(
2748 max_value=len(v_no_first_arc) - 1,
2750 tampered = list(bytearray(v_no_first_arc))
2751 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2752 tampered.insert(idx_for_tamper, 0x80)
2753 tampered = bytes(bytearray(tampered))
2755 ObjectIdentifier.tag_default +
2756 len_encode(len(tampered)) +
2759 ObjectIdentifier().decode(tampered, ctx={"bered": True})
2760 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2761 ObjectIdentifier().decode(tampered)
2765 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2767 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2768 values = list(draw(sets(
2770 min_size=len(schema),
2771 max_size=len(schema),
2773 schema = list(zip(schema, values))
2774 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2778 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2780 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2781 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2782 optional = draw(one_of(none(), booleans()))
2784 draw(integers(min_value=0)),
2785 draw(integers(min_value=0)),
2786 draw(integers(min_value=0)),
2788 return (schema, value, impl, expl, default, optional, _decoded)
2791 class TestEnumerated(CommonMixin, TestCase):
2792 class EWhatever(Enumerated):
2793 schema = (("whatever", 0),)
2795 base_klass = EWhatever
2797 def test_schema_required(self):
2798 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2801 def test_invalid_value_type(self):
2802 with self.assertRaises(InvalidValueType) as err:
2803 self.base_klass((1, 2))
2806 @given(sets(text_letters(), min_size=2))
2807 def test_unknown_name(self, schema_input):
2808 missing = schema_input.pop()
2810 class E(Enumerated):
2811 schema = [(n, 123) for n in schema_input]
2812 with self.assertRaises(ObjUnknown) as err:
2817 sets(text_letters(), min_size=2),
2818 sets(integers(), min_size=2),
2820 def test_unknown_value(self, schema_input, values_input):
2822 missing_value = values_input.pop()
2823 _input = list(zip(schema_input, values_input))
2825 class E(Enumerated):
2827 with self.assertRaises(DecodeError) as err:
2832 def test_optional(self, optional):
2833 obj = self.base_klass(default="whatever", optional=optional)
2834 self.assertTrue(obj.optional)
2836 def test_ready(self):
2837 obj = self.base_klass()
2838 self.assertFalse(obj.ready)
2841 pprint(obj, big_blobs=True, with_decode_path=True)
2842 with self.assertRaises(ObjNotReady) as err:
2845 obj = self.base_klass("whatever")
2846 self.assertTrue(obj.ready)
2849 pprint(obj, big_blobs=True, with_decode_path=True)
2851 @given(integers(), integers(), binary(), binary())
2852 def test_comparison(self, value1, value2, tag1, tag2):
2853 class E(Enumerated):
2855 ("whatever0", value1),
2856 ("whatever1", value2),
2859 class EInherited(E):
2861 for klass in (E, EInherited):
2862 obj1 = klass(value1)
2863 obj2 = klass(value2)
2864 self.assertEqual(obj1 == obj2, value1 == value2)
2865 self.assertEqual(obj1 != obj2, value1 != value2)
2866 self.assertEqual(obj1 == int(obj2), value1 == value2)
2867 obj1 = klass(value1, impl=tag1)
2868 obj2 = klass(value1, impl=tag2)
2869 self.assertEqual(obj1 == obj2, tag1 == tag2)
2870 self.assertEqual(obj1 != obj2, tag1 != tag2)
2872 @given(data_strategy())
2873 def test_call(self, d):
2882 ) = d.draw(enumerated_values_strategy())
2884 class E(Enumerated):
2885 schema = schema_initial
2887 value=value_initial,
2890 default=default_initial,
2891 optional=optional_initial or False,
2892 _decoded=_decoded_initial,
2902 ) = d.draw(enumerated_values_strategy(
2903 schema=schema_initial,
2904 do_expl=impl_initial is None,
2914 value_expected = default if value is None else value
2916 default_initial if value_expected is None
2921 dict(schema_initial).get(value_expected, value_expected),
2923 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2924 self.assertEqual(obj.expl_tag, expl or expl_initial)
2927 default_initial if default is None else default,
2929 if obj.default is None:
2930 optional = optional_initial if optional is None else optional
2931 optional = False if optional is None else optional
2934 self.assertEqual(obj.optional, optional)
2935 self.assertEqual(obj.specs, dict(schema_initial))
2937 @given(enumerated_values_strategy())
2938 def test_copy(self, values):
2939 schema_input, value, impl, expl, default, optional, _decoded = values
2941 class E(Enumerated):
2942 schema = schema_input
2951 obj_copied = obj.copy()
2952 self.assert_copied_basic_fields(obj, obj_copied)
2953 self.assertEqual(obj.specs, obj_copied.specs)
2955 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2956 @given(data_strategy())
2957 def test_symmetric(self, d):
2958 schema_input, _, _, _, default, optional, _decoded = d.draw(
2959 enumerated_values_strategy(),
2961 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2962 offset = d.draw(integers(min_value=0))
2963 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2964 tail_junk = d.draw(binary(max_size=5))
2966 class E(Enumerated):
2967 schema = schema_input
2976 pprint(obj, big_blobs=True, with_decode_path=True)
2977 self.assertFalse(obj.expled)
2978 obj_encoded = obj.encode()
2979 obj_expled = obj(value, expl=tag_expl)
2980 self.assertTrue(obj_expled.expled)
2982 list(obj_expled.pps())
2983 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2984 obj_expled_encoded = obj_expled.encode()
2985 ctx_copied = deepcopy(ctx_dummy)
2986 obj_decoded, tail = obj_expled.decode(
2987 obj_expled_encoded + tail_junk,
2991 self.assertDictEqual(ctx_copied, ctx_dummy)
2993 list(obj_decoded.pps())
2994 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2995 self.assertEqual(tail, tail_junk)
2996 self.assertEqual(obj_decoded, obj_expled)
2997 self.assertNotEqual(obj_decoded, obj)
2998 self.assertEqual(int(obj_decoded), int(obj_expled))
2999 self.assertEqual(int(obj_decoded), int(obj))
3000 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3001 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3002 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3004 obj_decoded.expl_llen,
3005 len(len_encode(len(obj_encoded))),
3007 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3008 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3011 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3013 self.assertEqual(obj_decoded.expl_offset, offset)
3017 def string_values_strategy(draw, alphabet, do_expl=False):
3018 bound_min, bound_max = sorted(draw(sets(
3019 integers(min_value=0, max_value=1 << 7),
3023 value = draw(one_of(
3025 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3027 default = draw(one_of(
3029 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3032 if draw(booleans()):
3033 bounds = (bound_min, bound_max)
3037 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3039 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3040 optional = draw(one_of(none(), booleans()))
3042 draw(integers(min_value=0)),
3043 draw(integers(min_value=0)),
3044 draw(integers(min_value=0)),
3046 return (value, bounds, impl, expl, default, optional, _decoded)
3049 class StringMixin(object):
3050 def test_invalid_value_type(self):
3051 with self.assertRaises(InvalidValueType) as err:
3052 self.base_klass((1, 2))
3055 def text_alphabet(self):
3056 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3057 return printable + whitespace
3061 def test_optional(self, optional):
3062 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3063 self.assertTrue(obj.optional)
3065 @given(data_strategy())
3066 def test_ready(self, d):
3067 obj = self.base_klass()
3068 self.assertFalse(obj.ready)
3071 pprint(obj, big_blobs=True, with_decode_path=True)
3073 with self.assertRaises(ObjNotReady) as err:
3076 value = d.draw(text(alphabet=self.text_alphabet()))
3077 obj = self.base_klass(value)
3078 self.assertTrue(obj.ready)
3081 pprint(obj, big_blobs=True, with_decode_path=True)
3084 @given(data_strategy())
3085 def test_comparison(self, d):
3086 value1 = d.draw(text(alphabet=self.text_alphabet()))
3087 value2 = d.draw(text(alphabet=self.text_alphabet()))
3088 tag1 = d.draw(binary(min_size=1))
3089 tag2 = d.draw(binary(min_size=1))
3090 obj1 = self.base_klass(value1)
3091 obj2 = self.base_klass(value2)
3092 self.assertEqual(obj1 == obj2, value1 == value2)
3093 self.assertEqual(obj1 != obj2, value1 != value2)
3094 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3095 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3096 obj1 = self.base_klass(value1, impl=tag1)
3097 obj2 = self.base_klass(value1, impl=tag2)
3098 self.assertEqual(obj1 == obj2, tag1 == tag2)
3099 self.assertEqual(obj1 != obj2, tag1 != tag2)
3101 @given(data_strategy())
3102 def test_bounds_satisfied(self, d):
3103 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3104 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3105 value = d.draw(text(
3106 alphabet=self.text_alphabet(),
3110 self.base_klass(value=value, bounds=(bound_min, bound_max))
3112 @given(data_strategy())
3113 def test_bounds_unsatisfied(self, d):
3114 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3115 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3116 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3117 with self.assertRaises(BoundsError) as err:
3118 self.base_klass(value=value, bounds=(bound_min, bound_max))
3120 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3121 self.base_klass(bounds=(bound_min, bound_max)).decode(
3122 self.base_klass(value).encode()
3125 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3126 with self.assertRaises(BoundsError) as err:
3127 self.base_klass(value=value, bounds=(bound_min, bound_max))
3129 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3130 self.base_klass(bounds=(bound_min, bound_max)).decode(
3131 self.base_klass(value).encode()
3135 @given(data_strategy())
3136 def test_call(self, d):
3145 ) = d.draw(string_values_strategy(self.text_alphabet()))
3146 obj_initial = self.base_klass(
3152 optional_initial or False,
3163 ) = d.draw(string_values_strategy(
3164 self.text_alphabet(),
3165 do_expl=impl_initial is None,
3167 if (default is None) and (obj_initial.default is not None):
3170 (bounds is None) and
3171 (value is not None) and
3172 (bounds_initial is not None) and
3173 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3177 (bounds is None) and
3178 (default is not None) and
3179 (bounds_initial is not None) and
3180 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3183 obj = obj_initial(value, bounds, impl, expl, default, optional)
3185 value_expected = default if value is None else value
3187 default_initial if value_expected is None
3190 self.assertEqual(obj, value_expected)
3191 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3192 self.assertEqual(obj.expl_tag, expl or expl_initial)
3195 default_initial if default is None else default,
3197 if obj.default is None:
3198 optional = optional_initial if optional is None else optional
3199 optional = False if optional is None else optional
3202 self.assertEqual(obj.optional, optional)
3204 (obj._bound_min, obj._bound_max),
3205 bounds or bounds_initial or (0, float("+inf")),
3208 @given(data_strategy())
3209 def test_copy(self, d):
3210 values = d.draw(string_values_strategy(self.text_alphabet()))
3211 obj = self.base_klass(*values)
3212 obj_copied = obj.copy()
3213 self.assert_copied_basic_fields(obj, obj_copied)
3214 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3215 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3216 self.assertEqual(obj._value, obj_copied._value)
3218 @given(data_strategy())
3219 def test_stripped(self, d):
3220 value = d.draw(text(alphabet=self.text_alphabet()))
3221 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3222 obj = self.base_klass(value, impl=tag_impl)
3223 with self.assertRaises(NotEnoughData):
3224 obj.decode(obj.encode()[:-1])
3226 @given(data_strategy())
3227 def test_stripped_expl(self, d):
3228 value = d.draw(text(alphabet=self.text_alphabet()))
3229 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3230 obj = self.base_klass(value, expl=tag_expl)
3231 with self.assertRaises(NotEnoughData):
3232 obj.decode(obj.encode()[:-1])
3235 integers(min_value=31),
3236 integers(min_value=0),
3239 def test_bad_tag(self, tag, offset, decode_path):
3240 with self.assertRaises(DecodeError) as err:
3241 self.base_klass().decode(
3242 tag_encode(tag)[:-1],
3244 decode_path=decode_path,
3247 self.assertEqual(err.exception.offset, offset)
3248 self.assertEqual(err.exception.decode_path, decode_path)
3251 integers(min_value=128),
3252 integers(min_value=0),
3255 def test_bad_len(self, l, offset, decode_path):
3256 with self.assertRaises(DecodeError) as err:
3257 self.base_klass().decode(
3258 self.base_klass.tag_default + len_encode(l)[:-1],
3260 decode_path=decode_path,
3263 self.assertEqual(err.exception.offset, offset)
3264 self.assertEqual(err.exception.decode_path, decode_path)
3267 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3268 integers(min_value=0),
3271 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3272 value, bound_min = list(sorted(ints))
3274 class String(self.base_klass):
3275 # Multiply this value by four, to satisfy UTF-32 bounds
3276 # (4 bytes per character) validation
3277 bounds = (bound_min * 4, bound_min * 4)
3278 with self.assertRaises(DecodeError) as err:
3280 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3282 decode_path=decode_path,
3285 self.assertEqual(err.exception.offset, offset)
3286 self.assertEqual(err.exception.decode_path, decode_path)
3288 @given(data_strategy())
3289 def test_symmetric(self, d):
3290 values = d.draw(string_values_strategy(self.text_alphabet()))
3291 value = d.draw(text(alphabet=self.text_alphabet()))
3292 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3293 offset = d.draw(integers(min_value=0))
3294 tail_junk = d.draw(binary(max_size=5))
3295 _, _, _, _, default, optional, _decoded = values
3296 obj = self.base_klass(
3304 pprint(obj, big_blobs=True, with_decode_path=True)
3305 self.assertFalse(obj.expled)
3306 obj_encoded = obj.encode()
3307 obj_expled = obj(value, expl=tag_expl)
3308 self.assertTrue(obj_expled.expled)
3310 list(obj_expled.pps())
3311 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3312 obj_expled_encoded = obj_expled.encode()
3313 ctx_copied = deepcopy(ctx_dummy)
3314 obj_decoded, tail = obj_expled.decode(
3315 obj_expled_encoded + tail_junk,
3319 self.assertDictEqual(ctx_copied, ctx_dummy)
3321 list(obj_decoded.pps())
3322 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3323 self.assertEqual(tail, tail_junk)
3324 self.assertEqual(obj_decoded, obj_expled)
3325 self.assertNotEqual(obj_decoded, obj)
3326 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3327 self.assertEqual(bytes(obj_decoded), bytes(obj))
3328 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3329 self.assertEqual(text_type(obj_decoded), text_type(obj))
3330 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3331 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3332 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3334 obj_decoded.expl_llen,
3335 len(len_encode(len(obj_encoded))),
3337 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3338 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3341 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3343 self.assertEqual(obj_decoded.expl_offset, offset)
3346 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3347 base_klass = UTF8String
3350 cyrillic_letters = text(
3351 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3357 class UnicodeDecodeErrorMixin(object):
3358 @given(cyrillic_letters)
3359 def test_unicode_decode_error(self, cyrillic_text):
3360 with self.assertRaises(DecodeError):
3361 self.base_klass(cyrillic_text)
3364 class TestNumericString(StringMixin, CommonMixin, TestCase):
3365 base_klass = NumericString
3367 def text_alphabet(self):
3370 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3371 def test_non_numeric(self, non_numeric_text):
3372 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3373 self.base_klass(non_numeric_text)
3376 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3377 integers(min_value=0),
3380 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3381 value, bound_min = list(sorted(ints))
3383 class String(self.base_klass):
3384 bounds = (bound_min, bound_min)
3385 with self.assertRaises(DecodeError) as err:
3387 self.base_klass(b"1" * value).encode(),
3389 decode_path=decode_path,
3392 self.assertEqual(err.exception.offset, offset)
3393 self.assertEqual(err.exception.decode_path, decode_path)
3396 class TestPrintableString(
3397 UnicodeDecodeErrorMixin,
3402 base_klass = PrintableString
3404 def text_alphabet(self):
3405 return ascii_letters + digits + " '()+,-./:=?"
3407 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3408 def test_non_printable(self, non_printable_text):
3409 with assertRaisesRegex(self, DecodeError, "non-printable"):
3410 self.base_klass(non_printable_text)
3413 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3414 integers(min_value=0),
3417 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3418 value, bound_min = list(sorted(ints))
3420 class String(self.base_klass):
3421 bounds = (bound_min, bound_min)
3422 with self.assertRaises(DecodeError) as err:
3424 self.base_klass(b"1" * value).encode(),
3426 decode_path=decode_path,
3429 self.assertEqual(err.exception.offset, offset)
3430 self.assertEqual(err.exception.decode_path, decode_path)
3433 class TestTeletexString(
3434 UnicodeDecodeErrorMixin,
3439 base_klass = TeletexString
3442 class TestVideotexString(
3443 UnicodeDecodeErrorMixin,
3448 base_klass = VideotexString
3451 class TestIA5String(
3452 UnicodeDecodeErrorMixin,
3457 base_klass = IA5String
3460 class TestGraphicString(
3461 UnicodeDecodeErrorMixin,
3466 base_klass = GraphicString
3469 class TestVisibleString(
3470 UnicodeDecodeErrorMixin,
3475 base_klass = VisibleString
3477 def test_x690_vector(self):
3478 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3479 self.assertSequenceEqual(tail, b"")
3480 self.assertEqual(str(obj), "Jones")
3481 self.assertFalse(obj.ber_encoded)
3482 self.assertFalse(obj.lenindef)
3483 self.assertFalse(obj.bered)
3485 obj, tail = VisibleString().decode(
3486 hexdec("3A0904034A6F6E04026573"),
3487 ctx={"bered": True},
3489 self.assertSequenceEqual(tail, b"")
3490 self.assertEqual(str(obj), "Jones")
3491 self.assertTrue(obj.ber_encoded)
3492 self.assertFalse(obj.lenindef)
3493 self.assertTrue(obj.bered)
3495 obj, tail = VisibleString().decode(
3496 hexdec("3A8004034A6F6E040265730000"),
3497 ctx={"bered": True},
3499 self.assertSequenceEqual(tail, b"")
3500 self.assertEqual(str(obj), "Jones")
3501 self.assertTrue(obj.ber_encoded)
3502 self.assertTrue(obj.lenindef)
3503 self.assertTrue(obj.bered)
3506 class TestGeneralString(
3507 UnicodeDecodeErrorMixin,
3512 base_klass = GeneralString
3515 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3516 base_klass = UniversalString
3519 class TestBMPString(StringMixin, CommonMixin, TestCase):
3520 base_klass = BMPString
3524 def generalized_time_values_strategy(
3532 if draw(booleans()):
3533 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3535 value = value.replace(microsecond=0)
3537 if draw(booleans()):
3538 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3540 default = default.replace(microsecond=0)
3544 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3546 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3547 optional = draw(one_of(none(), booleans()))
3549 draw(integers(min_value=0)),
3550 draw(integers(min_value=0)),
3551 draw(integers(min_value=0)),
3553 return (value, impl, expl, default, optional, _decoded)
3556 class TimeMixin(object):
3557 def test_invalid_value_type(self):
3558 with self.assertRaises(InvalidValueType) as err:
3559 self.base_klass(datetime.now().timetuple())
3562 @given(data_strategy())
3563 def test_optional(self, d):
3564 default = d.draw(datetimes(
3565 min_value=self.min_datetime,
3566 max_value=self.max_datetime,
3568 optional = d.draw(booleans())
3569 obj = self.base_klass(default=default, optional=optional)
3570 self.assertTrue(obj.optional)
3572 @given(data_strategy())
3573 def test_ready(self, d):
3574 obj = self.base_klass()
3575 self.assertFalse(obj.ready)
3578 pprint(obj, big_blobs=True, with_decode_path=True)
3579 with self.assertRaises(ObjNotReady) as err:
3582 value = d.draw(datetimes(min_value=self.min_datetime))
3583 obj = self.base_klass(value)
3584 self.assertTrue(obj.ready)
3587 pprint(obj, big_blobs=True, with_decode_path=True)
3589 @given(data_strategy())
3590 def test_comparison(self, d):
3591 value1 = d.draw(datetimes(
3592 min_value=self.min_datetime,
3593 max_value=self.max_datetime,
3595 value2 = d.draw(datetimes(
3596 min_value=self.min_datetime,
3597 max_value=self.max_datetime,
3599 tag1 = d.draw(binary(min_size=1))
3600 tag2 = d.draw(binary(min_size=1))
3602 value1 = value1.replace(microsecond=0)
3603 value2 = value2.replace(microsecond=0)
3604 obj1 = self.base_klass(value1)
3605 obj2 = self.base_klass(value2)
3606 self.assertEqual(obj1 == obj2, value1 == value2)
3607 self.assertEqual(obj1 != obj2, value1 != value2)
3608 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3609 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3610 obj1 = self.base_klass(value1, impl=tag1)
3611 obj2 = self.base_klass(value1, impl=tag2)
3612 self.assertEqual(obj1 == obj2, tag1 == tag2)
3613 self.assertEqual(obj1 != obj2, tag1 != tag2)
3615 @given(data_strategy())
3616 def test_call(self, d):
3624 ) = d.draw(generalized_time_values_strategy(
3625 min_datetime=self.min_datetime,
3626 max_datetime=self.max_datetime,
3627 omit_ms=self.omit_ms,
3629 obj_initial = self.base_klass(
3630 value=value_initial,
3633 default=default_initial,
3634 optional=optional_initial or False,
3635 _decoded=_decoded_initial,
3644 ) = d.draw(generalized_time_values_strategy(
3645 min_datetime=self.min_datetime,
3646 max_datetime=self.max_datetime,
3647 omit_ms=self.omit_ms,
3648 do_expl=impl_initial is None,
3658 value_expected = default if value is None else value
3660 default_initial if value_expected is None
3663 self.assertEqual(obj, value_expected)
3664 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3665 self.assertEqual(obj.expl_tag, expl or expl_initial)
3668 default_initial if default is None else default,
3670 if obj.default is None:
3671 optional = optional_initial if optional is None else optional
3672 optional = False if optional is None else optional
3675 self.assertEqual(obj.optional, optional)
3677 @given(data_strategy())
3678 def test_copy(self, d):
3679 values = d.draw(generalized_time_values_strategy(
3680 min_datetime=self.min_datetime,
3681 max_datetime=self.max_datetime,
3683 obj = self.base_klass(*values)
3684 obj_copied = obj.copy()
3685 self.assert_copied_basic_fields(obj, obj_copied)
3686 self.assertEqual(obj._value, obj_copied._value)
3688 @given(data_strategy())
3689 def test_stripped(self, d):
3690 value = d.draw(datetimes(
3691 min_value=self.min_datetime,
3692 max_value=self.max_datetime,
3694 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3695 obj = self.base_klass(value, impl=tag_impl)
3696 with self.assertRaises(NotEnoughData):
3697 obj.decode(obj.encode()[:-1])
3699 @given(data_strategy())
3700 def test_stripped_expl(self, d):
3701 value = d.draw(datetimes(
3702 min_value=self.min_datetime,
3703 max_value=self.max_datetime,
3705 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3706 obj = self.base_klass(value, expl=tag_expl)
3707 with self.assertRaises(NotEnoughData):
3708 obj.decode(obj.encode()[:-1])
3710 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3711 @given(data_strategy())
3712 def test_symmetric(self, d):
3713 values = d.draw(generalized_time_values_strategy(
3714 min_datetime=self.min_datetime,
3715 max_datetime=self.max_datetime,
3717 value = d.draw(datetimes(
3718 min_value=self.min_datetime,
3719 max_value=self.max_datetime,
3721 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3722 offset = d.draw(integers(min_value=0))
3723 tail_junk = d.draw(binary(max_size=5))
3724 _, _, _, default, optional, _decoded = values
3725 obj = self.base_klass(
3733 pprint(obj, big_blobs=True, with_decode_path=True)
3734 self.assertFalse(obj.expled)
3735 obj_encoded = obj.encode()
3736 obj_expled = obj(value, expl=tag_expl)
3737 self.assertTrue(obj_expled.expled)
3739 list(obj_expled.pps())
3740 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3741 obj_expled_encoded = obj_expled.encode()
3742 ctx_copied = deepcopy(ctx_dummy)
3743 obj_decoded, tail = obj_expled.decode(
3744 obj_expled_encoded + tail_junk,
3748 self.assertDictEqual(ctx_copied, ctx_dummy)
3750 list(obj_decoded.pps())
3751 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3752 self.assertEqual(tail, tail_junk)
3753 self.assertEqual(obj_decoded, obj_expled)
3754 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3755 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3756 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3757 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3758 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3760 obj_decoded.expl_llen,
3761 len(len_encode(len(obj_encoded))),
3763 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3764 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3767 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3769 self.assertEqual(obj_decoded.expl_offset, offset)
3772 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3773 base_klass = GeneralizedTime
3775 min_datetime = datetime(1900, 1, 1)
3776 max_datetime = datetime(9999, 12, 31)
3778 def test_go_vectors_invalid(self):
3790 b"-20100102030410Z",
3791 b"2010-0102030410Z",
3792 b"2010-0002030410Z",
3793 b"201001-02030410Z",
3794 b"20100102-030410Z",
3795 b"2010010203-0410Z",
3796 b"201001020304-10Z",
3797 # These ones are INVALID in *DER*, but accepted
3798 # by Go's encoding/asn1
3799 b"20100102030405+0607",
3800 b"20100102030405-0607",
3802 with self.assertRaises(DecodeError) as err:
3803 GeneralizedTime(data)
3806 def test_go_vectors_valid(self):
3808 GeneralizedTime(b"20100102030405Z").todatetime(),
3809 datetime(2010, 1, 2, 3, 4, 5, 0),
3814 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3815 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3817 binary(min_size=1, max_size=1),
3819 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3820 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3823 def test_junk(self, part0, part1, part2):
3824 junk = part0 + part1 + part2
3825 assume(not (set(junk) <= set(digits.encode("ascii"))))
3826 with self.assertRaises(DecodeError):
3827 GeneralizedTime().decode(
3828 GeneralizedTime.tag_default +
3829 len_encode(len(junk)) +
3835 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3836 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3838 binary(min_size=1, max_size=1),
3840 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3841 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3844 def test_junk_dm(self, part0, part1, part2):
3845 junk = part0 + part1 + part2
3846 assume(not (set(junk) <= set(digits.encode("ascii"))))
3847 with self.assertRaises(DecodeError):
3848 GeneralizedTime().decode(
3849 GeneralizedTime.tag_default +
3850 len_encode(len(junk)) +
3855 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3856 base_klass = UTCTime
3858 min_datetime = datetime(2000, 1, 1)
3859 max_datetime = datetime(2049, 12, 31)
3861 def test_go_vectors_invalid(self):
3887 # These ones are INVALID in *DER*, but accepted
3888 # by Go's encoding/asn1
3889 b"910506164540-0700",
3890 b"910506164540+0730",
3894 with self.assertRaises(DecodeError) as err:
3898 def test_go_vectors_valid(self):
3900 UTCTime(b"910506234540Z").todatetime(),
3901 datetime(1991, 5, 6, 23, 45, 40, 0),
3904 @given(integers(min_value=0, max_value=49))
3905 def test_pre50(self, year):
3907 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3911 @given(integers(min_value=50, max_value=99))
3912 def test_post50(self, year):
3914 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3920 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3921 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3923 binary(min_size=1, max_size=1),
3925 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3926 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3929 def test_junk(self, part0, part1, part2):
3930 junk = part0 + part1 + part2
3931 assume(not (set(junk) <= set(digits.encode("ascii"))))
3932 with self.assertRaises(DecodeError):
3934 UTCTime.tag_default +
3935 len_encode(len(junk)) +
3941 def any_values_strategy(draw, do_expl=False):
3942 value = draw(one_of(none(), binary()))
3945 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3946 optional = draw(one_of(none(), booleans()))
3948 draw(integers(min_value=0)),
3949 draw(integers(min_value=0)),
3950 draw(integers(min_value=0)),
3952 return (value, expl, optional, _decoded)
3955 class AnyInherited(Any):
3959 class TestAny(CommonMixin, TestCase):
3962 def test_invalid_value_type(self):
3963 with self.assertRaises(InvalidValueType) as err:
3968 def test_optional(self, optional):
3969 obj = Any(optional=optional)
3970 self.assertEqual(obj.optional, optional)
3973 def test_ready(self, value):
3975 self.assertFalse(obj.ready)
3978 pprint(obj, big_blobs=True, with_decode_path=True)
3979 with self.assertRaises(ObjNotReady) as err:
3983 self.assertTrue(obj.ready)
3986 pprint(obj, big_blobs=True, with_decode_path=True)
3989 def test_basic(self, value):
3990 integer_encoded = Integer(value).encode()
3992 Any(integer_encoded),
3993 Any(Integer(value)),
3994 Any(Any(Integer(value))),
3996 self.assertSequenceEqual(bytes(obj), integer_encoded)
3998 obj.decode(obj.encode())[0].vlen,
3999 len(integer_encoded),
4003 pprint(obj, big_blobs=True, with_decode_path=True)
4004 self.assertSequenceEqual(obj.encode(), integer_encoded)
4006 @given(binary(), binary())
4007 def test_comparison(self, value1, value2):
4008 for klass in (Any, AnyInherited):
4009 obj1 = klass(value1)
4010 obj2 = klass(value2)
4011 self.assertEqual(obj1 == obj2, value1 == value2)
4012 self.assertEqual(obj1 != obj2, value1 != value2)
4013 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4015 @given(data_strategy())
4016 def test_call(self, d):
4017 for klass in (Any, AnyInherited):
4023 ) = d.draw(any_values_strategy())
4024 obj_initial = klass(
4027 optional_initial or False,
4035 ) = d.draw(any_values_strategy(do_expl=True))
4036 obj = obj_initial(value, expl, optional)
4038 value_expected = None if value is None else value
4039 self.assertEqual(obj, value_expected)
4040 self.assertEqual(obj.expl_tag, expl or expl_initial)
4041 if obj.default is None:
4042 optional = optional_initial if optional is None else optional
4043 optional = False if optional is None else optional
4044 self.assertEqual(obj.optional, optional)
4046 def test_simultaneous_impl_expl(self):
4047 # override it, as Any does not have implicit tag
4050 def test_decoded(self):
4051 # override it, as Any does not have implicit tag
4054 @given(any_values_strategy())
4055 def test_copy(self, values):
4056 for klass in (Any, AnyInherited):
4057 obj = klass(*values)
4058 obj_copied = obj.copy()
4059 self.assert_copied_basic_fields(obj, obj_copied)
4060 self.assertEqual(obj._value, obj_copied._value)
4062 @given(binary().map(OctetString))
4063 def test_stripped(self, value):
4065 with self.assertRaises(NotEnoughData):
4066 obj.decode(obj.encode()[:-1])
4070 integers(min_value=1).map(tag_ctxc),
4072 def test_stripped_expl(self, value, tag_expl):
4073 obj = Any(value, expl=tag_expl)
4074 with self.assertRaises(NotEnoughData):
4075 obj.decode(obj.encode()[:-1])
4078 integers(min_value=31),
4079 integers(min_value=0),
4082 def test_bad_tag(self, tag, offset, decode_path):
4083 with self.assertRaises(DecodeError) as err:
4085 tag_encode(tag)[:-1],
4087 decode_path=decode_path,
4090 self.assertEqual(err.exception.offset, offset)
4091 self.assertEqual(err.exception.decode_path, decode_path)
4094 integers(min_value=128),
4095 integers(min_value=0),
4098 def test_bad_len(self, l, offset, decode_path):
4099 with self.assertRaises(DecodeError) as err:
4101 Any.tag_default + len_encode(l)[:-1],
4103 decode_path=decode_path,
4106 self.assertEqual(err.exception.offset, offset)
4107 self.assertEqual(err.exception.decode_path, decode_path)
4109 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4111 any_values_strategy(),
4112 integers().map(lambda x: Integer(x).encode()),
4113 integers(min_value=1).map(tag_ctxc),
4114 integers(min_value=0),
4117 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4118 for klass in (Any, AnyInherited):
4119 _, _, optional, _decoded = values
4120 obj = klass(value=value, optional=optional, _decoded=_decoded)
4123 pprint(obj, big_blobs=True, with_decode_path=True)
4124 self.assertFalse(obj.expled)
4125 obj_encoded = obj.encode()
4126 obj_expled = obj(value, expl=tag_expl)
4127 self.assertTrue(obj_expled.expled)
4129 list(obj_expled.pps())
4130 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4131 obj_expled_encoded = obj_expled.encode()
4132 ctx_copied = deepcopy(ctx_dummy)
4133 obj_decoded, tail = obj_expled.decode(
4134 obj_expled_encoded + tail_junk,
4138 self.assertDictEqual(ctx_copied, ctx_dummy)
4140 list(obj_decoded.pps())
4141 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4142 self.assertEqual(tail, tail_junk)
4143 self.assertEqual(obj_decoded, obj_expled)
4144 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4145 self.assertEqual(bytes(obj_decoded), bytes(obj))
4146 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4147 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4148 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4150 obj_decoded.expl_llen,
4151 len(len_encode(len(obj_encoded))),
4153 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4154 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4157 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4159 self.assertEqual(obj_decoded.expl_offset, offset)
4160 self.assertEqual(obj_decoded.tlen, 0)
4161 self.assertEqual(obj_decoded.llen, 0)
4162 self.assertEqual(obj_decoded.vlen, len(value))
4165 integers(min_value=1).map(tag_ctxc),
4166 integers(min_value=0, max_value=3),
4167 integers(min_value=0),
4171 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4172 chunk = Boolean(False, expl=expl).encode()
4174 OctetString.tag_default +
4176 b"".join([chunk] * chunks) +
4179 with self.assertRaises(LenIndefForm):
4183 decode_path=decode_path,
4185 obj, tail = Any().decode(
4188 decode_path=decode_path,
4189 ctx={"bered": True},
4191 self.assertSequenceEqual(tail, junk)
4192 self.assertEqual(obj.offset, offset)
4193 self.assertEqual(obj.tlvlen, len(encoded))
4194 self.assertTrue(obj.lenindef)
4195 self.assertFalse(obj.ber_encoded)
4196 self.assertTrue(obj.bered)
4199 pprint(obj, big_blobs=True, with_decode_path=True)
4200 with self.assertRaises(NotEnoughData) as err:
4204 decode_path=decode_path,
4205 ctx={"bered": True},
4207 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4208 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4210 class SeqOf(SequenceOf):
4211 schema = Boolean(expl=expl)
4213 class Seq(Sequence):
4215 ("type", ObjectIdentifier(defines=((("value",), {
4216 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4221 ("type", ObjectIdentifier("1.2.3")),
4222 ("value", Any(encoded)),
4224 seq_encoded = seq.encode()
4225 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4226 self.assertIsNotNone(seq_decoded["value"].defined)
4228 list(seq_decoded.pps())
4229 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4230 self.assertTrue(seq_decoded.bered)
4231 self.assertFalse(seq_decoded["type"].bered)
4232 self.assertTrue(seq_decoded["value"].bered)
4234 chunk = chunk[:-1] + b"\x01"
4235 chunks = b"".join([chunk] * (chunks + 1))
4236 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4238 ("type", ObjectIdentifier("1.2.3")),
4239 ("value", Any(encoded)),
4241 seq_encoded = seq.encode()
4242 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4243 self.assertIsNotNone(seq_decoded["value"].defined)
4245 list(seq_decoded.pps())
4246 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4247 self.assertTrue(seq_decoded.bered)
4248 self.assertFalse(seq_decoded["type"].bered)
4249 self.assertTrue(seq_decoded["value"].bered)
4253 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4255 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4256 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4258 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4259 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4261 min_size=len(names),
4262 max_size=len(names),
4265 (name, Integer(**tag_kwargs))
4266 for name, tag_kwargs in zip(names, tags)
4269 if value_required or draw(booleans()):
4270 value = draw(tuples(
4271 sampled_from([name for name, _ in schema]),
4272 integers().map(Integer),
4276 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4277 default = draw(one_of(
4279 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4281 optional = draw(one_of(none(), booleans()))
4283 draw(integers(min_value=0)),
4284 draw(integers(min_value=0)),
4285 draw(integers(min_value=0)),
4287 return (schema, value, expl, default, optional, _decoded)
4290 class ChoiceInherited(Choice):
4294 class TestChoice(CommonMixin, TestCase):
4296 schema = (("whatever", Boolean()),)
4299 def test_schema_required(self):
4300 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4303 def test_impl_forbidden(self):
4304 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4305 Choice(impl=b"whatever")
4307 def test_invalid_value_type(self):
4308 with self.assertRaises(InvalidValueType) as err:
4309 self.base_klass(123)
4311 with self.assertRaises(ObjUnknown) as err:
4312 self.base_klass(("whenever", Boolean(False)))
4314 with self.assertRaises(InvalidValueType) as err:
4315 self.base_klass(("whatever", Integer(123)))
4319 def test_optional(self, optional):
4320 obj = self.base_klass(
4321 default=self.base_klass(("whatever", Boolean(False))),
4324 self.assertTrue(obj.optional)
4327 def test_ready(self, value):
4328 obj = self.base_klass()
4329 self.assertFalse(obj.ready)
4332 pprint(obj, big_blobs=True, with_decode_path=True)
4333 self.assertIsNone(obj["whatever"])
4334 with self.assertRaises(ObjNotReady) as err:
4337 obj["whatever"] = Boolean()
4338 self.assertFalse(obj.ready)
4341 pprint(obj, big_blobs=True, with_decode_path=True)
4342 obj["whatever"] = Boolean(value)
4343 self.assertTrue(obj.ready)
4346 pprint(obj, big_blobs=True, with_decode_path=True)
4348 @given(booleans(), booleans())
4349 def test_comparison(self, value1, value2):
4350 class WahlInherited(self.base_klass):
4352 for klass in (self.base_klass, WahlInherited):
4353 obj1 = klass(("whatever", Boolean(value1)))
4354 obj2 = klass(("whatever", Boolean(value2)))
4355 self.assertEqual(obj1 == obj2, value1 == value2)
4356 self.assertEqual(obj1 != obj2, value1 != value2)
4357 self.assertEqual(obj1 == obj2._value, value1 == value2)
4358 self.assertFalse(obj1 == obj2._value[1])
4360 @given(data_strategy())
4361 def test_call(self, d):
4362 for klass in (Choice, ChoiceInherited):
4370 ) = d.draw(choice_values_strategy())
4373 schema = schema_initial
4375 value=value_initial,
4377 default=default_initial,
4378 optional=optional_initial or False,
4379 _decoded=_decoded_initial,
4388 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4389 obj = obj_initial(value, expl, default, optional)
4391 value_expected = default if value is None else value
4393 default_initial if value_expected is None
4396 self.assertEqual(obj.choice, value_expected[0])
4397 self.assertEqual(obj.value, int(value_expected[1]))
4398 self.assertEqual(obj.expl_tag, expl or expl_initial)
4399 default_expect = default_initial if default is None else default
4400 if default_expect is not None:
4401 self.assertEqual(obj.default.choice, default_expect[0])
4402 self.assertEqual(obj.default.value, int(default_expect[1]))
4403 if obj.default is None:
4404 optional = optional_initial if optional is None else optional
4405 optional = False if optional is None else optional
4408 self.assertEqual(obj.optional, optional)
4409 self.assertEqual(obj.specs, obj_initial.specs)
4411 def test_simultaneous_impl_expl(self):
4412 # override it, as Any does not have implicit tag
4415 def test_decoded(self):
4416 # override it, as Any does not have implicit tag
4419 @given(choice_values_strategy())
4420 def test_copy(self, values):
4421 _schema, value, expl, default, optional, _decoded = values
4423 class Wahl(self.base_klass):
4429 optional=optional or False,
4432 obj_copied = obj.copy()
4433 self.assertIsNone(obj.tag)
4434 self.assertIsNone(obj_copied.tag)
4435 # hack for assert_copied_basic_fields
4436 obj.tag = "whatever"
4437 obj_copied.tag = "whatever"
4438 self.assert_copied_basic_fields(obj, obj_copied)
4439 self.assertEqual(obj._value, obj_copied._value)
4440 self.assertEqual(obj.specs, obj_copied.specs)
4443 def test_stripped(self, value):
4444 obj = self.base_klass(("whatever", Boolean(value)))
4445 with self.assertRaises(NotEnoughData):
4446 obj.decode(obj.encode()[:-1])
4450 integers(min_value=1).map(tag_ctxc),
4452 def test_stripped_expl(self, value, tag_expl):
4453 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4454 with self.assertRaises(NotEnoughData):
4455 obj.decode(obj.encode()[:-1])
4457 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4458 @given(data_strategy())
4459 def test_symmetric(self, d):
4460 _schema, value, _, default, optional, _decoded = d.draw(
4461 choice_values_strategy(value_required=True)
4463 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4464 offset = d.draw(integers(min_value=0))
4465 tail_junk = d.draw(binary(max_size=5))
4467 class Wahl(self.base_klass):
4477 pprint(obj, big_blobs=True, with_decode_path=True)
4478 self.assertFalse(obj.expled)
4479 obj_encoded = obj.encode()
4480 obj_expled = obj(value, expl=tag_expl)
4481 self.assertTrue(obj_expled.expled)
4483 list(obj_expled.pps())
4484 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4485 obj_expled_encoded = obj_expled.encode()
4486 ctx_copied = deepcopy(ctx_dummy)
4487 obj_decoded, tail = obj_expled.decode(
4488 obj_expled_encoded + tail_junk,
4492 self.assertDictEqual(ctx_copied, ctx_dummy)
4494 list(obj_decoded.pps())
4495 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4496 self.assertEqual(tail, tail_junk)
4497 self.assertEqual(obj_decoded, obj_expled)
4498 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4499 self.assertEqual(obj_decoded.value, obj_expled.value)
4500 self.assertEqual(obj_decoded.choice, obj.choice)
4501 self.assertEqual(obj_decoded.value, obj.value)
4502 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4503 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4504 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4506 obj_decoded.expl_llen,
4507 len(len_encode(len(obj_encoded))),
4509 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4510 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4513 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4515 self.assertEqual(obj_decoded.expl_offset, offset)
4516 self.assertSequenceEqual(
4518 obj_decoded.value.fulloffset - offset:
4519 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4525 def test_set_get(self, value):
4528 ("erste", Boolean()),
4529 ("zweite", Integer()),
4532 with self.assertRaises(ObjUnknown) as err:
4533 obj["whatever"] = "whenever"
4534 with self.assertRaises(InvalidValueType) as err:
4535 obj["zweite"] = Boolean(False)
4536 obj["zweite"] = Integer(value)
4538 with self.assertRaises(ObjUnknown) as err:
4541 self.assertIsNone(obj["erste"])
4542 self.assertEqual(obj["zweite"], Integer(value))
4544 def test_tag_mismatch(self):
4547 ("erste", Boolean()),
4549 int_encoded = Integer(123).encode()
4550 bool_encoded = Boolean(False).encode()
4552 obj.decode(bool_encoded)
4553 with self.assertRaises(TagMismatch):
4554 obj.decode(int_encoded)
4556 def test_tag_mismatch_underlying(self):
4557 class SeqOfBoolean(SequenceOf):
4560 class SeqOfInteger(SequenceOf):
4565 ("erste", SeqOfBoolean()),
4568 int_encoded = SeqOfInteger((Integer(123),)).encode()
4569 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4571 obj.decode(bool_encoded)
4572 with self.assertRaises(TagMismatch) as err:
4573 obj.decode(int_encoded)
4574 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4578 def seq_values_strategy(draw, seq_klass, do_expl=False):
4580 if draw(booleans()):
4583 k: v for k, v in draw(dictionaries(
4586 booleans().map(Boolean),
4587 integers().map(Integer),
4592 if draw(booleans()):
4593 schema = list(draw(dictionaries(
4596 booleans().map(Boolean),
4597 integers().map(Integer),
4603 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4605 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4607 if draw(booleans()):
4608 default = seq_klass()
4610 k: v for k, v in draw(dictionaries(
4613 booleans().map(Boolean),
4614 integers().map(Integer),
4618 optional = draw(one_of(none(), booleans()))
4620 draw(integers(min_value=0)),
4621 draw(integers(min_value=0)),
4622 draw(integers(min_value=0)),
4624 return (value, schema, impl, expl, default, optional, _decoded)
4628 def sequence_strategy(draw, seq_klass):
4629 inputs = draw(lists(
4631 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4632 tuples(just(Integer), integers(), one_of(none(), integers())),
4637 integers(min_value=1),
4638 min_size=len(inputs),
4639 max_size=len(inputs),
4642 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4643 for tag, expled in zip(tags, draw(lists(
4645 min_size=len(inputs),
4646 max_size=len(inputs),
4650 for i, optional in enumerate(draw(lists(
4651 sampled_from(("required", "optional", "empty")),
4652 min_size=len(inputs),
4653 max_size=len(inputs),
4655 if optional in ("optional", "empty"):
4656 inits[i]["optional"] = True
4657 if optional == "empty":
4659 empties = set(empties)
4660 names = list(draw(sets(
4662 min_size=len(inputs),
4663 max_size=len(inputs),
4666 for i, (klass, value, default) in enumerate(inputs):
4667 schema.append((names[i], klass(default=default, **inits[i])))
4668 seq_name = draw(text_letters())
4669 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4672 for i, (klass, value, default) in enumerate(inputs):
4679 "default_value": None if spec.default is None else default,
4683 expect["optional"] = True
4685 expect["presented"] = True
4686 expect["value"] = value
4688 expect["optional"] = True
4689 if default is not None and default == value:
4690 expect["presented"] = False
4691 seq[name] = klass(value)
4692 expects.append(expect)
4697 def sequences_strategy(draw, seq_klass):
4698 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4700 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4701 for tag, expled in zip(tags, draw(lists(
4708 i for i, is_default in enumerate(draw(lists(
4714 names = list(draw(sets(
4719 seq_expectses = draw(lists(
4720 sequence_strategy(seq_klass=seq_klass),
4724 seqs = [seq for seq, _ in seq_expectses]
4726 for i, (name, seq) in enumerate(zip(names, seqs)):
4729 seq(default=(seq if i in defaulted else None), **inits[i]),
4731 seq_name = draw(text_letters())
4732 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4735 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4738 "expects": expects_inner,
4741 seq_outer[name] = seq_inner
4742 if seq_outer.specs[name].default is None:
4743 expect["presented"] = True
4744 expect_outers.append(expect)
4745 return seq_outer, expect_outers
4748 class SeqMixing(object):
4749 def test_invalid_value_type(self):
4750 with self.assertRaises(InvalidValueType) as err:
4751 self.base_klass(123)
4754 def test_invalid_value_type_set(self):
4755 class Seq(self.base_klass):
4756 schema = (("whatever", Boolean()),)
4758 with self.assertRaises(InvalidValueType) as err:
4759 seq["whatever"] = Integer(123)
4763 def test_optional(self, optional):
4764 obj = self.base_klass(default=self.base_klass(), optional=optional)
4765 self.assertTrue(obj.optional)
4767 @given(data_strategy())
4768 def test_ready(self, d):
4770 str(i): v for i, v in enumerate(d.draw(lists(
4777 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4784 for name in d.draw(permutations(
4785 list(ready.keys()) + list(non_ready.keys()),
4787 schema_input.append((name, Boolean()))
4789 class Seq(self.base_klass):
4790 schema = tuple(schema_input)
4792 for name in ready.keys():
4794 seq[name] = Boolean()
4795 self.assertFalse(seq.ready)
4798 pprint(seq, big_blobs=True, with_decode_path=True)
4799 for name, value in ready.items():
4800 seq[name] = Boolean(value)
4801 self.assertFalse(seq.ready)
4804 pprint(seq, big_blobs=True, with_decode_path=True)
4805 with self.assertRaises(ObjNotReady) as err:
4808 for name, value in non_ready.items():
4809 seq[name] = Boolean(value)
4810 self.assertTrue(seq.ready)
4813 pprint(seq, big_blobs=True, with_decode_path=True)
4815 @given(data_strategy())
4816 def test_call(self, d):
4817 class SeqInherited(self.base_klass):
4819 for klass in (self.base_klass, SeqInherited):
4828 ) = d.draw(seq_values_strategy(seq_klass=klass))
4829 obj_initial = klass(
4835 optional_initial or False,
4846 ) = d.draw(seq_values_strategy(
4848 do_expl=impl_initial is None,
4850 obj = obj_initial(value, impl, expl, default, optional)
4851 value_expected = default if value is None else value
4853 default_initial if value_expected is None
4856 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4857 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4858 self.assertEqual(obj.expl_tag, expl or expl_initial)
4860 {} if obj.default is None else obj.default._value,
4861 getattr(default_initial if default is None else default, "_value", {}),
4863 if obj.default is None:
4864 optional = optional_initial if optional is None else optional
4865 optional = False if optional is None else optional
4868 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4869 self.assertEqual(obj.optional, optional)
4871 @given(data_strategy())
4872 def test_copy(self, d):
4873 class SeqInherited(self.base_klass):
4875 for klass in (self.base_klass, SeqInherited):
4876 values = d.draw(seq_values_strategy(seq_klass=klass))
4877 obj = klass(*values)
4878 obj_copied = obj.copy()
4879 self.assert_copied_basic_fields(obj, obj_copied)
4880 self.assertEqual(obj.specs, obj_copied.specs)
4881 self.assertEqual(obj._value, obj_copied._value)
4883 @given(data_strategy())
4884 def test_stripped(self, d):
4885 value = d.draw(integers())
4886 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4888 class Seq(self.base_klass):
4890 schema = (("whatever", Integer()),)
4892 seq["whatever"] = Integer(value)
4893 with self.assertRaises(NotEnoughData):
4894 seq.decode(seq.encode()[:-1])
4896 @given(data_strategy())
4897 def test_stripped_expl(self, d):
4898 value = d.draw(integers())
4899 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4901 class Seq(self.base_klass):
4903 schema = (("whatever", Integer()),)
4905 seq["whatever"] = Integer(value)
4906 with self.assertRaises(NotEnoughData):
4907 seq.decode(seq.encode()[:-1])
4909 @given(binary(min_size=2))
4910 def test_non_tag_mismatch_raised(self, junk):
4912 _, _, len_encoded = tag_strip(memoryview(junk))
4913 len_decode(len_encoded)
4919 class Seq(self.base_klass):
4921 ("whatever", Integer()),
4923 ("whenever", Integer()),
4926 seq["whatever"] = Integer(123)
4927 seq["junk"] = Any(junk)
4928 seq["whenever"] = Integer(123)
4929 with self.assertRaises(DecodeError):
4930 seq.decode(seq.encode())
4933 integers(min_value=31),
4934 integers(min_value=0),
4937 def test_bad_tag(self, tag, offset, decode_path):
4938 with self.assertRaises(DecodeError) as err:
4939 self.base_klass().decode(
4940 tag_encode(tag)[:-1],
4942 decode_path=decode_path,
4945 self.assertEqual(err.exception.offset, offset)
4946 self.assertEqual(err.exception.decode_path, decode_path)
4949 integers(min_value=128),
4950 integers(min_value=0),
4953 def test_bad_len(self, l, offset, decode_path):
4954 with self.assertRaises(DecodeError) as err:
4955 self.base_klass().decode(
4956 self.base_klass.tag_default + len_encode(l)[:-1],
4958 decode_path=decode_path,
4961 self.assertEqual(err.exception.offset, offset)
4962 self.assertEqual(err.exception.decode_path, decode_path)
4964 def _assert_expects(self, seq, expects):
4965 for expect in expects:
4967 seq.specs[expect["name"]].optional,
4970 if expect["default_value"] is not None:
4972 seq.specs[expect["name"]].default,
4973 expect["default_value"],
4975 if expect["presented"]:
4976 self.assertIn(expect["name"], seq)
4977 self.assertEqual(seq[expect["name"]], expect["value"])
4979 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4980 @given(data_strategy())
4981 def test_symmetric(self, d):
4982 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4983 tail_junk = d.draw(binary(max_size=5))
4984 self.assertTrue(seq.ready)
4985 self.assertFalse(seq.decoded)
4986 self._assert_expects(seq, expects)
4989 pprint(seq, big_blobs=True, with_decode_path=True)
4990 self.assertTrue(seq.ready)
4991 seq_encoded = seq.encode()
4992 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4993 self.assertFalse(seq_decoded.lenindef)
4994 self.assertFalse(seq_decoded.ber_encoded)
4995 self.assertFalse(seq_decoded.bered)
4997 t, _, lv = tag_strip(seq_encoded)
4998 _, _, v = len_decode(lv)
4999 seq_encoded_lenindef = t + LENINDEF + v + EOC
5000 ctx_copied = deepcopy(ctx_dummy)
5001 ctx_copied["bered"] = True
5002 seq_decoded_lenindef, tail_lenindef = seq.decode(
5003 seq_encoded_lenindef + tail_junk,
5006 del ctx_copied["bered"]
5007 self.assertDictEqual(ctx_copied, ctx_dummy)
5008 self.assertTrue(seq_decoded_lenindef.lenindef)
5009 self.assertTrue(seq_decoded_lenindef.bered)
5010 with self.assertRaises(DecodeError):
5011 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5012 with self.assertRaises(DecodeError):
5013 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5014 repr(seq_decoded_lenindef)
5015 list(seq_decoded_lenindef.pps())
5016 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5017 self.assertTrue(seq_decoded_lenindef.ready)
5019 for decoded, decoded_tail, encoded in (
5020 (seq_decoded, tail, seq_encoded),
5021 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5023 self.assertEqual(decoded_tail, tail_junk)
5024 self._assert_expects(decoded, expects)
5025 self.assertEqual(seq, decoded)
5026 self.assertEqual(decoded.encode(), seq_encoded)
5027 self.assertEqual(decoded.tlvlen, len(encoded))
5028 for expect in expects:
5029 if not expect["presented"]:
5030 self.assertNotIn(expect["name"], decoded)
5032 self.assertIn(expect["name"], decoded)
5033 obj = decoded[expect["name"]]
5034 self.assertTrue(obj.decoded)
5035 offset = obj.expl_offset if obj.expled else obj.offset
5036 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5037 self.assertSequenceEqual(
5038 seq_encoded[offset:offset + tlvlen],
5042 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5043 @given(data_strategy())
5044 def test_symmetric_with_seq(self, d):
5045 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5046 self.assertTrue(seq.ready)
5047 seq_encoded = seq.encode()
5048 seq_decoded, tail = seq.decode(seq_encoded)
5049 self.assertEqual(tail, b"")
5050 self.assertTrue(seq.ready)
5051 self.assertEqual(seq, seq_decoded)
5052 self.assertEqual(seq_decoded.encode(), seq_encoded)
5053 for expect_outer in expect_outers:
5054 if not expect_outer["presented"]:
5055 self.assertNotIn(expect_outer["name"], seq_decoded)
5057 self.assertIn(expect_outer["name"], seq_decoded)
5058 obj = seq_decoded[expect_outer["name"]]
5059 self.assertTrue(obj.decoded)
5060 offset = obj.expl_offset if obj.expled else obj.offset
5061 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5062 self.assertSequenceEqual(
5063 seq_encoded[offset:offset + tlvlen],
5066 self._assert_expects(obj, expect_outer["expects"])
5068 @given(data_strategy())
5069 def test_default_disappears(self, d):
5070 _schema = list(d.draw(dictionaries(
5072 sets(integers(), min_size=2, max_size=2),
5076 class Seq(self.base_klass):
5078 (n, Integer(default=d))
5079 for n, (_, d) in _schema
5082 for name, (value, _) in _schema:
5083 seq[name] = Integer(value)
5084 self.assertEqual(len(seq._value), len(_schema))
5085 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5086 self.assertGreater(len(seq.encode()), len(empty_seq))
5087 for name, (_, default) in _schema:
5088 seq[name] = Integer(default)
5089 self.assertEqual(len(seq._value), 0)
5090 self.assertSequenceEqual(seq.encode(), empty_seq)
5092 @given(data_strategy())
5093 def test_encoded_default_not_accepted(self, d):
5094 _schema = list(d.draw(dictionaries(
5099 tags = [tag_encode(tag) for tag in d.draw(sets(
5100 integers(min_value=0),
5101 min_size=len(_schema),
5102 max_size=len(_schema),
5105 class SeqWithoutDefault(self.base_klass):
5107 (n, Integer(impl=t))
5108 for (n, _), t in zip(_schema, tags)
5110 seq_without_default = SeqWithoutDefault()
5111 for name, value in _schema:
5112 seq_without_default[name] = Integer(value)
5113 seq_encoded = seq_without_default.encode()
5115 class SeqWithDefault(self.base_klass):
5117 (n, Integer(default=v, impl=t))
5118 for (n, v), t in zip(_schema, tags)
5120 seq_with_default = SeqWithDefault()
5121 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5122 seq_with_default.decode(seq_encoded)
5123 for ctx in ({"bered": True}, {"allow_default_values": True}):
5124 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5125 self.assertTrue(seq_decoded.ber_encoded)
5126 self.assertTrue(seq_decoded.bered)
5127 for name, value in _schema:
5128 self.assertEqual(seq_decoded[name], seq_with_default[name])
5129 self.assertEqual(seq_decoded[name], value)
5131 @given(data_strategy())
5132 def test_missing_from_spec(self, d):
5133 names = list(d.draw(sets(text_letters(), min_size=2)))
5134 tags = [tag_encode(tag) for tag in d.draw(sets(
5135 integers(min_value=0),
5136 min_size=len(names),
5137 max_size=len(names),
5139 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5141 class SeqFull(self.base_klass):
5142 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5143 seq_full = SeqFull()
5144 for i, name in enumerate(names):
5145 seq_full[name] = Integer(i)
5146 seq_encoded = seq_full.encode()
5147 altered = names_tags[:-2] + names_tags[-1:]
5149 class SeqMissing(self.base_klass):
5150 schema = [(n, Integer(impl=t)) for n, t in altered]
5151 seq_missing = SeqMissing()
5152 with self.assertRaises(TagMismatch):
5153 seq_missing.decode(seq_encoded)
5155 @given(data_strategy())
5156 def test_bered(self, d):
5157 class Seq(self.base_klass):
5158 schema = (("underlying", Boolean()),)
5159 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5160 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5161 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5162 self.assertFalse(decoded.ber_encoded)
5163 self.assertFalse(decoded.lenindef)
5164 self.assertTrue(decoded.bered)
5166 class Seq(self.base_klass):
5167 schema = (("underlying", OctetString()),)
5169 tag_encode(form=TagFormConstructed, num=4) +
5171 OctetString(b"whatever").encode() +
5174 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5175 with self.assertRaises(DecodeError):
5176 Seq().decode(encoded)
5177 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5178 self.assertFalse(decoded.ber_encoded)
5179 self.assertFalse(decoded.lenindef)
5180 self.assertTrue(decoded.bered)
5183 class TestSequence(SeqMixing, CommonMixin, TestCase):
5184 base_klass = Sequence
5190 def test_remaining(self, value, junk):
5191 class Seq(Sequence):
5193 ("whatever", Integer()),
5195 int_encoded = Integer(value).encode()
5197 Sequence.tag_default,
5198 len_encode(len(int_encoded + junk)),
5201 with assertRaisesRegex(self, DecodeError, "remaining"):
5202 Seq().decode(junked)
5204 @given(sets(text_letters(), min_size=2))
5205 def test_obj_unknown(self, names):
5206 missing = names.pop()
5208 class Seq(Sequence):
5209 schema = [(n, Boolean()) for n in names]
5211 with self.assertRaises(ObjUnknown) as err:
5214 with self.assertRaises(ObjUnknown) as err:
5215 seq[missing] = Boolean()
5218 def test_x690_vector(self):
5219 class Seq(Sequence):
5221 ("name", IA5String()),
5224 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5225 self.assertEqual(seq["name"], "Smith")
5226 self.assertEqual(seq["ok"], True)
5229 class TestSet(SeqMixing, CommonMixin, TestCase):
5232 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5233 @given(data_strategy())
5234 def test_sorted(self, d):
5236 tag_encode(tag) for tag in
5237 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5241 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5243 for name, _ in Seq.schema:
5244 seq[name] = OctetString(b"")
5245 seq_encoded = seq.encode()
5246 seq_decoded, _ = seq.decode(seq_encoded)
5247 self.assertSequenceEqual(
5248 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5249 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5252 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5253 @given(data_strategy())
5254 def test_unsorted(self, d):
5256 tag_encode(tag) for tag in
5257 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5259 tags = d.draw(permutations(tags))
5260 assume(tags != sorted(tags))
5261 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5262 seq_encoded = b"".join((
5264 len_encode(len(encoded)),
5269 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5271 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5272 seq.decode(seq_encoded)
5273 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5274 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5275 self.assertTrue(seq_decoded.ber_encoded)
5276 self.assertTrue(seq_decoded.bered)
5277 self.assertSequenceEqual(
5278 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5284 def seqof_values_strategy(draw, schema=None, do_expl=False):
5286 schema = draw(sampled_from((Boolean(), Integer())))
5287 bound_min, bound_max = sorted(draw(sets(
5288 integers(min_value=0, max_value=10),
5292 if isinstance(schema, Boolean):
5293 values_generator = booleans().map(Boolean)
5294 elif isinstance(schema, Integer):
5295 values_generator = integers().map(Integer)
5296 values_generator = lists(
5301 values = draw(one_of(none(), values_generator))
5305 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5307 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5308 default = draw(one_of(none(), values_generator))
5309 optional = draw(one_of(none(), booleans()))
5311 draw(integers(min_value=0)),
5312 draw(integers(min_value=0)),
5313 draw(integers(min_value=0)),
5318 (bound_min, bound_max),
5327 class SeqOfMixing(object):
5328 def test_invalid_value_type(self):
5329 with self.assertRaises(InvalidValueType) as err:
5330 self.base_klass(123)
5333 def test_invalid_values_type(self):
5334 class SeqOf(self.base_klass):
5336 with self.assertRaises(InvalidValueType) as err:
5337 SeqOf([Integer(123), Boolean(False), Integer(234)])
5340 def test_schema_required(self):
5341 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5342 self.base_klass.__mro__[1]()
5344 @given(booleans(), booleans(), binary(), binary())
5345 def test_comparison(self, value1, value2, tag1, tag2):
5346 class SeqOf(self.base_klass):
5348 obj1 = SeqOf([Boolean(value1)])
5349 obj2 = SeqOf([Boolean(value2)])
5350 self.assertEqual(obj1 == obj2, value1 == value2)
5351 self.assertEqual(obj1 != obj2, value1 != value2)
5352 self.assertEqual(obj1 == list(obj2), value1 == value2)
5353 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5354 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5355 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5356 self.assertEqual(obj1 == obj2, tag1 == tag2)
5357 self.assertEqual(obj1 != obj2, tag1 != tag2)
5359 @given(lists(booleans()))
5360 def test_iter(self, values):
5361 class SeqOf(self.base_klass):
5363 obj = SeqOf([Boolean(value) for value in values])
5364 self.assertEqual(len(obj), len(values))
5365 for i, value in enumerate(obj):
5366 self.assertEqual(value, values[i])
5368 @given(data_strategy())
5369 def test_ready(self, d):
5370 ready = [Integer(v) for v in d.draw(lists(
5377 range(d.draw(integers(min_value=1, max_value=5)))
5380 class SeqOf(self.base_klass):
5382 values = d.draw(permutations(ready + non_ready))
5384 for value in values:
5386 self.assertFalse(seqof.ready)
5389 pprint(seqof, big_blobs=True, with_decode_path=True)
5390 with self.assertRaises(ObjNotReady) as err:
5393 for i, value in enumerate(values):
5394 self.assertEqual(seqof[i], value)
5395 if not seqof[i].ready:
5396 seqof[i] = Integer(i)
5397 self.assertTrue(seqof.ready)
5400 pprint(seqof, big_blobs=True, with_decode_path=True)
5402 def test_spec_mismatch(self):
5403 class SeqOf(self.base_klass):
5406 seqof.append(Integer(123))
5407 with self.assertRaises(ValueError):
5408 seqof.append(Boolean(False))
5409 with self.assertRaises(ValueError):
5410 seqof[0] = Boolean(False)
5412 @given(data_strategy())
5413 def test_bounds_satisfied(self, d):
5414 class SeqOf(self.base_klass):
5416 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5417 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5418 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5419 SeqOf(value=value, bounds=(bound_min, bound_max))
5421 @given(data_strategy())
5422 def test_bounds_unsatisfied(self, d):
5423 class SeqOf(self.base_klass):
5425 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5426 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5427 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5428 with self.assertRaises(BoundsError) as err:
5429 SeqOf(value=value, bounds=(bound_min, bound_max))
5431 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5432 SeqOf(bounds=(bound_min, bound_max)).decode(
5433 SeqOf(value).encode()
5436 value = [Boolean(True)] * d.draw(integers(
5437 min_value=bound_max + 1,
5438 max_value=bound_max + 10,
5440 with self.assertRaises(BoundsError) as err:
5441 SeqOf(value=value, bounds=(bound_min, bound_max))
5443 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5444 SeqOf(bounds=(bound_min, bound_max)).decode(
5445 SeqOf(value).encode()
5449 @given(integers(min_value=1, max_value=10))
5450 def test_out_of_bounds(self, bound_max):
5451 class SeqOf(self.base_klass):
5453 bounds = (0, bound_max)
5455 for _ in range(bound_max):
5456 seqof.append(Integer(123))
5457 with self.assertRaises(BoundsError):
5458 seqof.append(Integer(123))
5460 @given(data_strategy())
5461 def test_call(self, d):
5471 ) = d.draw(seqof_values_strategy())
5473 class SeqOf(self.base_klass):
5474 schema = schema_initial
5475 obj_initial = SeqOf(
5476 value=value_initial,
5477 bounds=bounds_initial,
5480 default=default_initial,
5481 optional=optional_initial or False,
5482 _decoded=_decoded_initial,
5493 ) = d.draw(seqof_values_strategy(
5494 schema=schema_initial,
5495 do_expl=impl_initial is None,
5497 if (default is None) and (obj_initial.default is not None):
5500 (bounds is None) and
5501 (value is not None) and
5502 (bounds_initial is not None) and
5503 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5507 (bounds is None) and
5508 (default is not None) and
5509 (bounds_initial is not None) and
5510 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5522 value_expected = default if value is None else value
5524 default_initial if value_expected is None
5527 value_expected = () if value_expected is None else value_expected
5528 self.assertEqual(obj, value_expected)
5529 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5530 self.assertEqual(obj.expl_tag, expl or expl_initial)
5533 default_initial if default is None else default,
5535 if obj.default is None:
5536 optional = optional_initial if optional is None else optional
5537 optional = False if optional is None else optional
5540 self.assertEqual(obj.optional, optional)
5542 (obj._bound_min, obj._bound_max),
5543 bounds or bounds_initial or (0, float("+inf")),
5546 @given(seqof_values_strategy())
5547 def test_copy(self, values):
5548 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5550 class SeqOf(self.base_klass):
5558 optional=optional or False,
5561 obj_copied = obj.copy()
5562 self.assert_copied_basic_fields(obj, obj_copied)
5563 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5564 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5565 self.assertEqual(obj._value, obj_copied._value)
5569 integers(min_value=1).map(tag_encode),
5571 def test_stripped(self, values, tag_impl):
5572 class SeqOf(self.base_klass):
5573 schema = OctetString()
5574 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5575 with self.assertRaises(NotEnoughData):
5576 obj.decode(obj.encode()[:-1])
5580 integers(min_value=1).map(tag_ctxc),
5582 def test_stripped_expl(self, values, tag_expl):
5583 class SeqOf(self.base_klass):
5584 schema = OctetString()
5585 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5586 with self.assertRaises(NotEnoughData):
5587 obj.decode(obj.encode()[:-1])
5590 integers(min_value=31),
5591 integers(min_value=0),
5594 def test_bad_tag(self, tag, offset, decode_path):
5595 with self.assertRaises(DecodeError) as err:
5596 self.base_klass().decode(
5597 tag_encode(tag)[:-1],
5599 decode_path=decode_path,
5602 self.assertEqual(err.exception.offset, offset)
5603 self.assertEqual(err.exception.decode_path, decode_path)
5606 integers(min_value=128),
5607 integers(min_value=0),
5610 def test_bad_len(self, l, offset, decode_path):
5611 with self.assertRaises(DecodeError) as err:
5612 self.base_klass().decode(
5613 self.base_klass.tag_default + len_encode(l)[:-1],
5615 decode_path=decode_path,
5618 self.assertEqual(err.exception.offset, offset)
5619 self.assertEqual(err.exception.decode_path, decode_path)
5621 @given(binary(min_size=1))
5622 def test_tag_mismatch(self, impl):
5623 assume(impl != self.base_klass.tag_default)
5624 with self.assertRaises(TagMismatch):
5625 self.base_klass(impl=impl).decode(self.base_klass().encode())
5627 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5629 seqof_values_strategy(schema=Integer()),
5630 lists(integers().map(Integer)),
5631 integers(min_value=1).map(tag_ctxc),
5632 integers(min_value=0),
5635 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5636 _, _, _, _, _, default, optional, _decoded = values
5638 class SeqOf(self.base_klass):
5648 pprint(obj, big_blobs=True, with_decode_path=True)
5649 self.assertFalse(obj.expled)
5650 obj_encoded = obj.encode()
5651 obj_expled = obj(value, expl=tag_expl)
5652 self.assertTrue(obj_expled.expled)
5654 list(obj_expled.pps())
5655 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5656 obj_expled_encoded = obj_expled.encode()
5657 ctx_copied = deepcopy(ctx_dummy)
5658 obj_decoded, tail = obj_expled.decode(
5659 obj_expled_encoded + tail_junk,
5663 self.assertDictEqual(ctx_copied, ctx_dummy)
5665 list(obj_decoded.pps())
5666 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5667 self.assertEqual(tail, tail_junk)
5668 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5669 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5670 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5671 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5673 obj_decoded.expl_llen,
5674 len(len_encode(len(obj_encoded))),
5676 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5677 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5680 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5682 self.assertEqual(obj_decoded.expl_offset, offset)
5683 for obj_inner in obj_decoded:
5684 self.assertIn(obj_inner, obj_decoded)
5685 self.assertSequenceEqual(
5688 obj_inner.offset - offset:
5689 obj_inner.offset + obj_inner.tlvlen - offset
5693 t, _, lv = tag_strip(obj_encoded)
5694 _, _, v = len_decode(lv)
5695 obj_encoded_lenindef = t + LENINDEF + v + EOC
5696 obj_decoded_lenindef, tail_lenindef = obj.decode(
5697 obj_encoded_lenindef + tail_junk,
5698 ctx={"bered": True},
5700 self.assertTrue(obj_decoded_lenindef.lenindef)
5701 self.assertTrue(obj_decoded_lenindef.bered)
5702 repr(obj_decoded_lenindef)
5703 list(obj_decoded_lenindef.pps())
5704 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5705 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5706 with self.assertRaises(DecodeError):
5707 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5708 with self.assertRaises(DecodeError):
5709 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5711 @given(data_strategy())
5712 def test_bered(self, d):
5713 class SeqOf(self.base_klass):
5715 encoded = Boolean(False).encode()
5716 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5717 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5718 with self.assertRaises(DecodeError):
5719 SeqOf().decode(encoded)
5720 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5721 self.assertFalse(decoded.ber_encoded)
5722 self.assertFalse(decoded.lenindef)
5723 self.assertTrue(decoded.bered)
5725 class SeqOf(self.base_klass):
5726 schema = OctetString()
5727 encoded = OctetString(b"whatever").encode()
5729 tag_encode(form=TagFormConstructed, num=4) +
5731 OctetString(b"whatever").encode() +
5734 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5735 with self.assertRaises(DecodeError):
5736 SeqOf().decode(encoded)
5737 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5738 self.assertFalse(decoded.ber_encoded)
5739 self.assertFalse(decoded.lenindef)
5740 self.assertTrue(decoded.bered)
5743 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5744 class SeqOf(SequenceOf):
5748 def _test_symmetric_compare_objs(self, obj1, obj2):
5749 self.assertEqual(obj1, obj2)
5750 self.assertSequenceEqual(list(obj1), list(obj2))
5753 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5758 def _test_symmetric_compare_objs(self, obj1, obj2):
5759 self.assertSetEqual(
5760 set(int(v) for v in obj1),
5761 set(int(v) for v in obj2),
5764 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5765 @given(data_strategy())
5766 def test_sorted(self, d):
5767 values = [OctetString(v) for v in d.draw(lists(binary()))]
5770 schema = OctetString()
5772 seq_encoded = seq.encode()
5773 seq_decoded, _ = seq.decode(seq_encoded)
5774 self.assertSequenceEqual(
5775 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5776 b"".join(sorted([v.encode() for v in values])),
5779 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5780 @given(data_strategy())
5781 def test_unsorted(self, d):
5782 values = [OctetString(v).encode() for v in d.draw(sets(
5783 binary(min_size=1, max_size=5),
5787 values = d.draw(permutations(values))
5788 assume(values != sorted(values))
5789 encoded = b"".join(values)
5790 seq_encoded = b"".join((
5792 len_encode(len(encoded)),
5797 schema = OctetString()
5799 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5800 seq.decode(seq_encoded)
5802 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5803 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5804 self.assertTrue(seq_decoded.ber_encoded)
5805 self.assertTrue(seq_decoded.bered)
5806 self.assertSequenceEqual(
5807 [obj.encode() for obj in seq_decoded],
5812 class TestGoMarshalVectors(TestCase):
5814 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5815 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5816 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5817 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5818 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5820 class Seq(Sequence):
5822 ("erste", Integer()),
5823 ("zweite", Integer(optional=True))
5826 seq["erste"] = Integer(64)
5827 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5828 seq["erste"] = Integer(0x123456)
5829 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5830 seq["erste"] = Integer(64)
5831 seq["zweite"] = Integer(65)
5832 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5834 class NestedSeq(Sequence):
5838 seq["erste"] = Integer(127)
5839 seq["zweite"] = None
5840 nested = NestedSeq()
5841 nested["nest"] = seq
5842 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5844 self.assertSequenceEqual(
5845 OctetString(b"\x01\x02\x03").encode(),
5846 hexdec("0403010203"),
5849 class Seq(Sequence):
5851 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5854 seq["erste"] = Integer(64)
5855 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5857 class Seq(Sequence):
5859 ("erste", Integer(expl=tag_ctxc(5))),
5862 seq["erste"] = Integer(64)
5863 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5865 class Seq(Sequence):
5868 impl=tag_encode(0, klass=TagClassContext),
5873 seq["erste"] = Null()
5874 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5876 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5878 self.assertSequenceEqual(
5879 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5880 hexdec("170d3730303130313030303030305a"),
5882 self.assertSequenceEqual(
5883 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5884 hexdec("170d3039313131353232353631365a"),
5886 self.assertSequenceEqual(
5887 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5888 hexdec("180f32313030303430353132303130315a"),
5891 class Seq(Sequence):
5893 ("erste", GeneralizedTime()),
5896 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5897 self.assertSequenceEqual(
5899 hexdec("3011180f32303039313131353232353631365a"),
5902 self.assertSequenceEqual(
5903 BitString((1, b"\x80")).encode(),
5906 self.assertSequenceEqual(
5907 BitString((12, b"\x81\xF0")).encode(),
5908 hexdec("03030481f0"),
5911 self.assertSequenceEqual(
5912 ObjectIdentifier("1.2.3.4").encode(),
5913 hexdec("06032a0304"),
5915 self.assertSequenceEqual(
5916 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5917 hexdec("06092a864888932d010105"),
5919 self.assertSequenceEqual(
5920 ObjectIdentifier("2.100.3").encode(),
5921 hexdec("0603813403"),
5924 self.assertSequenceEqual(
5925 PrintableString("test").encode(),
5926 hexdec("130474657374"),
5928 self.assertSequenceEqual(
5929 PrintableString("x" * 127).encode(),
5930 hexdec("137F" + "78" * 127),
5932 self.assertSequenceEqual(
5933 PrintableString("x" * 128).encode(),
5934 hexdec("138180" + "78" * 128),
5936 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5938 class Seq(Sequence):
5940 ("erste", IA5String()),
5943 seq["erste"] = IA5String("test")
5944 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5946 class Seq(Sequence):
5948 ("erste", PrintableString()),
5951 seq["erste"] = PrintableString("test")
5952 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5953 # Asterisk is actually not allowable
5954 PrintableString._allowable_chars |= set(b"*")
5955 seq["erste"] = PrintableString("test*")
5956 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5957 PrintableString._allowable_chars -= set(b"*")
5959 class Seq(Sequence):
5961 ("erste", Any(optional=True)),
5962 ("zweite", Integer()),
5965 seq["zweite"] = Integer(64)
5966 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5971 seq.append(Integer(10))
5972 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5974 class _SeqOf(SequenceOf):
5975 schema = PrintableString()
5977 class SeqOf(SequenceOf):
5980 _seqof.append(PrintableString("1"))
5982 seqof.append(_seqof)
5983 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5985 class Seq(Sequence):
5987 ("erste", Integer(default=1)),
5990 seq["erste"] = Integer(0)
5991 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5992 seq["erste"] = Integer(1)
5993 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5994 seq["erste"] = Integer(2)
5995 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5998 class TestPP(TestCase):
5999 @given(data_strategy())
6000 def test_oid_printing(self, d):
6002 str(ObjectIdentifier(k)): v * 2
6003 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6005 chosen = d.draw(sampled_from(sorted(oids)))
6006 chosen_id = oids[chosen]
6007 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6008 self.assertNotIn(chosen_id, pp_console_row(pp))
6009 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
6012 class TestAutoAddSlots(TestCase):
6014 class Inher(Integer):
6017 with self.assertRaises(AttributeError):
6019 inher.unexistent = "whatever"
6022 class TestOIDDefines(TestCase):
6023 @given(data_strategy())
6024 def runTest(self, d):
6025 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6026 value_name_chosen = d.draw(sampled_from(value_names))
6028 ObjectIdentifier(oid)
6029 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6031 oid_chosen = d.draw(sampled_from(oids))
6032 values = d.draw(lists(
6034 min_size=len(value_names),
6035 max_size=len(value_names),
6038 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6039 oid: Integer() for oid in oids[:-1]
6042 for i, value_name in enumerate(value_names):
6043 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6045 class Seq(Sequence):
6048 for value_name, value in zip(value_names, values):
6049 seq[value_name] = Any(Integer(value).encode())
6050 seq["type"] = oid_chosen
6051 seq, _ = Seq().decode(seq.encode())
6052 for value_name in value_names:
6053 if value_name == value_name_chosen:
6055 self.assertIsNone(seq[value_name].defined)
6056 if value_name_chosen in oids[:-1]:
6057 self.assertIsNotNone(seq[value_name_chosen].defined)
6058 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6059 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6062 pprint(seq, big_blobs=True, with_decode_path=True)
6065 class TestDefinesByPath(TestCase):
6066 def test_generated(self):
6067 class Seq(Sequence):
6069 ("type", ObjectIdentifier()),
6070 ("value", OctetString(expl=tag_ctxc(123))),
6073 class SeqInner(Sequence):
6075 ("typeInner", ObjectIdentifier()),
6076 ("valueInner", Any()),
6079 class PairValue(SetOf):
6082 class Pair(Sequence):
6084 ("type", ObjectIdentifier()),
6085 ("value", PairValue()),
6088 class Pairs(SequenceOf):
6095 type_octet_stringed,
6097 ObjectIdentifier(oid)
6098 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6100 seq_integered = Seq()
6101 seq_integered["type"] = type_integered
6102 seq_integered["value"] = OctetString(Integer(123).encode())
6103 seq_integered_raw = seq_integered.encode()
6107 (type_octet_stringed, OctetString(b"whatever")),
6108 (type_integered, Integer(123)),
6109 (type_octet_stringed, OctetString(b"whenever")),
6110 (type_integered, Integer(234)),
6112 for t, v in pairs_input:
6115 pair["value"] = PairValue((Any(v),))
6117 seq_inner = SeqInner()
6118 seq_inner["typeInner"] = type_innered
6119 seq_inner["valueInner"] = Any(pairs)
6120 seq_sequenced = Seq()
6121 seq_sequenced["type"] = type_sequenced
6122 seq_sequenced["value"] = OctetString(seq_inner.encode())
6123 seq_sequenced_raw = seq_sequenced.encode()
6125 list(seq_sequenced.pps())
6126 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6128 defines_by_path = []
6129 ctx_copied = deepcopy(ctx_dummy)
6130 seq_integered, _ = Seq().decode(
6134 self.assertDictEqual(ctx_copied, ctx_dummy)
6135 self.assertIsNone(seq_integered["value"].defined)
6136 defines_by_path.append(
6137 (("type",), ((("value",), {
6138 type_integered: Integer(),
6139 type_sequenced: SeqInner(),
6142 ctx_copied["defines_by_path"] = defines_by_path
6143 seq_integered, _ = Seq().decode(
6147 del ctx_copied["defines_by_path"]
6148 self.assertDictEqual(ctx_copied, ctx_dummy)
6149 self.assertIsNotNone(seq_integered["value"].defined)
6150 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6151 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6152 self.assertTrue(seq_integered_raw[
6153 seq_integered["value"].defined[1].offset:
6154 ].startswith(Integer(123).encode()))
6156 list(seq_integered.pps())
6157 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6159 ctx_copied["defines_by_path"] = defines_by_path
6160 seq_sequenced, _ = Seq().decode(
6164 del ctx_copied["defines_by_path"]
6165 self.assertDictEqual(ctx_copied, ctx_dummy)
6166 self.assertIsNotNone(seq_sequenced["value"].defined)
6167 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6168 seq_inner = seq_sequenced["value"].defined[1]
6169 self.assertIsNone(seq_inner["valueInner"].defined)
6171 list(seq_sequenced.pps())
6172 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6174 defines_by_path.append((
6175 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6176 ((("valueInner",), {type_innered: Pairs()}),),
6178 ctx_copied["defines_by_path"] = defines_by_path
6179 seq_sequenced, _ = Seq().decode(
6183 del ctx_copied["defines_by_path"]
6184 self.assertDictEqual(ctx_copied, ctx_dummy)
6185 self.assertIsNotNone(seq_sequenced["value"].defined)
6186 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6187 seq_inner = seq_sequenced["value"].defined[1]
6188 self.assertIsNotNone(seq_inner["valueInner"].defined)
6189 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6190 pairs = seq_inner["valueInner"].defined[1]
6192 self.assertIsNone(pair["value"][0].defined)
6194 list(seq_sequenced.pps())
6195 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6197 defines_by_path.append((
6200 DecodePathDefBy(type_sequenced),
6202 DecodePathDefBy(type_innered),
6207 type_integered: Integer(),
6208 type_octet_stringed: OctetString(),
6211 ctx_copied["defines_by_path"] = defines_by_path
6212 seq_sequenced, _ = Seq().decode(
6216 del ctx_copied["defines_by_path"]
6217 self.assertDictEqual(ctx_copied, ctx_dummy)
6218 self.assertIsNotNone(seq_sequenced["value"].defined)
6219 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6220 seq_inner = seq_sequenced["value"].defined[1]
6221 self.assertIsNotNone(seq_inner["valueInner"].defined)
6222 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6223 pairs_got = seq_inner["valueInner"].defined[1]
6224 for pair_input, pair_got in zip(pairs_input, pairs_got):
6225 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6226 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6228 list(seq_sequenced.pps())
6229 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6231 @given(oid_strategy(), integers())
6232 def test_simple(self, oid, tgt):
6233 class Inner(Sequence):
6235 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6236 ObjectIdentifier(oid): Integer(),
6240 class Outer(Sequence):
6243 ("tgt", OctetString()),
6247 inner["oid"] = ObjectIdentifier(oid)
6249 outer["inner"] = inner
6250 outer["tgt"] = OctetString(Integer(tgt).encode())
6251 decoded, _ = Outer().decode(outer.encode())
6252 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6255 class TestAbsDecodePath(TestCase):
6257 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6258 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6260 def test_concat(self, decode_path, rel_path):
6261 self.assertSequenceEqual(
6262 abs_decode_path(decode_path, rel_path),
6263 decode_path + rel_path,
6267 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6268 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6270 def test_abs(self, decode_path, rel_path):
6271 self.assertSequenceEqual(
6272 abs_decode_path(decode_path, ("/",) + rel_path),
6277 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6278 integers(min_value=1, max_value=3),
6279 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6281 def test_dots(self, decode_path, number_of_dots, rel_path):
6282 self.assertSequenceEqual(
6283 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6284 decode_path[:-number_of_dots] + rel_path,
6288 class TestStrictDefaultExistence(TestCase):
6289 @given(data_strategy())
6290 def runTest(self, d):
6291 count = d.draw(integers(min_value=1, max_value=10))
6292 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6294 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6295 for i in range(count)
6297 for klass in (Sequence, Set):
6301 for i in range(count):
6302 seq["int%d" % i] = Integer(123)
6304 chosen_choice = "int%d" % chosen
6305 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6306 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6308 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6309 self.assertTrue(decoded.ber_encoded)
6310 self.assertTrue(decoded.bered)
6311 decoded, _ = seq.decode(raw, ctx={"bered": True})
6312 self.assertTrue(decoded.ber_encoded)
6313 self.assertTrue(decoded.bered)
6316 class TestX690PrefixedType(TestCase):
6318 self.assertSequenceEqual(
6319 VisibleString("Jones").encode(),
6320 hexdec("1A054A6F6E6573"),
6322 self.assertSequenceEqual(
6325 impl=tag_encode(3, klass=TagClassApplication),
6327 hexdec("43054A6F6E6573"),
6329 self.assertSequenceEqual(
6333 impl=tag_encode(3, klass=TagClassApplication),
6337 hexdec("A20743054A6F6E6573"),
6339 self.assertSequenceEqual(
6343 impl=tag_encode(3, klass=TagClassApplication),
6345 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6347 hexdec("670743054A6F6E6573"),
6349 self.assertSequenceEqual(
6350 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6351 hexdec("82054A6F6E6573"),
6355 class TestExplOOB(TestCase):
6357 expl = tag_ctxc(123)
6358 raw = Integer(123).encode() + Integer(234).encode()
6359 raw = b"".join((expl, len_encode(len(raw)), raw))
6360 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6361 Integer(expl=expl).decode(raw)
6362 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})