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)
2413 self.assertFalse(obj.ber_encoded)
2416 pprint(obj, big_blobs=True, with_decode_path=True)
2419 @given(oid_strategy(), oid_strategy(), binary(), binary())
2420 def test_comparison(self, value1, value2, tag1, tag2):
2421 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2422 obj1 = klass(value1)
2423 obj2 = klass(value2)
2424 self.assertEqual(obj1 == obj2, value1 == value2)
2425 self.assertEqual(obj1 != obj2, value1 != value2)
2426 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2427 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2428 obj1 = klass(value1, impl=tag1)
2429 obj2 = klass(value1, impl=tag2)
2430 self.assertEqual(obj1 == obj2, tag1 == tag2)
2431 self.assertEqual(obj1 != obj2, tag1 != tag2)
2433 @given(lists(oid_strategy()))
2434 def test_sorted_works(self, values):
2435 self.assertSequenceEqual(
2436 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2440 @given(data_strategy())
2441 def test_call(self, d):
2442 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2450 ) = d.draw(oid_values_strategy())
2451 obj_initial = klass(
2452 value=value_initial,
2455 default=default_initial,
2456 optional=optional_initial or False,
2457 _decoded=_decoded_initial,
2466 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2475 value_expected = default if value is None else value
2477 default_initial if value_expected is None
2480 self.assertEqual(obj, value_expected)
2481 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2482 self.assertEqual(obj.expl_tag, expl or expl_initial)
2485 default_initial if default is None else default,
2487 if obj.default is None:
2488 optional = optional_initial if optional is None else optional
2489 optional = False if optional is None else optional
2492 self.assertEqual(obj.optional, optional)
2494 @given(oid_values_strategy())
2495 def test_copy(self, values):
2496 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2513 obj_copied = obj.copy()
2514 self.assert_copied_basic_fields(obj, obj_copied)
2515 self.assertEqual(obj._value, obj_copied._value)
2517 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2520 integers(min_value=1).map(tag_encode),
2522 def test_stripped(self, value, tag_impl):
2523 obj = ObjectIdentifier(value, impl=tag_impl)
2524 with self.assertRaises(NotEnoughData):
2525 obj.decode(obj.encode()[:-1])
2529 integers(min_value=1).map(tag_ctxc),
2531 def test_stripped_expl(self, value, tag_expl):
2532 obj = ObjectIdentifier(value, expl=tag_expl)
2533 with self.assertRaises(NotEnoughData):
2534 obj.decode(obj.encode()[:-1])
2537 integers(min_value=31),
2538 integers(min_value=0),
2541 def test_bad_tag(self, tag, offset, decode_path):
2542 with self.assertRaises(DecodeError) as err:
2543 ObjectIdentifier().decode(
2544 tag_encode(tag)[:-1],
2546 decode_path=decode_path,
2549 self.assertEqual(err.exception.offset, offset)
2550 self.assertEqual(err.exception.decode_path, decode_path)
2553 integers(min_value=128),
2554 integers(min_value=0),
2557 def test_bad_len(self, l, offset, decode_path):
2558 with self.assertRaises(DecodeError) as err:
2559 ObjectIdentifier().decode(
2560 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2562 decode_path=decode_path,
2565 self.assertEqual(err.exception.offset, offset)
2566 self.assertEqual(err.exception.decode_path, decode_path)
2568 def test_zero_oid(self):
2569 with self.assertRaises(NotEnoughData):
2570 ObjectIdentifier().decode(
2571 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2574 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2575 @given(oid_strategy())
2576 def test_unfinished_oid(self, value):
2577 assume(list(value)[-1] > 255)
2578 obj_encoded = ObjectIdentifier(value).encode()
2579 obj, _ = ObjectIdentifier().decode(obj_encoded)
2580 data = obj_encoded[obj.tlen + obj.llen:-1]
2582 ObjectIdentifier.tag_default,
2583 len_encode(len(data)),
2586 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2589 @given(integers(min_value=0))
2590 def test_invalid_short(self, value):
2591 with self.assertRaises(InvalidOID):
2592 ObjectIdentifier((value,))
2593 with self.assertRaises(InvalidOID):
2594 ObjectIdentifier("%d" % value)
2596 @given(integers(min_value=3), integers(min_value=0))
2597 def test_invalid_first_arc(self, first_arc, second_arc):
2598 with self.assertRaises(InvalidOID):
2599 ObjectIdentifier((first_arc, second_arc))
2600 with self.assertRaises(InvalidOID):
2601 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2603 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2604 def test_invalid_second_arc(self, first_arc, second_arc):
2605 with self.assertRaises(InvalidOID):
2606 ObjectIdentifier((first_arc, second_arc))
2607 with self.assertRaises(InvalidOID):
2608 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2610 @given(text(alphabet=ascii_letters + ".", min_size=1))
2611 def test_junk(self, oid):
2612 with self.assertRaises(InvalidOID):
2613 ObjectIdentifier(oid)
2615 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2616 @given(oid_strategy())
2617 def test_validness(self, oid):
2618 obj = ObjectIdentifier(oid)
2619 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2622 pprint(obj, big_blobs=True, with_decode_path=True)
2624 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2626 oid_values_strategy(),
2628 integers(min_value=1).map(tag_ctxc),
2629 integers(min_value=0),
2632 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2633 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2634 _, _, _, default, optional, _decoded = values
2643 pprint(obj, big_blobs=True, with_decode_path=True)
2644 self.assertFalse(obj.expled)
2645 obj_encoded = obj.encode()
2646 obj_expled = obj(value, expl=tag_expl)
2647 self.assertTrue(obj_expled.expled)
2649 list(obj_expled.pps())
2650 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2651 obj_expled_encoded = obj_expled.encode()
2652 ctx_copied = deepcopy(ctx_dummy)
2653 obj_decoded, tail = obj_expled.decode(
2654 obj_expled_encoded + tail_junk,
2658 self.assertDictEqual(ctx_copied, ctx_dummy)
2660 list(obj_decoded.pps())
2661 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2662 self.assertEqual(tail, tail_junk)
2663 self.assertEqual(obj_decoded, obj_expled)
2664 self.assertNotEqual(obj_decoded, obj)
2665 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2666 self.assertEqual(tuple(obj_decoded), tuple(obj))
2667 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2668 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2669 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2671 obj_decoded.expl_llen,
2672 len(len_encode(len(obj_encoded))),
2674 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2675 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2678 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2680 self.assertEqual(obj_decoded.expl_offset, offset)
2683 oid_strategy().map(ObjectIdentifier),
2684 oid_strategy().map(ObjectIdentifier),
2686 def test_add(self, oid1, oid2):
2687 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2688 for oid_to_add in (oid2, tuple(oid2)):
2689 self.assertEqual(oid1 + oid_to_add, oid_expect)
2690 with self.assertRaises(InvalidValueType):
2693 def test_go_vectors_valid(self):
2694 for data, expect in (
2696 (b"\x55\x02", (2, 5, 2)),
2697 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2698 (b"\x81\x34\x03", (2, 100, 3)),
2701 ObjectIdentifier().decode(b"".join((
2702 ObjectIdentifier.tag_default,
2703 len_encode(len(data)),
2709 def test_go_vectors_invalid(self):
2710 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2711 with self.assertRaises(DecodeError):
2712 ObjectIdentifier().decode(b"".join((
2713 Integer.tag_default,
2714 len_encode(len(data)),
2718 def test_x690_vector(self):
2720 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2721 ObjectIdentifier((2, 999, 3)),
2724 @given(data_strategy())
2725 def test_nonnormalized_first_arc(self, d):
2727 ObjectIdentifier.tag_default +
2730 ObjectIdentifier((1, 0)).encode()[-1:]
2732 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2733 self.assertTrue(obj.ber_encoded)
2734 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2735 ObjectIdentifier().decode(tampered)
2737 @given(data_strategy())
2738 def test_nonnormalized_arcs(self, d):
2739 arcs = d.draw(lists(
2740 integers(min_value=0, max_value=100),
2744 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2745 _, tlen, lv = tag_strip(dered)
2746 _, llen, v = len_decode(lv)
2747 v_no_first_arc = v[1:]
2748 idx_for_tamper = d.draw(integers(
2750 max_value=len(v_no_first_arc) - 1,
2752 tampered = list(bytearray(v_no_first_arc))
2753 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2754 tampered.insert(idx_for_tamper, 0x80)
2755 tampered = bytes(bytearray(tampered))
2757 ObjectIdentifier.tag_default +
2758 len_encode(len(tampered)) +
2761 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2762 self.assertTrue(obj.ber_encoded)
2763 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2764 ObjectIdentifier().decode(tampered)
2768 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2770 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2771 values = list(draw(sets(
2773 min_size=len(schema),
2774 max_size=len(schema),
2776 schema = list(zip(schema, values))
2777 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2781 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2783 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2784 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2785 optional = draw(one_of(none(), booleans()))
2787 draw(integers(min_value=0)),
2788 draw(integers(min_value=0)),
2789 draw(integers(min_value=0)),
2791 return (schema, value, impl, expl, default, optional, _decoded)
2794 class TestEnumerated(CommonMixin, TestCase):
2795 class EWhatever(Enumerated):
2796 schema = (("whatever", 0),)
2798 base_klass = EWhatever
2800 def test_schema_required(self):
2801 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2804 def test_invalid_value_type(self):
2805 with self.assertRaises(InvalidValueType) as err:
2806 self.base_klass((1, 2))
2809 @given(sets(text_letters(), min_size=2))
2810 def test_unknown_name(self, schema_input):
2811 missing = schema_input.pop()
2813 class E(Enumerated):
2814 schema = [(n, 123) for n in schema_input]
2815 with self.assertRaises(ObjUnknown) as err:
2820 sets(text_letters(), min_size=2),
2821 sets(integers(), min_size=2),
2823 def test_unknown_value(self, schema_input, values_input):
2825 missing_value = values_input.pop()
2826 _input = list(zip(schema_input, values_input))
2828 class E(Enumerated):
2830 with self.assertRaises(DecodeError) as err:
2835 def test_optional(self, optional):
2836 obj = self.base_klass(default="whatever", optional=optional)
2837 self.assertTrue(obj.optional)
2839 def test_ready(self):
2840 obj = self.base_klass()
2841 self.assertFalse(obj.ready)
2844 pprint(obj, big_blobs=True, with_decode_path=True)
2845 with self.assertRaises(ObjNotReady) as err:
2848 obj = self.base_klass("whatever")
2849 self.assertTrue(obj.ready)
2852 pprint(obj, big_blobs=True, with_decode_path=True)
2854 @given(integers(), integers(), binary(), binary())
2855 def test_comparison(self, value1, value2, tag1, tag2):
2856 class E(Enumerated):
2858 ("whatever0", value1),
2859 ("whatever1", value2),
2862 class EInherited(E):
2864 for klass in (E, EInherited):
2865 obj1 = klass(value1)
2866 obj2 = klass(value2)
2867 self.assertEqual(obj1 == obj2, value1 == value2)
2868 self.assertEqual(obj1 != obj2, value1 != value2)
2869 self.assertEqual(obj1 == int(obj2), value1 == value2)
2870 obj1 = klass(value1, impl=tag1)
2871 obj2 = klass(value1, impl=tag2)
2872 self.assertEqual(obj1 == obj2, tag1 == tag2)
2873 self.assertEqual(obj1 != obj2, tag1 != tag2)
2875 @given(data_strategy())
2876 def test_call(self, d):
2885 ) = d.draw(enumerated_values_strategy())
2887 class E(Enumerated):
2888 schema = schema_initial
2890 value=value_initial,
2893 default=default_initial,
2894 optional=optional_initial or False,
2895 _decoded=_decoded_initial,
2905 ) = d.draw(enumerated_values_strategy(
2906 schema=schema_initial,
2907 do_expl=impl_initial is None,
2917 value_expected = default if value is None else value
2919 default_initial if value_expected is None
2924 dict(schema_initial).get(value_expected, value_expected),
2926 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2927 self.assertEqual(obj.expl_tag, expl or expl_initial)
2930 default_initial if default is None else default,
2932 if obj.default is None:
2933 optional = optional_initial if optional is None else optional
2934 optional = False if optional is None else optional
2937 self.assertEqual(obj.optional, optional)
2938 self.assertEqual(obj.specs, dict(schema_initial))
2940 @given(enumerated_values_strategy())
2941 def test_copy(self, values):
2942 schema_input, value, impl, expl, default, optional, _decoded = values
2944 class E(Enumerated):
2945 schema = schema_input
2954 obj_copied = obj.copy()
2955 self.assert_copied_basic_fields(obj, obj_copied)
2956 self.assertEqual(obj.specs, obj_copied.specs)
2958 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2959 @given(data_strategy())
2960 def test_symmetric(self, d):
2961 schema_input, _, _, _, default, optional, _decoded = d.draw(
2962 enumerated_values_strategy(),
2964 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2965 offset = d.draw(integers(min_value=0))
2966 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2967 tail_junk = d.draw(binary(max_size=5))
2969 class E(Enumerated):
2970 schema = schema_input
2979 pprint(obj, big_blobs=True, with_decode_path=True)
2980 self.assertFalse(obj.expled)
2981 obj_encoded = obj.encode()
2982 obj_expled = obj(value, expl=tag_expl)
2983 self.assertTrue(obj_expled.expled)
2985 list(obj_expled.pps())
2986 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2987 obj_expled_encoded = obj_expled.encode()
2988 ctx_copied = deepcopy(ctx_dummy)
2989 obj_decoded, tail = obj_expled.decode(
2990 obj_expled_encoded + tail_junk,
2994 self.assertDictEqual(ctx_copied, ctx_dummy)
2996 list(obj_decoded.pps())
2997 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2998 self.assertEqual(tail, tail_junk)
2999 self.assertEqual(obj_decoded, obj_expled)
3000 self.assertNotEqual(obj_decoded, obj)
3001 self.assertEqual(int(obj_decoded), int(obj_expled))
3002 self.assertEqual(int(obj_decoded), int(obj))
3003 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3004 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3005 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3007 obj_decoded.expl_llen,
3008 len(len_encode(len(obj_encoded))),
3010 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3011 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3014 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3016 self.assertEqual(obj_decoded.expl_offset, offset)
3020 def string_values_strategy(draw, alphabet, do_expl=False):
3021 bound_min, bound_max = sorted(draw(sets(
3022 integers(min_value=0, max_value=1 << 7),
3026 value = draw(one_of(
3028 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3030 default = draw(one_of(
3032 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3035 if draw(booleans()):
3036 bounds = (bound_min, bound_max)
3040 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3042 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3043 optional = draw(one_of(none(), booleans()))
3045 draw(integers(min_value=0)),
3046 draw(integers(min_value=0)),
3047 draw(integers(min_value=0)),
3049 return (value, bounds, impl, expl, default, optional, _decoded)
3052 class StringMixin(object):
3053 def test_invalid_value_type(self):
3054 with self.assertRaises(InvalidValueType) as err:
3055 self.base_klass((1, 2))
3058 def text_alphabet(self):
3059 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3060 return printable + whitespace
3064 def test_optional(self, optional):
3065 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3066 self.assertTrue(obj.optional)
3068 @given(data_strategy())
3069 def test_ready(self, d):
3070 obj = self.base_klass()
3071 self.assertFalse(obj.ready)
3074 pprint(obj, big_blobs=True, with_decode_path=True)
3076 with self.assertRaises(ObjNotReady) as err:
3079 value = d.draw(text(alphabet=self.text_alphabet()))
3080 obj = self.base_klass(value)
3081 self.assertTrue(obj.ready)
3084 pprint(obj, big_blobs=True, with_decode_path=True)
3087 @given(data_strategy())
3088 def test_comparison(self, d):
3089 value1 = d.draw(text(alphabet=self.text_alphabet()))
3090 value2 = d.draw(text(alphabet=self.text_alphabet()))
3091 tag1 = d.draw(binary(min_size=1))
3092 tag2 = d.draw(binary(min_size=1))
3093 obj1 = self.base_klass(value1)
3094 obj2 = self.base_klass(value2)
3095 self.assertEqual(obj1 == obj2, value1 == value2)
3096 self.assertEqual(obj1 != obj2, value1 != value2)
3097 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3098 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3099 obj1 = self.base_klass(value1, impl=tag1)
3100 obj2 = self.base_klass(value1, impl=tag2)
3101 self.assertEqual(obj1 == obj2, tag1 == tag2)
3102 self.assertEqual(obj1 != obj2, tag1 != tag2)
3104 @given(data_strategy())
3105 def test_bounds_satisfied(self, d):
3106 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3107 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3108 value = d.draw(text(
3109 alphabet=self.text_alphabet(),
3113 self.base_klass(value=value, bounds=(bound_min, bound_max))
3115 @given(data_strategy())
3116 def test_bounds_unsatisfied(self, d):
3117 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3118 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3119 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3120 with self.assertRaises(BoundsError) as err:
3121 self.base_klass(value=value, bounds=(bound_min, bound_max))
3123 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3124 self.base_klass(bounds=(bound_min, bound_max)).decode(
3125 self.base_klass(value).encode()
3128 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3129 with self.assertRaises(BoundsError) as err:
3130 self.base_klass(value=value, bounds=(bound_min, bound_max))
3132 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3133 self.base_klass(bounds=(bound_min, bound_max)).decode(
3134 self.base_klass(value).encode()
3138 @given(data_strategy())
3139 def test_call(self, d):
3148 ) = d.draw(string_values_strategy(self.text_alphabet()))
3149 obj_initial = self.base_klass(
3155 optional_initial or False,
3166 ) = d.draw(string_values_strategy(
3167 self.text_alphabet(),
3168 do_expl=impl_initial is None,
3170 if (default is None) and (obj_initial.default is not None):
3173 (bounds is None) and
3174 (value is not None) and
3175 (bounds_initial is not None) and
3176 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3180 (bounds is None) and
3181 (default is not None) and
3182 (bounds_initial is not None) and
3183 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3186 obj = obj_initial(value, bounds, impl, expl, default, optional)
3188 value_expected = default if value is None else value
3190 default_initial if value_expected is None
3193 self.assertEqual(obj, value_expected)
3194 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3195 self.assertEqual(obj.expl_tag, expl or expl_initial)
3198 default_initial if default is None else default,
3200 if obj.default is None:
3201 optional = optional_initial if optional is None else optional
3202 optional = False if optional is None else optional
3205 self.assertEqual(obj.optional, optional)
3207 (obj._bound_min, obj._bound_max),
3208 bounds or bounds_initial or (0, float("+inf")),
3211 @given(data_strategy())
3212 def test_copy(self, d):
3213 values = d.draw(string_values_strategy(self.text_alphabet()))
3214 obj = self.base_klass(*values)
3215 obj_copied = obj.copy()
3216 self.assert_copied_basic_fields(obj, obj_copied)
3217 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3218 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3219 self.assertEqual(obj._value, obj_copied._value)
3221 @given(data_strategy())
3222 def test_stripped(self, d):
3223 value = d.draw(text(alphabet=self.text_alphabet()))
3224 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3225 obj = self.base_klass(value, impl=tag_impl)
3226 with self.assertRaises(NotEnoughData):
3227 obj.decode(obj.encode()[:-1])
3229 @given(data_strategy())
3230 def test_stripped_expl(self, d):
3231 value = d.draw(text(alphabet=self.text_alphabet()))
3232 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3233 obj = self.base_klass(value, expl=tag_expl)
3234 with self.assertRaises(NotEnoughData):
3235 obj.decode(obj.encode()[:-1])
3238 integers(min_value=31),
3239 integers(min_value=0),
3242 def test_bad_tag(self, tag, offset, decode_path):
3243 with self.assertRaises(DecodeError) as err:
3244 self.base_klass().decode(
3245 tag_encode(tag)[:-1],
3247 decode_path=decode_path,
3250 self.assertEqual(err.exception.offset, offset)
3251 self.assertEqual(err.exception.decode_path, decode_path)
3254 integers(min_value=128),
3255 integers(min_value=0),
3258 def test_bad_len(self, l, offset, decode_path):
3259 with self.assertRaises(DecodeError) as err:
3260 self.base_klass().decode(
3261 self.base_klass.tag_default + len_encode(l)[:-1],
3263 decode_path=decode_path,
3266 self.assertEqual(err.exception.offset, offset)
3267 self.assertEqual(err.exception.decode_path, decode_path)
3270 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3271 integers(min_value=0),
3274 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3275 value, bound_min = list(sorted(ints))
3277 class String(self.base_klass):
3278 # Multiply this value by four, to satisfy UTF-32 bounds
3279 # (4 bytes per character) validation
3280 bounds = (bound_min * 4, bound_min * 4)
3281 with self.assertRaises(DecodeError) as err:
3283 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3285 decode_path=decode_path,
3288 self.assertEqual(err.exception.offset, offset)
3289 self.assertEqual(err.exception.decode_path, decode_path)
3291 @given(data_strategy())
3292 def test_symmetric(self, d):
3293 values = d.draw(string_values_strategy(self.text_alphabet()))
3294 value = d.draw(text(alphabet=self.text_alphabet()))
3295 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3296 offset = d.draw(integers(min_value=0))
3297 tail_junk = d.draw(binary(max_size=5))
3298 _, _, _, _, default, optional, _decoded = values
3299 obj = self.base_klass(
3307 pprint(obj, big_blobs=True, with_decode_path=True)
3308 self.assertFalse(obj.expled)
3309 obj_encoded = obj.encode()
3310 obj_expled = obj(value, expl=tag_expl)
3311 self.assertTrue(obj_expled.expled)
3313 list(obj_expled.pps())
3314 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3315 obj_expled_encoded = obj_expled.encode()
3316 ctx_copied = deepcopy(ctx_dummy)
3317 obj_decoded, tail = obj_expled.decode(
3318 obj_expled_encoded + tail_junk,
3322 self.assertDictEqual(ctx_copied, ctx_dummy)
3324 list(obj_decoded.pps())
3325 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3326 self.assertEqual(tail, tail_junk)
3327 self.assertEqual(obj_decoded, obj_expled)
3328 self.assertNotEqual(obj_decoded, obj)
3329 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3330 self.assertEqual(bytes(obj_decoded), bytes(obj))
3331 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3332 self.assertEqual(text_type(obj_decoded), text_type(obj))
3333 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3334 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3335 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3337 obj_decoded.expl_llen,
3338 len(len_encode(len(obj_encoded))),
3340 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3341 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3344 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3346 self.assertEqual(obj_decoded.expl_offset, offset)
3349 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3350 base_klass = UTF8String
3353 cyrillic_letters = text(
3354 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3360 class UnicodeDecodeErrorMixin(object):
3361 @given(cyrillic_letters)
3362 def test_unicode_decode_error(self, cyrillic_text):
3363 with self.assertRaises(DecodeError):
3364 self.base_klass(cyrillic_text)
3367 class TestNumericString(StringMixin, CommonMixin, TestCase):
3368 base_klass = NumericString
3370 def text_alphabet(self):
3373 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3374 def test_non_numeric(self, non_numeric_text):
3375 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3376 self.base_klass(non_numeric_text)
3379 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3380 integers(min_value=0),
3383 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3384 value, bound_min = list(sorted(ints))
3386 class String(self.base_klass):
3387 bounds = (bound_min, bound_min)
3388 with self.assertRaises(DecodeError) as err:
3390 self.base_klass(b"1" * value).encode(),
3392 decode_path=decode_path,
3395 self.assertEqual(err.exception.offset, offset)
3396 self.assertEqual(err.exception.decode_path, decode_path)
3399 class TestPrintableString(
3400 UnicodeDecodeErrorMixin,
3405 base_klass = PrintableString
3407 def text_alphabet(self):
3408 return ascii_letters + digits + " '()+,-./:=?"
3410 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3411 def test_non_printable(self, non_printable_text):
3412 with assertRaisesRegex(self, DecodeError, "non-printable"):
3413 self.base_klass(non_printable_text)
3416 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3417 integers(min_value=0),
3420 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3421 value, bound_min = list(sorted(ints))
3423 class String(self.base_klass):
3424 bounds = (bound_min, bound_min)
3425 with self.assertRaises(DecodeError) as err:
3427 self.base_klass(b"1" * value).encode(),
3429 decode_path=decode_path,
3432 self.assertEqual(err.exception.offset, offset)
3433 self.assertEqual(err.exception.decode_path, decode_path)
3436 class TestTeletexString(
3437 UnicodeDecodeErrorMixin,
3442 base_klass = TeletexString
3445 class TestVideotexString(
3446 UnicodeDecodeErrorMixin,
3451 base_klass = VideotexString
3454 class TestIA5String(
3455 UnicodeDecodeErrorMixin,
3460 base_klass = IA5String
3463 class TestGraphicString(
3464 UnicodeDecodeErrorMixin,
3469 base_klass = GraphicString
3472 class TestVisibleString(
3473 UnicodeDecodeErrorMixin,
3478 base_klass = VisibleString
3480 def test_x690_vector(self):
3481 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3482 self.assertSequenceEqual(tail, b"")
3483 self.assertEqual(str(obj), "Jones")
3484 self.assertFalse(obj.ber_encoded)
3485 self.assertFalse(obj.lenindef)
3486 self.assertFalse(obj.bered)
3488 obj, tail = VisibleString().decode(
3489 hexdec("3A0904034A6F6E04026573"),
3490 ctx={"bered": True},
3492 self.assertSequenceEqual(tail, b"")
3493 self.assertEqual(str(obj), "Jones")
3494 self.assertTrue(obj.ber_encoded)
3495 self.assertFalse(obj.lenindef)
3496 self.assertTrue(obj.bered)
3498 obj, tail = VisibleString().decode(
3499 hexdec("3A8004034A6F6E040265730000"),
3500 ctx={"bered": True},
3502 self.assertSequenceEqual(tail, b"")
3503 self.assertEqual(str(obj), "Jones")
3504 self.assertTrue(obj.ber_encoded)
3505 self.assertTrue(obj.lenindef)
3506 self.assertTrue(obj.bered)
3509 class TestGeneralString(
3510 UnicodeDecodeErrorMixin,
3515 base_klass = GeneralString
3518 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3519 base_klass = UniversalString
3522 class TestBMPString(StringMixin, CommonMixin, TestCase):
3523 base_klass = BMPString
3527 def generalized_time_values_strategy(
3535 if draw(booleans()):
3536 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3538 value = value.replace(microsecond=0)
3540 if draw(booleans()):
3541 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3543 default = default.replace(microsecond=0)
3547 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3549 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3550 optional = draw(one_of(none(), booleans()))
3552 draw(integers(min_value=0)),
3553 draw(integers(min_value=0)),
3554 draw(integers(min_value=0)),
3556 return (value, impl, expl, default, optional, _decoded)
3559 class TimeMixin(object):
3560 def test_invalid_value_type(self):
3561 with self.assertRaises(InvalidValueType) as err:
3562 self.base_klass(datetime.now().timetuple())
3565 @given(data_strategy())
3566 def test_optional(self, d):
3567 default = d.draw(datetimes(
3568 min_value=self.min_datetime,
3569 max_value=self.max_datetime,
3571 optional = d.draw(booleans())
3572 obj = self.base_klass(default=default, optional=optional)
3573 self.assertTrue(obj.optional)
3575 @given(data_strategy())
3576 def test_ready(self, d):
3577 obj = self.base_klass()
3578 self.assertFalse(obj.ready)
3581 pprint(obj, big_blobs=True, with_decode_path=True)
3582 with self.assertRaises(ObjNotReady) as err:
3585 value = d.draw(datetimes(min_value=self.min_datetime))
3586 obj = self.base_klass(value)
3587 self.assertTrue(obj.ready)
3590 pprint(obj, big_blobs=True, with_decode_path=True)
3592 @given(data_strategy())
3593 def test_comparison(self, d):
3594 value1 = d.draw(datetimes(
3595 min_value=self.min_datetime,
3596 max_value=self.max_datetime,
3598 value2 = d.draw(datetimes(
3599 min_value=self.min_datetime,
3600 max_value=self.max_datetime,
3602 tag1 = d.draw(binary(min_size=1))
3603 tag2 = d.draw(binary(min_size=1))
3605 value1 = value1.replace(microsecond=0)
3606 value2 = value2.replace(microsecond=0)
3607 obj1 = self.base_klass(value1)
3608 obj2 = self.base_klass(value2)
3609 self.assertEqual(obj1 == obj2, value1 == value2)
3610 self.assertEqual(obj1 != obj2, value1 != value2)
3611 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3612 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3613 obj1 = self.base_klass(value1, impl=tag1)
3614 obj2 = self.base_klass(value1, impl=tag2)
3615 self.assertEqual(obj1 == obj2, tag1 == tag2)
3616 self.assertEqual(obj1 != obj2, tag1 != tag2)
3618 @given(data_strategy())
3619 def test_call(self, d):
3627 ) = d.draw(generalized_time_values_strategy(
3628 min_datetime=self.min_datetime,
3629 max_datetime=self.max_datetime,
3630 omit_ms=self.omit_ms,
3632 obj_initial = self.base_klass(
3633 value=value_initial,
3636 default=default_initial,
3637 optional=optional_initial or False,
3638 _decoded=_decoded_initial,
3647 ) = d.draw(generalized_time_values_strategy(
3648 min_datetime=self.min_datetime,
3649 max_datetime=self.max_datetime,
3650 omit_ms=self.omit_ms,
3651 do_expl=impl_initial is None,
3661 value_expected = default if value is None else value
3663 default_initial if value_expected is None
3666 self.assertEqual(obj, value_expected)
3667 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3668 self.assertEqual(obj.expl_tag, expl or expl_initial)
3671 default_initial if default is None else default,
3673 if obj.default is None:
3674 optional = optional_initial if optional is None else optional
3675 optional = False if optional is None else optional
3678 self.assertEqual(obj.optional, optional)
3680 @given(data_strategy())
3681 def test_copy(self, d):
3682 values = d.draw(generalized_time_values_strategy(
3683 min_datetime=self.min_datetime,
3684 max_datetime=self.max_datetime,
3686 obj = self.base_klass(*values)
3687 obj_copied = obj.copy()
3688 self.assert_copied_basic_fields(obj, obj_copied)
3689 self.assertEqual(obj._value, obj_copied._value)
3691 @given(data_strategy())
3692 def test_stripped(self, d):
3693 value = d.draw(datetimes(
3694 min_value=self.min_datetime,
3695 max_value=self.max_datetime,
3697 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3698 obj = self.base_klass(value, impl=tag_impl)
3699 with self.assertRaises(NotEnoughData):
3700 obj.decode(obj.encode()[:-1])
3702 @given(data_strategy())
3703 def test_stripped_expl(self, d):
3704 value = d.draw(datetimes(
3705 min_value=self.min_datetime,
3706 max_value=self.max_datetime,
3708 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3709 obj = self.base_klass(value, expl=tag_expl)
3710 with self.assertRaises(NotEnoughData):
3711 obj.decode(obj.encode()[:-1])
3713 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3714 @given(data_strategy())
3715 def test_symmetric(self, d):
3716 values = d.draw(generalized_time_values_strategy(
3717 min_datetime=self.min_datetime,
3718 max_datetime=self.max_datetime,
3720 value = d.draw(datetimes(
3721 min_value=self.min_datetime,
3722 max_value=self.max_datetime,
3724 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3725 offset = d.draw(integers(min_value=0))
3726 tail_junk = d.draw(binary(max_size=5))
3727 _, _, _, default, optional, _decoded = values
3728 obj = self.base_klass(
3736 pprint(obj, big_blobs=True, with_decode_path=True)
3737 self.assertFalse(obj.expled)
3738 obj_encoded = obj.encode()
3739 obj_expled = obj(value, expl=tag_expl)
3740 self.assertTrue(obj_expled.expled)
3742 list(obj_expled.pps())
3743 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3744 obj_expled_encoded = obj_expled.encode()
3745 ctx_copied = deepcopy(ctx_dummy)
3746 obj_decoded, tail = obj_expled.decode(
3747 obj_expled_encoded + tail_junk,
3751 self.assertDictEqual(ctx_copied, ctx_dummy)
3753 list(obj_decoded.pps())
3754 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3755 self.assertEqual(tail, tail_junk)
3756 self.assertEqual(obj_decoded, obj_expled)
3757 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3758 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3759 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3760 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3761 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3763 obj_decoded.expl_llen,
3764 len(len_encode(len(obj_encoded))),
3766 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3767 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3770 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3772 self.assertEqual(obj_decoded.expl_offset, offset)
3775 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3776 base_klass = GeneralizedTime
3778 min_datetime = datetime(1900, 1, 1)
3779 max_datetime = datetime(9999, 12, 31)
3781 def test_go_vectors_invalid(self):
3793 b"-20100102030410Z",
3794 b"2010-0102030410Z",
3795 b"2010-0002030410Z",
3796 b"201001-02030410Z",
3797 b"20100102-030410Z",
3798 b"2010010203-0410Z",
3799 b"201001020304-10Z",
3800 # These ones are INVALID in *DER*, but accepted
3801 # by Go's encoding/asn1
3802 b"20100102030405+0607",
3803 b"20100102030405-0607",
3805 with self.assertRaises(DecodeError) as err:
3806 GeneralizedTime(data)
3809 def test_go_vectors_valid(self):
3811 GeneralizedTime(b"20100102030405Z").todatetime(),
3812 datetime(2010, 1, 2, 3, 4, 5, 0),
3817 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3818 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3820 binary(min_size=1, max_size=1),
3822 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3823 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3826 def test_junk(self, part0, part1, part2):
3827 junk = part0 + part1 + part2
3828 assume(not (set(junk) <= set(digits.encode("ascii"))))
3829 with self.assertRaises(DecodeError):
3830 GeneralizedTime().decode(
3831 GeneralizedTime.tag_default +
3832 len_encode(len(junk)) +
3838 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3839 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3841 binary(min_size=1, max_size=1),
3843 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3844 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3847 def test_junk_dm(self, part0, part1, part2):
3848 junk = part0 + part1 + part2
3849 assume(not (set(junk) <= set(digits.encode("ascii"))))
3850 with self.assertRaises(DecodeError):
3851 GeneralizedTime().decode(
3852 GeneralizedTime.tag_default +
3853 len_encode(len(junk)) +
3858 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3859 base_klass = UTCTime
3861 min_datetime = datetime(2000, 1, 1)
3862 max_datetime = datetime(2049, 12, 31)
3864 def test_go_vectors_invalid(self):
3890 # These ones are INVALID in *DER*, but accepted
3891 # by Go's encoding/asn1
3892 b"910506164540-0700",
3893 b"910506164540+0730",
3897 with self.assertRaises(DecodeError) as err:
3901 def test_go_vectors_valid(self):
3903 UTCTime(b"910506234540Z").todatetime(),
3904 datetime(1991, 5, 6, 23, 45, 40, 0),
3907 @given(integers(min_value=0, max_value=49))
3908 def test_pre50(self, year):
3910 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3914 @given(integers(min_value=50, max_value=99))
3915 def test_post50(self, year):
3917 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3923 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3924 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3926 binary(min_size=1, max_size=1),
3928 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3929 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3932 def test_junk(self, part0, part1, part2):
3933 junk = part0 + part1 + part2
3934 assume(not (set(junk) <= set(digits.encode("ascii"))))
3935 with self.assertRaises(DecodeError):
3937 UTCTime.tag_default +
3938 len_encode(len(junk)) +
3944 def any_values_strategy(draw, do_expl=False):
3945 value = draw(one_of(none(), binary()))
3948 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3949 optional = draw(one_of(none(), booleans()))
3951 draw(integers(min_value=0)),
3952 draw(integers(min_value=0)),
3953 draw(integers(min_value=0)),
3955 return (value, expl, optional, _decoded)
3958 class AnyInherited(Any):
3962 class TestAny(CommonMixin, TestCase):
3965 def test_invalid_value_type(self):
3966 with self.assertRaises(InvalidValueType) as err:
3971 def test_optional(self, optional):
3972 obj = Any(optional=optional)
3973 self.assertEqual(obj.optional, optional)
3976 def test_ready(self, value):
3978 self.assertFalse(obj.ready)
3981 pprint(obj, big_blobs=True, with_decode_path=True)
3982 with self.assertRaises(ObjNotReady) as err:
3986 self.assertTrue(obj.ready)
3989 pprint(obj, big_blobs=True, with_decode_path=True)
3992 def test_basic(self, value):
3993 integer_encoded = Integer(value).encode()
3995 Any(integer_encoded),
3996 Any(Integer(value)),
3997 Any(Any(Integer(value))),
3999 self.assertSequenceEqual(bytes(obj), integer_encoded)
4001 obj.decode(obj.encode())[0].vlen,
4002 len(integer_encoded),
4006 pprint(obj, big_blobs=True, with_decode_path=True)
4007 self.assertSequenceEqual(obj.encode(), integer_encoded)
4009 @given(binary(), binary())
4010 def test_comparison(self, value1, value2):
4011 for klass in (Any, AnyInherited):
4012 obj1 = klass(value1)
4013 obj2 = klass(value2)
4014 self.assertEqual(obj1 == obj2, value1 == value2)
4015 self.assertEqual(obj1 != obj2, value1 != value2)
4016 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4018 @given(data_strategy())
4019 def test_call(self, d):
4020 for klass in (Any, AnyInherited):
4026 ) = d.draw(any_values_strategy())
4027 obj_initial = klass(
4030 optional_initial or False,
4038 ) = d.draw(any_values_strategy(do_expl=True))
4039 obj = obj_initial(value, expl, optional)
4041 value_expected = None if value is None else value
4042 self.assertEqual(obj, value_expected)
4043 self.assertEqual(obj.expl_tag, expl or expl_initial)
4044 if obj.default is None:
4045 optional = optional_initial if optional is None else optional
4046 optional = False if optional is None else optional
4047 self.assertEqual(obj.optional, optional)
4049 def test_simultaneous_impl_expl(self):
4050 # override it, as Any does not have implicit tag
4053 def test_decoded(self):
4054 # override it, as Any does not have implicit tag
4057 @given(any_values_strategy())
4058 def test_copy(self, values):
4059 for klass in (Any, AnyInherited):
4060 obj = klass(*values)
4061 obj_copied = obj.copy()
4062 self.assert_copied_basic_fields(obj, obj_copied)
4063 self.assertEqual(obj._value, obj_copied._value)
4065 @given(binary().map(OctetString))
4066 def test_stripped(self, value):
4068 with self.assertRaises(NotEnoughData):
4069 obj.decode(obj.encode()[:-1])
4073 integers(min_value=1).map(tag_ctxc),
4075 def test_stripped_expl(self, value, tag_expl):
4076 obj = Any(value, expl=tag_expl)
4077 with self.assertRaises(NotEnoughData):
4078 obj.decode(obj.encode()[:-1])
4081 integers(min_value=31),
4082 integers(min_value=0),
4085 def test_bad_tag(self, tag, offset, decode_path):
4086 with self.assertRaises(DecodeError) as err:
4088 tag_encode(tag)[:-1],
4090 decode_path=decode_path,
4093 self.assertEqual(err.exception.offset, offset)
4094 self.assertEqual(err.exception.decode_path, decode_path)
4097 integers(min_value=128),
4098 integers(min_value=0),
4101 def test_bad_len(self, l, offset, decode_path):
4102 with self.assertRaises(DecodeError) as err:
4104 Any.tag_default + len_encode(l)[:-1],
4106 decode_path=decode_path,
4109 self.assertEqual(err.exception.offset, offset)
4110 self.assertEqual(err.exception.decode_path, decode_path)
4112 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4114 any_values_strategy(),
4115 integers().map(lambda x: Integer(x).encode()),
4116 integers(min_value=1).map(tag_ctxc),
4117 integers(min_value=0),
4120 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4121 for klass in (Any, AnyInherited):
4122 _, _, optional, _decoded = values
4123 obj = klass(value=value, optional=optional, _decoded=_decoded)
4126 pprint(obj, big_blobs=True, with_decode_path=True)
4127 self.assertFalse(obj.expled)
4128 obj_encoded = obj.encode()
4129 obj_expled = obj(value, expl=tag_expl)
4130 self.assertTrue(obj_expled.expled)
4132 list(obj_expled.pps())
4133 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4134 obj_expled_encoded = obj_expled.encode()
4135 ctx_copied = deepcopy(ctx_dummy)
4136 obj_decoded, tail = obj_expled.decode(
4137 obj_expled_encoded + tail_junk,
4141 self.assertDictEqual(ctx_copied, ctx_dummy)
4143 list(obj_decoded.pps())
4144 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4145 self.assertEqual(tail, tail_junk)
4146 self.assertEqual(obj_decoded, obj_expled)
4147 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4148 self.assertEqual(bytes(obj_decoded), bytes(obj))
4149 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4150 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4151 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4153 obj_decoded.expl_llen,
4154 len(len_encode(len(obj_encoded))),
4156 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4157 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4160 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4162 self.assertEqual(obj_decoded.expl_offset, offset)
4163 self.assertEqual(obj_decoded.tlen, 0)
4164 self.assertEqual(obj_decoded.llen, 0)
4165 self.assertEqual(obj_decoded.vlen, len(value))
4168 integers(min_value=1).map(tag_ctxc),
4169 integers(min_value=0, max_value=3),
4170 integers(min_value=0),
4174 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4175 chunk = Boolean(False, expl=expl).encode()
4177 OctetString.tag_default +
4179 b"".join([chunk] * chunks) +
4182 with self.assertRaises(LenIndefForm):
4186 decode_path=decode_path,
4188 obj, tail = Any().decode(
4191 decode_path=decode_path,
4192 ctx={"bered": True},
4194 self.assertSequenceEqual(tail, junk)
4195 self.assertEqual(obj.offset, offset)
4196 self.assertEqual(obj.tlvlen, len(encoded))
4197 self.assertTrue(obj.lenindef)
4198 self.assertFalse(obj.ber_encoded)
4199 self.assertTrue(obj.bered)
4202 pprint(obj, big_blobs=True, with_decode_path=True)
4203 with self.assertRaises(NotEnoughData) as err:
4207 decode_path=decode_path,
4208 ctx={"bered": True},
4210 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4211 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4213 class SeqOf(SequenceOf):
4214 schema = Boolean(expl=expl)
4216 class Seq(Sequence):
4218 ("type", ObjectIdentifier(defines=((("value",), {
4219 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4224 ("type", ObjectIdentifier("1.2.3")),
4225 ("value", Any(encoded)),
4227 seq_encoded = seq.encode()
4228 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4229 self.assertIsNotNone(seq_decoded["value"].defined)
4231 list(seq_decoded.pps())
4232 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4233 self.assertTrue(seq_decoded.bered)
4234 self.assertFalse(seq_decoded["type"].bered)
4235 self.assertTrue(seq_decoded["value"].bered)
4237 chunk = chunk[:-1] + b"\x01"
4238 chunks = b"".join([chunk] * (chunks + 1))
4239 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4241 ("type", ObjectIdentifier("1.2.3")),
4242 ("value", Any(encoded)),
4244 seq_encoded = seq.encode()
4245 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4246 self.assertIsNotNone(seq_decoded["value"].defined)
4248 list(seq_decoded.pps())
4249 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4250 self.assertTrue(seq_decoded.bered)
4251 self.assertFalse(seq_decoded["type"].bered)
4252 self.assertTrue(seq_decoded["value"].bered)
4256 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4258 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4259 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4261 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4262 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4264 min_size=len(names),
4265 max_size=len(names),
4268 (name, Integer(**tag_kwargs))
4269 for name, tag_kwargs in zip(names, tags)
4272 if value_required or draw(booleans()):
4273 value = draw(tuples(
4274 sampled_from([name for name, _ in schema]),
4275 integers().map(Integer),
4279 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4280 default = draw(one_of(
4282 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4284 optional = draw(one_of(none(), booleans()))
4286 draw(integers(min_value=0)),
4287 draw(integers(min_value=0)),
4288 draw(integers(min_value=0)),
4290 return (schema, value, expl, default, optional, _decoded)
4293 class ChoiceInherited(Choice):
4297 class TestChoice(CommonMixin, TestCase):
4299 schema = (("whatever", Boolean()),)
4302 def test_schema_required(self):
4303 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4306 def test_impl_forbidden(self):
4307 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4308 Choice(impl=b"whatever")
4310 def test_invalid_value_type(self):
4311 with self.assertRaises(InvalidValueType) as err:
4312 self.base_klass(123)
4314 with self.assertRaises(ObjUnknown) as err:
4315 self.base_klass(("whenever", Boolean(False)))
4317 with self.assertRaises(InvalidValueType) as err:
4318 self.base_klass(("whatever", Integer(123)))
4322 def test_optional(self, optional):
4323 obj = self.base_klass(
4324 default=self.base_klass(("whatever", Boolean(False))),
4327 self.assertTrue(obj.optional)
4330 def test_ready(self, value):
4331 obj = self.base_klass()
4332 self.assertFalse(obj.ready)
4335 pprint(obj, big_blobs=True, with_decode_path=True)
4336 self.assertIsNone(obj["whatever"])
4337 with self.assertRaises(ObjNotReady) as err:
4340 obj["whatever"] = Boolean()
4341 self.assertFalse(obj.ready)
4344 pprint(obj, big_blobs=True, with_decode_path=True)
4345 obj["whatever"] = Boolean(value)
4346 self.assertTrue(obj.ready)
4349 pprint(obj, big_blobs=True, with_decode_path=True)
4351 @given(booleans(), booleans())
4352 def test_comparison(self, value1, value2):
4353 class WahlInherited(self.base_klass):
4355 for klass in (self.base_klass, WahlInherited):
4356 obj1 = klass(("whatever", Boolean(value1)))
4357 obj2 = klass(("whatever", Boolean(value2)))
4358 self.assertEqual(obj1 == obj2, value1 == value2)
4359 self.assertEqual(obj1 != obj2, value1 != value2)
4360 self.assertEqual(obj1 == obj2._value, value1 == value2)
4361 self.assertFalse(obj1 == obj2._value[1])
4363 @given(data_strategy())
4364 def test_call(self, d):
4365 for klass in (Choice, ChoiceInherited):
4373 ) = d.draw(choice_values_strategy())
4376 schema = schema_initial
4378 value=value_initial,
4380 default=default_initial,
4381 optional=optional_initial or False,
4382 _decoded=_decoded_initial,
4391 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4392 obj = obj_initial(value, expl, default, optional)
4394 value_expected = default if value is None else value
4396 default_initial if value_expected is None
4399 self.assertEqual(obj.choice, value_expected[0])
4400 self.assertEqual(obj.value, int(value_expected[1]))
4401 self.assertEqual(obj.expl_tag, expl or expl_initial)
4402 default_expect = default_initial if default is None else default
4403 if default_expect is not None:
4404 self.assertEqual(obj.default.choice, default_expect[0])
4405 self.assertEqual(obj.default.value, int(default_expect[1]))
4406 if obj.default is None:
4407 optional = optional_initial if optional is None else optional
4408 optional = False if optional is None else optional
4411 self.assertEqual(obj.optional, optional)
4412 self.assertEqual(obj.specs, obj_initial.specs)
4414 def test_simultaneous_impl_expl(self):
4415 # override it, as Any does not have implicit tag
4418 def test_decoded(self):
4419 # override it, as Any does not have implicit tag
4422 @given(choice_values_strategy())
4423 def test_copy(self, values):
4424 _schema, value, expl, default, optional, _decoded = values
4426 class Wahl(self.base_klass):
4432 optional=optional or False,
4435 obj_copied = obj.copy()
4436 self.assertIsNone(obj.tag)
4437 self.assertIsNone(obj_copied.tag)
4438 # hack for assert_copied_basic_fields
4439 obj.tag = "whatever"
4440 obj_copied.tag = "whatever"
4441 self.assert_copied_basic_fields(obj, obj_copied)
4442 self.assertEqual(obj._value, obj_copied._value)
4443 self.assertEqual(obj.specs, obj_copied.specs)
4446 def test_stripped(self, value):
4447 obj = self.base_klass(("whatever", Boolean(value)))
4448 with self.assertRaises(NotEnoughData):
4449 obj.decode(obj.encode()[:-1])
4453 integers(min_value=1).map(tag_ctxc),
4455 def test_stripped_expl(self, value, tag_expl):
4456 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4457 with self.assertRaises(NotEnoughData):
4458 obj.decode(obj.encode()[:-1])
4460 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4461 @given(data_strategy())
4462 def test_symmetric(self, d):
4463 _schema, value, _, default, optional, _decoded = d.draw(
4464 choice_values_strategy(value_required=True)
4466 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4467 offset = d.draw(integers(min_value=0))
4468 tail_junk = d.draw(binary(max_size=5))
4470 class Wahl(self.base_klass):
4480 pprint(obj, big_blobs=True, with_decode_path=True)
4481 self.assertFalse(obj.expled)
4482 obj_encoded = obj.encode()
4483 obj_expled = obj(value, expl=tag_expl)
4484 self.assertTrue(obj_expled.expled)
4486 list(obj_expled.pps())
4487 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4488 obj_expled_encoded = obj_expled.encode()
4489 ctx_copied = deepcopy(ctx_dummy)
4490 obj_decoded, tail = obj_expled.decode(
4491 obj_expled_encoded + tail_junk,
4495 self.assertDictEqual(ctx_copied, ctx_dummy)
4497 list(obj_decoded.pps())
4498 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4499 self.assertEqual(tail, tail_junk)
4500 self.assertEqual(obj_decoded, obj_expled)
4501 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4502 self.assertEqual(obj_decoded.value, obj_expled.value)
4503 self.assertEqual(obj_decoded.choice, obj.choice)
4504 self.assertEqual(obj_decoded.value, obj.value)
4505 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4506 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4507 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4509 obj_decoded.expl_llen,
4510 len(len_encode(len(obj_encoded))),
4512 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4513 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4516 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4518 self.assertEqual(obj_decoded.expl_offset, offset)
4519 self.assertSequenceEqual(
4521 obj_decoded.value.fulloffset - offset:
4522 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4528 def test_set_get(self, value):
4531 ("erste", Boolean()),
4532 ("zweite", Integer()),
4535 with self.assertRaises(ObjUnknown) as err:
4536 obj["whatever"] = "whenever"
4537 with self.assertRaises(InvalidValueType) as err:
4538 obj["zweite"] = Boolean(False)
4539 obj["zweite"] = Integer(value)
4541 with self.assertRaises(ObjUnknown) as err:
4544 self.assertIsNone(obj["erste"])
4545 self.assertEqual(obj["zweite"], Integer(value))
4547 def test_tag_mismatch(self):
4550 ("erste", Boolean()),
4552 int_encoded = Integer(123).encode()
4553 bool_encoded = Boolean(False).encode()
4555 obj.decode(bool_encoded)
4556 with self.assertRaises(TagMismatch):
4557 obj.decode(int_encoded)
4559 def test_tag_mismatch_underlying(self):
4560 class SeqOfBoolean(SequenceOf):
4563 class SeqOfInteger(SequenceOf):
4568 ("erste", SeqOfBoolean()),
4571 int_encoded = SeqOfInteger((Integer(123),)).encode()
4572 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4574 obj.decode(bool_encoded)
4575 with self.assertRaises(TagMismatch) as err:
4576 obj.decode(int_encoded)
4577 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4581 def seq_values_strategy(draw, seq_klass, do_expl=False):
4583 if draw(booleans()):
4586 k: v for k, v in draw(dictionaries(
4589 booleans().map(Boolean),
4590 integers().map(Integer),
4595 if draw(booleans()):
4596 schema = list(draw(dictionaries(
4599 booleans().map(Boolean),
4600 integers().map(Integer),
4606 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4608 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4610 if draw(booleans()):
4611 default = seq_klass()
4613 k: v for k, v in draw(dictionaries(
4616 booleans().map(Boolean),
4617 integers().map(Integer),
4621 optional = draw(one_of(none(), booleans()))
4623 draw(integers(min_value=0)),
4624 draw(integers(min_value=0)),
4625 draw(integers(min_value=0)),
4627 return (value, schema, impl, expl, default, optional, _decoded)
4631 def sequence_strategy(draw, seq_klass):
4632 inputs = draw(lists(
4634 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4635 tuples(just(Integer), integers(), one_of(none(), integers())),
4640 integers(min_value=1),
4641 min_size=len(inputs),
4642 max_size=len(inputs),
4645 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4646 for tag, expled in zip(tags, draw(lists(
4648 min_size=len(inputs),
4649 max_size=len(inputs),
4653 for i, optional in enumerate(draw(lists(
4654 sampled_from(("required", "optional", "empty")),
4655 min_size=len(inputs),
4656 max_size=len(inputs),
4658 if optional in ("optional", "empty"):
4659 inits[i]["optional"] = True
4660 if optional == "empty":
4662 empties = set(empties)
4663 names = list(draw(sets(
4665 min_size=len(inputs),
4666 max_size=len(inputs),
4669 for i, (klass, value, default) in enumerate(inputs):
4670 schema.append((names[i], klass(default=default, **inits[i])))
4671 seq_name = draw(text_letters())
4672 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4675 for i, (klass, value, default) in enumerate(inputs):
4682 "default_value": None if spec.default is None else default,
4686 expect["optional"] = True
4688 expect["presented"] = True
4689 expect["value"] = value
4691 expect["optional"] = True
4692 if default is not None and default == value:
4693 expect["presented"] = False
4694 seq[name] = klass(value)
4695 expects.append(expect)
4700 def sequences_strategy(draw, seq_klass):
4701 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4703 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4704 for tag, expled in zip(tags, draw(lists(
4711 i for i, is_default in enumerate(draw(lists(
4717 names = list(draw(sets(
4722 seq_expectses = draw(lists(
4723 sequence_strategy(seq_klass=seq_klass),
4727 seqs = [seq for seq, _ in seq_expectses]
4729 for i, (name, seq) in enumerate(zip(names, seqs)):
4732 seq(default=(seq if i in defaulted else None), **inits[i]),
4734 seq_name = draw(text_letters())
4735 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4738 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4741 "expects": expects_inner,
4744 seq_outer[name] = seq_inner
4745 if seq_outer.specs[name].default is None:
4746 expect["presented"] = True
4747 expect_outers.append(expect)
4748 return seq_outer, expect_outers
4751 class SeqMixing(object):
4752 def test_invalid_value_type(self):
4753 with self.assertRaises(InvalidValueType) as err:
4754 self.base_klass(123)
4757 def test_invalid_value_type_set(self):
4758 class Seq(self.base_klass):
4759 schema = (("whatever", Boolean()),)
4761 with self.assertRaises(InvalidValueType) as err:
4762 seq["whatever"] = Integer(123)
4766 def test_optional(self, optional):
4767 obj = self.base_klass(default=self.base_klass(), optional=optional)
4768 self.assertTrue(obj.optional)
4770 @given(data_strategy())
4771 def test_ready(self, d):
4773 str(i): v for i, v in enumerate(d.draw(lists(
4780 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4787 for name in d.draw(permutations(
4788 list(ready.keys()) + list(non_ready.keys()),
4790 schema_input.append((name, Boolean()))
4792 class Seq(self.base_klass):
4793 schema = tuple(schema_input)
4795 for name in ready.keys():
4797 seq[name] = Boolean()
4798 self.assertFalse(seq.ready)
4801 pprint(seq, big_blobs=True, with_decode_path=True)
4802 for name, value in ready.items():
4803 seq[name] = Boolean(value)
4804 self.assertFalse(seq.ready)
4807 pprint(seq, big_blobs=True, with_decode_path=True)
4808 with self.assertRaises(ObjNotReady) as err:
4811 for name, value in non_ready.items():
4812 seq[name] = Boolean(value)
4813 self.assertTrue(seq.ready)
4816 pprint(seq, big_blobs=True, with_decode_path=True)
4818 @given(data_strategy())
4819 def test_call(self, d):
4820 class SeqInherited(self.base_klass):
4822 for klass in (self.base_klass, SeqInherited):
4831 ) = d.draw(seq_values_strategy(seq_klass=klass))
4832 obj_initial = klass(
4838 optional_initial or False,
4849 ) = d.draw(seq_values_strategy(
4851 do_expl=impl_initial is None,
4853 obj = obj_initial(value, impl, expl, default, optional)
4854 value_expected = default if value is None else value
4856 default_initial if value_expected is None
4859 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4860 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4861 self.assertEqual(obj.expl_tag, expl or expl_initial)
4863 {} if obj.default is None else obj.default._value,
4864 getattr(default_initial if default is None else default, "_value", {}),
4866 if obj.default is None:
4867 optional = optional_initial if optional is None else optional
4868 optional = False if optional is None else optional
4871 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4872 self.assertEqual(obj.optional, optional)
4874 @given(data_strategy())
4875 def test_copy(self, d):
4876 class SeqInherited(self.base_klass):
4878 for klass in (self.base_klass, SeqInherited):
4879 values = d.draw(seq_values_strategy(seq_klass=klass))
4880 obj = klass(*values)
4881 obj_copied = obj.copy()
4882 self.assert_copied_basic_fields(obj, obj_copied)
4883 self.assertEqual(obj.specs, obj_copied.specs)
4884 self.assertEqual(obj._value, obj_copied._value)
4886 @given(data_strategy())
4887 def test_stripped(self, d):
4888 value = d.draw(integers())
4889 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4891 class Seq(self.base_klass):
4893 schema = (("whatever", Integer()),)
4895 seq["whatever"] = Integer(value)
4896 with self.assertRaises(NotEnoughData):
4897 seq.decode(seq.encode()[:-1])
4899 @given(data_strategy())
4900 def test_stripped_expl(self, d):
4901 value = d.draw(integers())
4902 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4904 class Seq(self.base_klass):
4906 schema = (("whatever", Integer()),)
4908 seq["whatever"] = Integer(value)
4909 with self.assertRaises(NotEnoughData):
4910 seq.decode(seq.encode()[:-1])
4912 @given(binary(min_size=2))
4913 def test_non_tag_mismatch_raised(self, junk):
4915 _, _, len_encoded = tag_strip(memoryview(junk))
4916 len_decode(len_encoded)
4922 class Seq(self.base_klass):
4924 ("whatever", Integer()),
4926 ("whenever", Integer()),
4929 seq["whatever"] = Integer(123)
4930 seq["junk"] = Any(junk)
4931 seq["whenever"] = Integer(123)
4932 with self.assertRaises(DecodeError):
4933 seq.decode(seq.encode())
4936 integers(min_value=31),
4937 integers(min_value=0),
4940 def test_bad_tag(self, tag, offset, decode_path):
4941 with self.assertRaises(DecodeError) as err:
4942 self.base_klass().decode(
4943 tag_encode(tag)[:-1],
4945 decode_path=decode_path,
4948 self.assertEqual(err.exception.offset, offset)
4949 self.assertEqual(err.exception.decode_path, decode_path)
4952 integers(min_value=128),
4953 integers(min_value=0),
4956 def test_bad_len(self, l, offset, decode_path):
4957 with self.assertRaises(DecodeError) as err:
4958 self.base_klass().decode(
4959 self.base_klass.tag_default + len_encode(l)[:-1],
4961 decode_path=decode_path,
4964 self.assertEqual(err.exception.offset, offset)
4965 self.assertEqual(err.exception.decode_path, decode_path)
4967 def _assert_expects(self, seq, expects):
4968 for expect in expects:
4970 seq.specs[expect["name"]].optional,
4973 if expect["default_value"] is not None:
4975 seq.specs[expect["name"]].default,
4976 expect["default_value"],
4978 if expect["presented"]:
4979 self.assertIn(expect["name"], seq)
4980 self.assertEqual(seq[expect["name"]], expect["value"])
4982 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4983 @given(data_strategy())
4984 def test_symmetric(self, d):
4985 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4986 tail_junk = d.draw(binary(max_size=5))
4987 self.assertTrue(seq.ready)
4988 self.assertFalse(seq.decoded)
4989 self._assert_expects(seq, expects)
4992 pprint(seq, big_blobs=True, with_decode_path=True)
4993 self.assertTrue(seq.ready)
4994 seq_encoded = seq.encode()
4995 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4996 self.assertFalse(seq_decoded.lenindef)
4997 self.assertFalse(seq_decoded.ber_encoded)
4998 self.assertFalse(seq_decoded.bered)
5000 t, _, lv = tag_strip(seq_encoded)
5001 _, _, v = len_decode(lv)
5002 seq_encoded_lenindef = t + LENINDEF + v + EOC
5003 ctx_copied = deepcopy(ctx_dummy)
5004 ctx_copied["bered"] = True
5005 seq_decoded_lenindef, tail_lenindef = seq.decode(
5006 seq_encoded_lenindef + tail_junk,
5009 del ctx_copied["bered"]
5010 self.assertDictEqual(ctx_copied, ctx_dummy)
5011 self.assertTrue(seq_decoded_lenindef.lenindef)
5012 self.assertTrue(seq_decoded_lenindef.bered)
5013 with self.assertRaises(DecodeError):
5014 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5015 with self.assertRaises(DecodeError):
5016 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5017 repr(seq_decoded_lenindef)
5018 list(seq_decoded_lenindef.pps())
5019 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5020 self.assertTrue(seq_decoded_lenindef.ready)
5022 for decoded, decoded_tail, encoded in (
5023 (seq_decoded, tail, seq_encoded),
5024 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5026 self.assertEqual(decoded_tail, tail_junk)
5027 self._assert_expects(decoded, expects)
5028 self.assertEqual(seq, decoded)
5029 self.assertEqual(decoded.encode(), seq_encoded)
5030 self.assertEqual(decoded.tlvlen, len(encoded))
5031 for expect in expects:
5032 if not expect["presented"]:
5033 self.assertNotIn(expect["name"], decoded)
5035 self.assertIn(expect["name"], decoded)
5036 obj = decoded[expect["name"]]
5037 self.assertTrue(obj.decoded)
5038 offset = obj.expl_offset if obj.expled else obj.offset
5039 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5040 self.assertSequenceEqual(
5041 seq_encoded[offset:offset + tlvlen],
5045 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5046 @given(data_strategy())
5047 def test_symmetric_with_seq(self, d):
5048 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5049 self.assertTrue(seq.ready)
5050 seq_encoded = seq.encode()
5051 seq_decoded, tail = seq.decode(seq_encoded)
5052 self.assertEqual(tail, b"")
5053 self.assertTrue(seq.ready)
5054 self.assertEqual(seq, seq_decoded)
5055 self.assertEqual(seq_decoded.encode(), seq_encoded)
5056 for expect_outer in expect_outers:
5057 if not expect_outer["presented"]:
5058 self.assertNotIn(expect_outer["name"], seq_decoded)
5060 self.assertIn(expect_outer["name"], seq_decoded)
5061 obj = seq_decoded[expect_outer["name"]]
5062 self.assertTrue(obj.decoded)
5063 offset = obj.expl_offset if obj.expled else obj.offset
5064 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5065 self.assertSequenceEqual(
5066 seq_encoded[offset:offset + tlvlen],
5069 self._assert_expects(obj, expect_outer["expects"])
5071 @given(data_strategy())
5072 def test_default_disappears(self, d):
5073 _schema = list(d.draw(dictionaries(
5075 sets(integers(), min_size=2, max_size=2),
5079 class Seq(self.base_klass):
5081 (n, Integer(default=d))
5082 for n, (_, d) in _schema
5085 for name, (value, _) in _schema:
5086 seq[name] = Integer(value)
5087 self.assertEqual(len(seq._value), len(_schema))
5088 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5089 self.assertGreater(len(seq.encode()), len(empty_seq))
5090 for name, (_, default) in _schema:
5091 seq[name] = Integer(default)
5092 self.assertEqual(len(seq._value), 0)
5093 self.assertSequenceEqual(seq.encode(), empty_seq)
5095 @given(data_strategy())
5096 def test_encoded_default_not_accepted(self, d):
5097 _schema = list(d.draw(dictionaries(
5102 tags = [tag_encode(tag) for tag in d.draw(sets(
5103 integers(min_value=0),
5104 min_size=len(_schema),
5105 max_size=len(_schema),
5108 class SeqWithoutDefault(self.base_klass):
5110 (n, Integer(impl=t))
5111 for (n, _), t in zip(_schema, tags)
5113 seq_without_default = SeqWithoutDefault()
5114 for name, value in _schema:
5115 seq_without_default[name] = Integer(value)
5116 seq_encoded = seq_without_default.encode()
5118 class SeqWithDefault(self.base_klass):
5120 (n, Integer(default=v, impl=t))
5121 for (n, v), t in zip(_schema, tags)
5123 seq_with_default = SeqWithDefault()
5124 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5125 seq_with_default.decode(seq_encoded)
5126 for ctx in ({"bered": True}, {"allow_default_values": True}):
5127 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5128 self.assertTrue(seq_decoded.ber_encoded)
5129 self.assertTrue(seq_decoded.bered)
5130 for name, value in _schema:
5131 self.assertEqual(seq_decoded[name], seq_with_default[name])
5132 self.assertEqual(seq_decoded[name], value)
5134 @given(data_strategy())
5135 def test_missing_from_spec(self, d):
5136 names = list(d.draw(sets(text_letters(), min_size=2)))
5137 tags = [tag_encode(tag) for tag in d.draw(sets(
5138 integers(min_value=0),
5139 min_size=len(names),
5140 max_size=len(names),
5142 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5144 class SeqFull(self.base_klass):
5145 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5146 seq_full = SeqFull()
5147 for i, name in enumerate(names):
5148 seq_full[name] = Integer(i)
5149 seq_encoded = seq_full.encode()
5150 altered = names_tags[:-2] + names_tags[-1:]
5152 class SeqMissing(self.base_klass):
5153 schema = [(n, Integer(impl=t)) for n, t in altered]
5154 seq_missing = SeqMissing()
5155 with self.assertRaises(TagMismatch):
5156 seq_missing.decode(seq_encoded)
5158 @given(data_strategy())
5159 def test_bered(self, d):
5160 class Seq(self.base_klass):
5161 schema = (("underlying", Boolean()),)
5162 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5163 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5164 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5165 self.assertFalse(decoded.ber_encoded)
5166 self.assertFalse(decoded.lenindef)
5167 self.assertTrue(decoded.bered)
5169 class Seq(self.base_klass):
5170 schema = (("underlying", OctetString()),)
5172 tag_encode(form=TagFormConstructed, num=4) +
5174 OctetString(b"whatever").encode() +
5177 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5178 with self.assertRaises(DecodeError):
5179 Seq().decode(encoded)
5180 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5181 self.assertFalse(decoded.ber_encoded)
5182 self.assertFalse(decoded.lenindef)
5183 self.assertTrue(decoded.bered)
5186 class TestSequence(SeqMixing, CommonMixin, TestCase):
5187 base_klass = Sequence
5193 def test_remaining(self, value, junk):
5194 class Seq(Sequence):
5196 ("whatever", Integer()),
5198 int_encoded = Integer(value).encode()
5200 Sequence.tag_default,
5201 len_encode(len(int_encoded + junk)),
5204 with assertRaisesRegex(self, DecodeError, "remaining"):
5205 Seq().decode(junked)
5207 @given(sets(text_letters(), min_size=2))
5208 def test_obj_unknown(self, names):
5209 missing = names.pop()
5211 class Seq(Sequence):
5212 schema = [(n, Boolean()) for n in names]
5214 with self.assertRaises(ObjUnknown) as err:
5217 with self.assertRaises(ObjUnknown) as err:
5218 seq[missing] = Boolean()
5221 def test_x690_vector(self):
5222 class Seq(Sequence):
5224 ("name", IA5String()),
5227 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5228 self.assertEqual(seq["name"], "Smith")
5229 self.assertEqual(seq["ok"], True)
5232 class TestSet(SeqMixing, CommonMixin, TestCase):
5235 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5236 @given(data_strategy())
5237 def test_sorted(self, d):
5239 tag_encode(tag) for tag in
5240 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5244 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5246 for name, _ in Seq.schema:
5247 seq[name] = OctetString(b"")
5248 seq_encoded = seq.encode()
5249 seq_decoded, _ = seq.decode(seq_encoded)
5250 self.assertSequenceEqual(
5251 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5252 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5255 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5256 @given(data_strategy())
5257 def test_unsorted(self, d):
5259 tag_encode(tag) for tag in
5260 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5262 tags = d.draw(permutations(tags))
5263 assume(tags != sorted(tags))
5264 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5265 seq_encoded = b"".join((
5267 len_encode(len(encoded)),
5272 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5274 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5275 seq.decode(seq_encoded)
5276 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5277 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5278 self.assertTrue(seq_decoded.ber_encoded)
5279 self.assertTrue(seq_decoded.bered)
5280 self.assertSequenceEqual(
5281 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5287 def seqof_values_strategy(draw, schema=None, do_expl=False):
5289 schema = draw(sampled_from((Boolean(), Integer())))
5290 bound_min, bound_max = sorted(draw(sets(
5291 integers(min_value=0, max_value=10),
5295 if isinstance(schema, Boolean):
5296 values_generator = booleans().map(Boolean)
5297 elif isinstance(schema, Integer):
5298 values_generator = integers().map(Integer)
5299 values_generator = lists(
5304 values = draw(one_of(none(), values_generator))
5308 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5310 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5311 default = draw(one_of(none(), values_generator))
5312 optional = draw(one_of(none(), booleans()))
5314 draw(integers(min_value=0)),
5315 draw(integers(min_value=0)),
5316 draw(integers(min_value=0)),
5321 (bound_min, bound_max),
5330 class SeqOfMixing(object):
5331 def test_invalid_value_type(self):
5332 with self.assertRaises(InvalidValueType) as err:
5333 self.base_klass(123)
5336 def test_invalid_values_type(self):
5337 class SeqOf(self.base_klass):
5339 with self.assertRaises(InvalidValueType) as err:
5340 SeqOf([Integer(123), Boolean(False), Integer(234)])
5343 def test_schema_required(self):
5344 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5345 self.base_klass.__mro__[1]()
5347 @given(booleans(), booleans(), binary(), binary())
5348 def test_comparison(self, value1, value2, tag1, tag2):
5349 class SeqOf(self.base_klass):
5351 obj1 = SeqOf([Boolean(value1)])
5352 obj2 = SeqOf([Boolean(value2)])
5353 self.assertEqual(obj1 == obj2, value1 == value2)
5354 self.assertEqual(obj1 != obj2, value1 != value2)
5355 self.assertEqual(obj1 == list(obj2), value1 == value2)
5356 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5357 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5358 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5359 self.assertEqual(obj1 == obj2, tag1 == tag2)
5360 self.assertEqual(obj1 != obj2, tag1 != tag2)
5362 @given(lists(booleans()))
5363 def test_iter(self, values):
5364 class SeqOf(self.base_klass):
5366 obj = SeqOf([Boolean(value) for value in values])
5367 self.assertEqual(len(obj), len(values))
5368 for i, value in enumerate(obj):
5369 self.assertEqual(value, values[i])
5371 @given(data_strategy())
5372 def test_ready(self, d):
5373 ready = [Integer(v) for v in d.draw(lists(
5380 range(d.draw(integers(min_value=1, max_value=5)))
5383 class SeqOf(self.base_klass):
5385 values = d.draw(permutations(ready + non_ready))
5387 for value in values:
5389 self.assertFalse(seqof.ready)
5392 pprint(seqof, big_blobs=True, with_decode_path=True)
5393 with self.assertRaises(ObjNotReady) as err:
5396 for i, value in enumerate(values):
5397 self.assertEqual(seqof[i], value)
5398 if not seqof[i].ready:
5399 seqof[i] = Integer(i)
5400 self.assertTrue(seqof.ready)
5403 pprint(seqof, big_blobs=True, with_decode_path=True)
5405 def test_spec_mismatch(self):
5406 class SeqOf(self.base_klass):
5409 seqof.append(Integer(123))
5410 with self.assertRaises(ValueError):
5411 seqof.append(Boolean(False))
5412 with self.assertRaises(ValueError):
5413 seqof[0] = Boolean(False)
5415 @given(data_strategy())
5416 def test_bounds_satisfied(self, d):
5417 class SeqOf(self.base_klass):
5419 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5420 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5421 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5422 SeqOf(value=value, bounds=(bound_min, bound_max))
5424 @given(data_strategy())
5425 def test_bounds_unsatisfied(self, d):
5426 class SeqOf(self.base_klass):
5428 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5429 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5430 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5431 with self.assertRaises(BoundsError) as err:
5432 SeqOf(value=value, bounds=(bound_min, bound_max))
5434 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5435 SeqOf(bounds=(bound_min, bound_max)).decode(
5436 SeqOf(value).encode()
5439 value = [Boolean(True)] * d.draw(integers(
5440 min_value=bound_max + 1,
5441 max_value=bound_max + 10,
5443 with self.assertRaises(BoundsError) as err:
5444 SeqOf(value=value, bounds=(bound_min, bound_max))
5446 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5447 SeqOf(bounds=(bound_min, bound_max)).decode(
5448 SeqOf(value).encode()
5452 @given(integers(min_value=1, max_value=10))
5453 def test_out_of_bounds(self, bound_max):
5454 class SeqOf(self.base_klass):
5456 bounds = (0, bound_max)
5458 for _ in range(bound_max):
5459 seqof.append(Integer(123))
5460 with self.assertRaises(BoundsError):
5461 seqof.append(Integer(123))
5463 @given(data_strategy())
5464 def test_call(self, d):
5474 ) = d.draw(seqof_values_strategy())
5476 class SeqOf(self.base_klass):
5477 schema = schema_initial
5478 obj_initial = SeqOf(
5479 value=value_initial,
5480 bounds=bounds_initial,
5483 default=default_initial,
5484 optional=optional_initial or False,
5485 _decoded=_decoded_initial,
5496 ) = d.draw(seqof_values_strategy(
5497 schema=schema_initial,
5498 do_expl=impl_initial is None,
5500 if (default is None) and (obj_initial.default is not None):
5503 (bounds is None) and
5504 (value is not None) and
5505 (bounds_initial is not None) and
5506 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5510 (bounds is None) and
5511 (default is not None) and
5512 (bounds_initial is not None) and
5513 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5525 value_expected = default if value is None else value
5527 default_initial if value_expected is None
5530 value_expected = () if value_expected is None else value_expected
5531 self.assertEqual(obj, value_expected)
5532 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5533 self.assertEqual(obj.expl_tag, expl or expl_initial)
5536 default_initial if default is None else default,
5538 if obj.default is None:
5539 optional = optional_initial if optional is None else optional
5540 optional = False if optional is None else optional
5543 self.assertEqual(obj.optional, optional)
5545 (obj._bound_min, obj._bound_max),
5546 bounds or bounds_initial or (0, float("+inf")),
5549 @given(seqof_values_strategy())
5550 def test_copy(self, values):
5551 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5553 class SeqOf(self.base_klass):
5561 optional=optional or False,
5564 obj_copied = obj.copy()
5565 self.assert_copied_basic_fields(obj, obj_copied)
5566 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5567 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5568 self.assertEqual(obj._value, obj_copied._value)
5572 integers(min_value=1).map(tag_encode),
5574 def test_stripped(self, values, tag_impl):
5575 class SeqOf(self.base_klass):
5576 schema = OctetString()
5577 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5578 with self.assertRaises(NotEnoughData):
5579 obj.decode(obj.encode()[:-1])
5583 integers(min_value=1).map(tag_ctxc),
5585 def test_stripped_expl(self, values, tag_expl):
5586 class SeqOf(self.base_klass):
5587 schema = OctetString()
5588 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5589 with self.assertRaises(NotEnoughData):
5590 obj.decode(obj.encode()[:-1])
5593 integers(min_value=31),
5594 integers(min_value=0),
5597 def test_bad_tag(self, tag, offset, decode_path):
5598 with self.assertRaises(DecodeError) as err:
5599 self.base_klass().decode(
5600 tag_encode(tag)[:-1],
5602 decode_path=decode_path,
5605 self.assertEqual(err.exception.offset, offset)
5606 self.assertEqual(err.exception.decode_path, decode_path)
5609 integers(min_value=128),
5610 integers(min_value=0),
5613 def test_bad_len(self, l, offset, decode_path):
5614 with self.assertRaises(DecodeError) as err:
5615 self.base_klass().decode(
5616 self.base_klass.tag_default + len_encode(l)[:-1],
5618 decode_path=decode_path,
5621 self.assertEqual(err.exception.offset, offset)
5622 self.assertEqual(err.exception.decode_path, decode_path)
5624 @given(binary(min_size=1))
5625 def test_tag_mismatch(self, impl):
5626 assume(impl != self.base_klass.tag_default)
5627 with self.assertRaises(TagMismatch):
5628 self.base_klass(impl=impl).decode(self.base_klass().encode())
5630 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5632 seqof_values_strategy(schema=Integer()),
5633 lists(integers().map(Integer)),
5634 integers(min_value=1).map(tag_ctxc),
5635 integers(min_value=0),
5638 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5639 _, _, _, _, _, default, optional, _decoded = values
5641 class SeqOf(self.base_klass):
5651 pprint(obj, big_blobs=True, with_decode_path=True)
5652 self.assertFalse(obj.expled)
5653 obj_encoded = obj.encode()
5654 obj_expled = obj(value, expl=tag_expl)
5655 self.assertTrue(obj_expled.expled)
5657 list(obj_expled.pps())
5658 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5659 obj_expled_encoded = obj_expled.encode()
5660 ctx_copied = deepcopy(ctx_dummy)
5661 obj_decoded, tail = obj_expled.decode(
5662 obj_expled_encoded + tail_junk,
5666 self.assertDictEqual(ctx_copied, ctx_dummy)
5668 list(obj_decoded.pps())
5669 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5670 self.assertEqual(tail, tail_junk)
5671 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5672 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5673 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5674 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5676 obj_decoded.expl_llen,
5677 len(len_encode(len(obj_encoded))),
5679 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5680 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5683 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5685 self.assertEqual(obj_decoded.expl_offset, offset)
5686 for obj_inner in obj_decoded:
5687 self.assertIn(obj_inner, obj_decoded)
5688 self.assertSequenceEqual(
5691 obj_inner.offset - offset:
5692 obj_inner.offset + obj_inner.tlvlen - offset
5696 t, _, lv = tag_strip(obj_encoded)
5697 _, _, v = len_decode(lv)
5698 obj_encoded_lenindef = t + LENINDEF + v + EOC
5699 obj_decoded_lenindef, tail_lenindef = obj.decode(
5700 obj_encoded_lenindef + tail_junk,
5701 ctx={"bered": True},
5703 self.assertTrue(obj_decoded_lenindef.lenindef)
5704 self.assertTrue(obj_decoded_lenindef.bered)
5705 repr(obj_decoded_lenindef)
5706 list(obj_decoded_lenindef.pps())
5707 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5708 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5709 with self.assertRaises(DecodeError):
5710 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5711 with self.assertRaises(DecodeError):
5712 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5714 @given(data_strategy())
5715 def test_bered(self, d):
5716 class SeqOf(self.base_klass):
5718 encoded = Boolean(False).encode()
5719 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5720 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5721 with self.assertRaises(DecodeError):
5722 SeqOf().decode(encoded)
5723 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5724 self.assertFalse(decoded.ber_encoded)
5725 self.assertFalse(decoded.lenindef)
5726 self.assertTrue(decoded.bered)
5728 class SeqOf(self.base_klass):
5729 schema = OctetString()
5730 encoded = OctetString(b"whatever").encode()
5732 tag_encode(form=TagFormConstructed, num=4) +
5734 OctetString(b"whatever").encode() +
5737 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5738 with self.assertRaises(DecodeError):
5739 SeqOf().decode(encoded)
5740 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5741 self.assertFalse(decoded.ber_encoded)
5742 self.assertFalse(decoded.lenindef)
5743 self.assertTrue(decoded.bered)
5746 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5747 class SeqOf(SequenceOf):
5751 def _test_symmetric_compare_objs(self, obj1, obj2):
5752 self.assertEqual(obj1, obj2)
5753 self.assertSequenceEqual(list(obj1), list(obj2))
5756 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5761 def _test_symmetric_compare_objs(self, obj1, obj2):
5762 self.assertSetEqual(
5763 set(int(v) for v in obj1),
5764 set(int(v) for v in obj2),
5767 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5768 @given(data_strategy())
5769 def test_sorted(self, d):
5770 values = [OctetString(v) for v in d.draw(lists(binary()))]
5773 schema = OctetString()
5775 seq_encoded = seq.encode()
5776 seq_decoded, _ = seq.decode(seq_encoded)
5777 self.assertSequenceEqual(
5778 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5779 b"".join(sorted([v.encode() for v in values])),
5782 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5783 @given(data_strategy())
5784 def test_unsorted(self, d):
5785 values = [OctetString(v).encode() for v in d.draw(sets(
5786 binary(min_size=1, max_size=5),
5790 values = d.draw(permutations(values))
5791 assume(values != sorted(values))
5792 encoded = b"".join(values)
5793 seq_encoded = b"".join((
5795 len_encode(len(encoded)),
5800 schema = OctetString()
5802 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5803 seq.decode(seq_encoded)
5805 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5806 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5807 self.assertTrue(seq_decoded.ber_encoded)
5808 self.assertTrue(seq_decoded.bered)
5809 self.assertSequenceEqual(
5810 [obj.encode() for obj in seq_decoded],
5815 class TestGoMarshalVectors(TestCase):
5817 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5818 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5819 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5820 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5821 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5823 class Seq(Sequence):
5825 ("erste", Integer()),
5826 ("zweite", Integer(optional=True))
5829 seq["erste"] = Integer(64)
5830 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5831 seq["erste"] = Integer(0x123456)
5832 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5833 seq["erste"] = Integer(64)
5834 seq["zweite"] = Integer(65)
5835 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5837 class NestedSeq(Sequence):
5841 seq["erste"] = Integer(127)
5842 seq["zweite"] = None
5843 nested = NestedSeq()
5844 nested["nest"] = seq
5845 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5847 self.assertSequenceEqual(
5848 OctetString(b"\x01\x02\x03").encode(),
5849 hexdec("0403010203"),
5852 class Seq(Sequence):
5854 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5857 seq["erste"] = Integer(64)
5858 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5860 class Seq(Sequence):
5862 ("erste", Integer(expl=tag_ctxc(5))),
5865 seq["erste"] = Integer(64)
5866 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5868 class Seq(Sequence):
5871 impl=tag_encode(0, klass=TagClassContext),
5876 seq["erste"] = Null()
5877 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5879 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5881 self.assertSequenceEqual(
5882 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5883 hexdec("170d3730303130313030303030305a"),
5885 self.assertSequenceEqual(
5886 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5887 hexdec("170d3039313131353232353631365a"),
5889 self.assertSequenceEqual(
5890 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5891 hexdec("180f32313030303430353132303130315a"),
5894 class Seq(Sequence):
5896 ("erste", GeneralizedTime()),
5899 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5900 self.assertSequenceEqual(
5902 hexdec("3011180f32303039313131353232353631365a"),
5905 self.assertSequenceEqual(
5906 BitString((1, b"\x80")).encode(),
5909 self.assertSequenceEqual(
5910 BitString((12, b"\x81\xF0")).encode(),
5911 hexdec("03030481f0"),
5914 self.assertSequenceEqual(
5915 ObjectIdentifier("1.2.3.4").encode(),
5916 hexdec("06032a0304"),
5918 self.assertSequenceEqual(
5919 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5920 hexdec("06092a864888932d010105"),
5922 self.assertSequenceEqual(
5923 ObjectIdentifier("2.100.3").encode(),
5924 hexdec("0603813403"),
5927 self.assertSequenceEqual(
5928 PrintableString("test").encode(),
5929 hexdec("130474657374"),
5931 self.assertSequenceEqual(
5932 PrintableString("x" * 127).encode(),
5933 hexdec("137F" + "78" * 127),
5935 self.assertSequenceEqual(
5936 PrintableString("x" * 128).encode(),
5937 hexdec("138180" + "78" * 128),
5939 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5941 class Seq(Sequence):
5943 ("erste", IA5String()),
5946 seq["erste"] = IA5String("test")
5947 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5949 class Seq(Sequence):
5951 ("erste", PrintableString()),
5954 seq["erste"] = PrintableString("test")
5955 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5956 # Asterisk is actually not allowable
5957 PrintableString._allowable_chars |= set(b"*")
5958 seq["erste"] = PrintableString("test*")
5959 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5960 PrintableString._allowable_chars -= set(b"*")
5962 class Seq(Sequence):
5964 ("erste", Any(optional=True)),
5965 ("zweite", Integer()),
5968 seq["zweite"] = Integer(64)
5969 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5974 seq.append(Integer(10))
5975 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5977 class _SeqOf(SequenceOf):
5978 schema = PrintableString()
5980 class SeqOf(SequenceOf):
5983 _seqof.append(PrintableString("1"))
5985 seqof.append(_seqof)
5986 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5988 class Seq(Sequence):
5990 ("erste", Integer(default=1)),
5993 seq["erste"] = Integer(0)
5994 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5995 seq["erste"] = Integer(1)
5996 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5997 seq["erste"] = Integer(2)
5998 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6001 class TestPP(TestCase):
6002 @given(data_strategy())
6003 def test_oid_printing(self, d):
6005 str(ObjectIdentifier(k)): v * 2
6006 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6008 chosen = d.draw(sampled_from(sorted(oids)))
6009 chosen_id = oids[chosen]
6010 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6011 self.assertNotIn(chosen_id, pp_console_row(pp))
6012 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
6015 class TestAutoAddSlots(TestCase):
6017 class Inher(Integer):
6020 with self.assertRaises(AttributeError):
6022 inher.unexistent = "whatever"
6025 class TestOIDDefines(TestCase):
6026 @given(data_strategy())
6027 def runTest(self, d):
6028 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6029 value_name_chosen = d.draw(sampled_from(value_names))
6031 ObjectIdentifier(oid)
6032 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6034 oid_chosen = d.draw(sampled_from(oids))
6035 values = d.draw(lists(
6037 min_size=len(value_names),
6038 max_size=len(value_names),
6041 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6042 oid: Integer() for oid in oids[:-1]
6045 for i, value_name in enumerate(value_names):
6046 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6048 class Seq(Sequence):
6051 for value_name, value in zip(value_names, values):
6052 seq[value_name] = Any(Integer(value).encode())
6053 seq["type"] = oid_chosen
6054 seq, _ = Seq().decode(seq.encode())
6055 for value_name in value_names:
6056 if value_name == value_name_chosen:
6058 self.assertIsNone(seq[value_name].defined)
6059 if value_name_chosen in oids[:-1]:
6060 self.assertIsNotNone(seq[value_name_chosen].defined)
6061 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6062 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6065 pprint(seq, big_blobs=True, with_decode_path=True)
6068 class TestDefinesByPath(TestCase):
6069 def test_generated(self):
6070 class Seq(Sequence):
6072 ("type", ObjectIdentifier()),
6073 ("value", OctetString(expl=tag_ctxc(123))),
6076 class SeqInner(Sequence):
6078 ("typeInner", ObjectIdentifier()),
6079 ("valueInner", Any()),
6082 class PairValue(SetOf):
6085 class Pair(Sequence):
6087 ("type", ObjectIdentifier()),
6088 ("value", PairValue()),
6091 class Pairs(SequenceOf):
6098 type_octet_stringed,
6100 ObjectIdentifier(oid)
6101 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6103 seq_integered = Seq()
6104 seq_integered["type"] = type_integered
6105 seq_integered["value"] = OctetString(Integer(123).encode())
6106 seq_integered_raw = seq_integered.encode()
6110 (type_octet_stringed, OctetString(b"whatever")),
6111 (type_integered, Integer(123)),
6112 (type_octet_stringed, OctetString(b"whenever")),
6113 (type_integered, Integer(234)),
6115 for t, v in pairs_input:
6118 pair["value"] = PairValue((Any(v),))
6120 seq_inner = SeqInner()
6121 seq_inner["typeInner"] = type_innered
6122 seq_inner["valueInner"] = Any(pairs)
6123 seq_sequenced = Seq()
6124 seq_sequenced["type"] = type_sequenced
6125 seq_sequenced["value"] = OctetString(seq_inner.encode())
6126 seq_sequenced_raw = seq_sequenced.encode()
6128 list(seq_sequenced.pps())
6129 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6131 defines_by_path = []
6132 ctx_copied = deepcopy(ctx_dummy)
6133 seq_integered, _ = Seq().decode(
6137 self.assertDictEqual(ctx_copied, ctx_dummy)
6138 self.assertIsNone(seq_integered["value"].defined)
6139 defines_by_path.append(
6140 (("type",), ((("value",), {
6141 type_integered: Integer(),
6142 type_sequenced: SeqInner(),
6145 ctx_copied["defines_by_path"] = defines_by_path
6146 seq_integered, _ = Seq().decode(
6150 del ctx_copied["defines_by_path"]
6151 self.assertDictEqual(ctx_copied, ctx_dummy)
6152 self.assertIsNotNone(seq_integered["value"].defined)
6153 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6154 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6155 self.assertTrue(seq_integered_raw[
6156 seq_integered["value"].defined[1].offset:
6157 ].startswith(Integer(123).encode()))
6159 list(seq_integered.pps())
6160 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6162 ctx_copied["defines_by_path"] = defines_by_path
6163 seq_sequenced, _ = Seq().decode(
6167 del ctx_copied["defines_by_path"]
6168 self.assertDictEqual(ctx_copied, ctx_dummy)
6169 self.assertIsNotNone(seq_sequenced["value"].defined)
6170 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6171 seq_inner = seq_sequenced["value"].defined[1]
6172 self.assertIsNone(seq_inner["valueInner"].defined)
6174 list(seq_sequenced.pps())
6175 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6177 defines_by_path.append((
6178 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6179 ((("valueInner",), {type_innered: Pairs()}),),
6181 ctx_copied["defines_by_path"] = defines_by_path
6182 seq_sequenced, _ = Seq().decode(
6186 del ctx_copied["defines_by_path"]
6187 self.assertDictEqual(ctx_copied, ctx_dummy)
6188 self.assertIsNotNone(seq_sequenced["value"].defined)
6189 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6190 seq_inner = seq_sequenced["value"].defined[1]
6191 self.assertIsNotNone(seq_inner["valueInner"].defined)
6192 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6193 pairs = seq_inner["valueInner"].defined[1]
6195 self.assertIsNone(pair["value"][0].defined)
6197 list(seq_sequenced.pps())
6198 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6200 defines_by_path.append((
6203 DecodePathDefBy(type_sequenced),
6205 DecodePathDefBy(type_innered),
6210 type_integered: Integer(),
6211 type_octet_stringed: OctetString(),
6214 ctx_copied["defines_by_path"] = defines_by_path
6215 seq_sequenced, _ = Seq().decode(
6219 del ctx_copied["defines_by_path"]
6220 self.assertDictEqual(ctx_copied, ctx_dummy)
6221 self.assertIsNotNone(seq_sequenced["value"].defined)
6222 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6223 seq_inner = seq_sequenced["value"].defined[1]
6224 self.assertIsNotNone(seq_inner["valueInner"].defined)
6225 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6226 pairs_got = seq_inner["valueInner"].defined[1]
6227 for pair_input, pair_got in zip(pairs_input, pairs_got):
6228 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6229 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6231 list(seq_sequenced.pps())
6232 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6234 @given(oid_strategy(), integers())
6235 def test_simple(self, oid, tgt):
6236 class Inner(Sequence):
6238 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6239 ObjectIdentifier(oid): Integer(),
6243 class Outer(Sequence):
6246 ("tgt", OctetString()),
6250 inner["oid"] = ObjectIdentifier(oid)
6252 outer["inner"] = inner
6253 outer["tgt"] = OctetString(Integer(tgt).encode())
6254 decoded, _ = Outer().decode(outer.encode())
6255 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6258 class TestAbsDecodePath(TestCase):
6260 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6261 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6263 def test_concat(self, decode_path, rel_path):
6264 self.assertSequenceEqual(
6265 abs_decode_path(decode_path, rel_path),
6266 decode_path + rel_path,
6270 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6271 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6273 def test_abs(self, decode_path, rel_path):
6274 self.assertSequenceEqual(
6275 abs_decode_path(decode_path, ("/",) + rel_path),
6280 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6281 integers(min_value=1, max_value=3),
6282 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6284 def test_dots(self, decode_path, number_of_dots, rel_path):
6285 self.assertSequenceEqual(
6286 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6287 decode_path[:-number_of_dots] + rel_path,
6291 class TestStrictDefaultExistence(TestCase):
6292 @given(data_strategy())
6293 def runTest(self, d):
6294 count = d.draw(integers(min_value=1, max_value=10))
6295 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6297 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6298 for i in range(count)
6300 for klass in (Sequence, Set):
6304 for i in range(count):
6305 seq["int%d" % i] = Integer(123)
6307 chosen_choice = "int%d" % chosen
6308 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6309 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6311 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6312 self.assertTrue(decoded.ber_encoded)
6313 self.assertTrue(decoded.bered)
6314 decoded, _ = seq.decode(raw, ctx={"bered": True})
6315 self.assertTrue(decoded.ber_encoded)
6316 self.assertTrue(decoded.bered)
6319 class TestX690PrefixedType(TestCase):
6321 self.assertSequenceEqual(
6322 VisibleString("Jones").encode(),
6323 hexdec("1A054A6F6E6573"),
6325 self.assertSequenceEqual(
6328 impl=tag_encode(3, klass=TagClassApplication),
6330 hexdec("43054A6F6E6573"),
6332 self.assertSequenceEqual(
6336 impl=tag_encode(3, klass=TagClassApplication),
6340 hexdec("A20743054A6F6E6573"),
6342 self.assertSequenceEqual(
6346 impl=tag_encode(3, klass=TagClassApplication),
6348 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6350 hexdec("670743054A6F6E6573"),
6352 self.assertSequenceEqual(
6353 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6354 hexdec("82054A6F6E6573"),
6358 class TestExplOOB(TestCase):
6360 expl = tag_ctxc(123)
6361 raw = Integer(123).encode() + Integer(234).encode()
6362 raw = b"".join((expl, len_encode(len(raw)), raw))
6363 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6364 Integer(expl=expl).decode(raw)
6365 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})