2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from copy import deepcopy
20 from datetime import datetime
21 from string import ascii_letters
22 from string import digits
23 from string import printable
24 from string import whitespace
25 from unittest import TestCase
27 from hypothesis import assume
28 from hypothesis import given
29 from hypothesis import settings
30 from hypothesis.strategies import binary
31 from hypothesis.strategies import booleans
32 from hypothesis.strategies import composite
33 from hypothesis.strategies import data as data_strategy
34 from hypothesis.strategies import datetimes
35 from hypothesis.strategies import dictionaries
36 from hypothesis.strategies import integers
37 from hypothesis.strategies import just
38 from hypothesis.strategies import lists
39 from hypothesis.strategies import none
40 from hypothesis.strategies import one_of
41 from hypothesis.strategies import permutations
42 from hypothesis.strategies import sampled_from
43 from hypothesis.strategies import sets
44 from hypothesis.strategies import text
45 from hypothesis.strategies import tuples
46 from six import assertRaisesRegex
47 from six import binary_type
48 from six import byte2int
49 from six import indexbytes
50 from six import int2byte
51 from six import iterbytes
53 from six import text_type
54 from six import unichr as six_unichr
56 from pyderasn import _pp
57 from pyderasn import abs_decode_path
58 from pyderasn import Any
59 from pyderasn import BitString
60 from pyderasn import BMPString
61 from pyderasn import Boolean
62 from pyderasn import BoundsError
63 from pyderasn import Choice
64 from pyderasn import DecodeError
65 from pyderasn import DecodePathDefBy
66 from pyderasn import Enumerated
67 from pyderasn import EOC
68 from pyderasn import EOC_LEN
69 from pyderasn import GeneralizedTime
70 from pyderasn import GeneralString
71 from pyderasn import GraphicString
72 from pyderasn import hexdec
73 from pyderasn import hexenc
74 from pyderasn import IA5String
75 from pyderasn import Integer
76 from pyderasn import InvalidLength
77 from pyderasn import InvalidOID
78 from pyderasn import InvalidValueType
79 from pyderasn import len_decode
80 from pyderasn import len_encode
81 from pyderasn import LEN_YYMMDDHHMMSSZ
82 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
83 from pyderasn import LEN_YYYYMMDDHHMMSSZ
84 from pyderasn import LENINDEF
85 from pyderasn import LenIndefForm
86 from pyderasn import NotEnoughData
87 from pyderasn import Null
88 from pyderasn import NumericString
89 from pyderasn import ObjectIdentifier
90 from pyderasn import ObjNotReady
91 from pyderasn import ObjUnknown
92 from pyderasn import OctetString
93 from pyderasn import pp_console_row
94 from pyderasn import pprint
95 from pyderasn import PrintableString
96 from pyderasn import Sequence
97 from pyderasn import SequenceOf
98 from pyderasn import Set
99 from pyderasn import SetOf
100 from pyderasn import tag_ctxc
101 from pyderasn import tag_ctxp
102 from pyderasn import tag_decode
103 from pyderasn import tag_encode
104 from pyderasn import tag_strip
105 from pyderasn import TagClassApplication
106 from pyderasn import TagClassContext
107 from pyderasn import TagClassPrivate
108 from pyderasn import TagClassUniversal
109 from pyderasn import TagFormConstructed
110 from pyderasn import TagFormPrimitive
111 from pyderasn import TagMismatch
112 from pyderasn import TeletexString
113 from pyderasn import UniversalString
114 from pyderasn import UTCTime
115 from pyderasn import UTF8String
116 from pyderasn import VideotexString
117 from pyderasn import VisibleString
120 settings.register_profile("local", settings(
123 settings.load_profile("local")
124 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
126 tag_classes = sampled_from((
132 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
133 decode_path_strat = lists(integers(), max_size=3).map(
134 lambda decode_path: tuple(str(dp) for dp in decode_path)
136 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
139 class TestHex(TestCase):
141 def test_symmetric(self, data):
142 self.assertEqual(hexdec(hexenc(data)), data)
145 class TestTagCoder(TestCase):
146 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
150 integers(min_value=0, max_value=30),
153 def test_short(self, klass, form, num, junk):
154 raw = tag_encode(klass=klass, form=form, num=num)
155 self.assertEqual(tag_decode(raw), (klass, form, num))
156 self.assertEqual(len(raw), 1)
158 byte2int(tag_encode(klass=klass, form=form, num=0)),
159 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
161 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
162 self.assertSequenceEqual(stripped.tobytes(), raw)
163 self.assertEqual(tlen, len(raw))
164 self.assertSequenceEqual(tail, junk)
166 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
170 integers(min_value=31),
173 def test_long(self, klass, form, num, junk):
174 raw = tag_encode(klass=klass, form=form, num=num)
175 self.assertEqual(tag_decode(raw), (klass, form, num))
176 self.assertGreater(len(raw), 1)
178 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
181 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
182 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
183 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
184 self.assertSequenceEqual(stripped.tobytes(), raw)
185 self.assertEqual(tlen, len(raw))
186 self.assertSequenceEqual(tail, junk)
188 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
189 @given(integers(min_value=31))
190 def test_unfinished_tag(self, num):
191 raw = bytearray(tag_encode(num=num))
192 for i in range(1, len(raw)):
194 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
195 tag_strip(bytes(raw))
197 def test_go_vectors_valid(self):
198 for data, (eklass, etag, elen, eform) in (
199 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
200 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
201 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
202 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
203 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
204 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
205 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
206 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
207 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
208 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
210 tag, _, len_encoded = tag_strip(memoryview(data))
211 klass, form, num = tag_decode(tag)
212 _len, _, tail = len_decode(len_encoded)
213 self.assertSequenceEqual(tail, b"")
214 self.assertEqual(klass, eklass)
215 self.assertEqual(num, etag)
216 self.assertEqual(_len, elen)
217 self.assertEqual(form, eform)
219 def test_go_vectors_invalid(self):
227 with self.assertRaises(DecodeError):
228 _, _, len_encoded = tag_strip(memoryview(data))
229 len_decode(len_encoded)
232 integers(min_value=0, max_value=127),
233 integers(min_value=0, max_value=2),
235 def test_long_instead_of_short(self, l, dummy_num):
236 octets = (b"\x00" * dummy_num) + int2byte(l)
237 octets = int2byte((dummy_num + 1) | 0x80) + octets
238 with self.assertRaises(DecodeError):
242 class TestLenCoder(TestCase):
243 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
245 integers(min_value=0, max_value=127),
248 def test_short(self, l, junk):
249 raw = len_encode(l) + junk
250 decoded, llen, tail = len_decode(memoryview(raw))
251 self.assertEqual(decoded, l)
252 self.assertEqual(llen, 1)
253 self.assertEqual(len(raw), 1 + len(junk))
254 self.assertEqual(tail.tobytes(), junk)
256 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
258 integers(min_value=128),
261 def test_long(self, l, junk):
262 raw = len_encode(l) + junk
263 decoded, llen, tail = len_decode(memoryview(raw))
264 self.assertEqual(decoded, l)
265 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
266 self.assertEqual(llen, len(raw) - len(junk))
267 self.assertNotEqual(indexbytes(raw, 1), 0)
268 self.assertSequenceEqual(tail.tobytes(), junk)
270 def test_empty(self):
271 with self.assertRaises(NotEnoughData):
274 @given(integers(min_value=128))
275 def test_stripped(self, _len):
276 with self.assertRaises(NotEnoughData):
277 len_decode(len_encode(_len)[:-1])
280 text_printable = text(alphabet=printable, min_size=1)
284 def text_letters(draw):
285 result = draw(text(alphabet=ascii_letters, min_size=1))
287 result = result.encode("ascii")
291 class CommonMixin(object):
292 def test_tag_default(self):
293 obj = self.base_klass()
294 self.assertEqual(obj.tag, obj.tag_default)
296 def test_simultaneous_impl_expl(self):
297 with self.assertRaises(ValueError):
298 self.base_klass(impl=b"whatever", expl=b"whenever")
300 @given(binary(min_size=1), integers(), integers(), integers())
301 def test_decoded(self, impl, offset, llen, vlen):
302 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
303 self.assertEqual(obj.offset, offset)
304 self.assertEqual(obj.llen, llen)
305 self.assertEqual(obj.vlen, vlen)
306 self.assertEqual(obj.tlen, len(impl))
307 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
309 @given(binary(min_size=1))
310 def test_impl_inherited(self, impl_tag):
311 class Inherited(self.base_klass):
314 self.assertSequenceEqual(obj.impl, impl_tag)
315 self.assertFalse(obj.expled)
318 def test_expl_inherited(self, expl_tag):
319 class Inherited(self.base_klass):
322 self.assertSequenceEqual(obj.expl, expl_tag)
323 self.assertTrue(obj.expled)
325 def assert_copied_basic_fields(self, obj, obj_copied):
326 self.assertEqual(obj, obj_copied)
327 self.assertSequenceEqual(obj.tag, obj_copied.tag)
328 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
329 self.assertEqual(obj.default, obj_copied.default)
330 self.assertEqual(obj.optional, obj_copied.optional)
331 self.assertEqual(obj.offset, obj_copied.offset)
332 self.assertEqual(obj.llen, obj_copied.llen)
333 self.assertEqual(obj.vlen, obj_copied.vlen)
337 def boolean_values_strategy(draw, do_expl=False):
338 value = draw(one_of(none(), booleans()))
342 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
344 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
345 default = draw(one_of(none(), booleans()))
346 optional = draw(one_of(none(), booleans()))
348 draw(integers(min_value=0)),
349 draw(integers(min_value=0)),
350 draw(integers(min_value=0)),
352 return (value, impl, expl, default, optional, _decoded)
355 class BooleanInherited(Boolean):
359 class TestBoolean(CommonMixin, TestCase):
362 def test_invalid_value_type(self):
363 with self.assertRaises(InvalidValueType) as err:
368 def test_optional(self, optional):
369 obj = Boolean(default=Boolean(False), optional=optional)
370 self.assertTrue(obj.optional)
373 def test_ready(self, value):
375 self.assertFalse(obj.ready)
378 pprint(obj, big_blobs=True, with_decode_path=True)
379 with self.assertRaises(ObjNotReady) as err:
383 self.assertTrue(obj.ready)
386 pprint(obj, big_blobs=True, with_decode_path=True)
388 @given(booleans(), booleans(), binary(), binary())
389 def test_comparison(self, value1, value2, tag1, tag2):
390 for klass in (Boolean, BooleanInherited):
393 self.assertEqual(obj1 == obj2, value1 == value2)
394 self.assertEqual(obj1 != obj2, value1 != value2)
395 self.assertEqual(obj1 == bool(obj2), value1 == value2)
396 obj1 = klass(value1, impl=tag1)
397 obj2 = klass(value1, impl=tag2)
398 self.assertEqual(obj1 == obj2, tag1 == tag2)
399 self.assertEqual(obj1 != obj2, tag1 != tag2)
401 @given(data_strategy())
402 def test_call(self, d):
403 for klass in (Boolean, BooleanInherited):
411 ) = d.draw(boolean_values_strategy())
417 optional_initial or False,
427 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
428 obj = obj_initial(value, impl, expl, default, optional)
430 value_expected = default if value is None else value
432 default_initial if value_expected is None
435 self.assertEqual(obj, value_expected)
436 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
437 self.assertEqual(obj.expl_tag, expl or expl_initial)
440 default_initial if default is None else default,
442 if obj.default is None:
443 optional = optional_initial if optional is None else optional
444 optional = False if optional is None else optional
447 self.assertEqual(obj.optional, optional)
449 @given(boolean_values_strategy())
450 def test_copy(self, values):
451 for klass in (Boolean, BooleanInherited):
453 obj_copied = obj.copy()
454 self.assert_copied_basic_fields(obj, obj_copied)
458 integers(min_value=1).map(tag_encode),
460 def test_stripped(self, value, tag_impl):
461 obj = Boolean(value, impl=tag_impl)
462 with self.assertRaises(NotEnoughData):
463 obj.decode(obj.encode()[:-1])
467 integers(min_value=1).map(tag_ctxc),
469 def test_stripped_expl(self, value, tag_expl):
470 obj = Boolean(value, expl=tag_expl)
471 with self.assertRaises(NotEnoughData):
472 obj.decode(obj.encode()[:-1])
475 integers(min_value=31),
476 integers(min_value=0),
479 def test_bad_tag(self, tag, offset, decode_path):
480 with self.assertRaises(DecodeError) as err:
482 tag_encode(tag)[:-1],
484 decode_path=decode_path,
487 self.assertEqual(err.exception.offset, offset)
488 self.assertEqual(err.exception.decode_path, decode_path)
491 integers(min_value=31),
492 integers(min_value=0),
495 def test_bad_expl_tag(self, tag, offset, decode_path):
496 with self.assertRaises(DecodeError) as err:
497 Boolean(expl=Boolean.tag_default).decode(
498 tag_encode(tag)[:-1],
500 decode_path=decode_path,
503 self.assertEqual(err.exception.offset, offset)
504 self.assertEqual(err.exception.decode_path, decode_path)
507 integers(min_value=128),
508 integers(min_value=0),
511 def test_bad_len(self, l, offset, decode_path):
512 with self.assertRaises(DecodeError) as err:
514 Boolean.tag_default + len_encode(l)[:-1],
516 decode_path=decode_path,
519 self.assertEqual(err.exception.offset, offset)
520 self.assertEqual(err.exception.decode_path, decode_path)
523 integers(min_value=128),
524 integers(min_value=0),
527 def test_bad_expl_len(self, l, offset, decode_path):
528 with self.assertRaises(DecodeError) as err:
529 Boolean(expl=Boolean.tag_default).decode(
530 Boolean.tag_default + len_encode(l)[:-1],
532 decode_path=decode_path,
535 self.assertEqual(err.exception.offset, offset)
536 self.assertEqual(err.exception.decode_path, decode_path)
538 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
540 boolean_values_strategy(),
542 integers(min_value=1).map(tag_ctxc),
543 integers(min_value=0),
546 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
547 for klass in (Boolean, BooleanInherited):
548 _, _, _, default, optional, _decoded = values
557 pprint(obj, big_blobs=True, with_decode_path=True)
558 self.assertFalse(obj.expled)
559 obj_encoded = obj.encode()
560 obj_expled = obj(value, expl=tag_expl)
561 self.assertTrue(obj_expled.expled)
563 list(obj_expled.pps())
564 pprint(obj_expled, big_blobs=True, with_decode_path=True)
565 obj_expled_encoded = obj_expled.encode()
566 ctx_copied = deepcopy(ctx_dummy)
567 obj_decoded, tail = obj_expled.decode(
568 obj_expled_encoded + tail_junk,
572 self.assertDictEqual(ctx_copied, ctx_dummy)
574 list(obj_decoded.pps())
575 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
576 self.assertEqual(tail, tail_junk)
577 self.assertEqual(obj_decoded, obj_expled)
578 self.assertNotEqual(obj_decoded, obj)
579 self.assertEqual(bool(obj_decoded), bool(obj_expled))
580 self.assertEqual(bool(obj_decoded), bool(obj))
581 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
582 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
583 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
585 obj_decoded.expl_llen,
586 len(len_encode(len(obj_encoded))),
588 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
589 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
592 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
594 self.assertEqual(obj_decoded.expl_offset, offset)
596 @given(integers(min_value=2))
597 def test_invalid_len(self, l):
598 with self.assertRaises(InvalidLength):
599 Boolean().decode(b"".join((
605 @given(integers(min_value=0 + 1, max_value=255 - 1))
606 def test_ber_value(self, value):
607 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
608 Boolean().decode(b"".join((
613 obj, _ = Boolean().decode(
621 self.assertTrue(bool(obj))
622 self.assertTrue(obj.ber_encoded)
623 self.assertFalse(obj.lenindef)
624 self.assertTrue(obj.bered)
627 integers(min_value=1).map(tag_ctxc),
628 binary().filter(lambda x: not x.startswith(EOC)),
630 def test_ber_expl_no_eoc(self, expl, junk):
631 encoded = expl + LENINDEF + Boolean(False).encode()
632 with self.assertRaises(LenIndefForm):
633 Boolean(expl=expl).decode(encoded + junk)
634 with assertRaisesRegex(self, DecodeError, "no EOC"):
635 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
636 obj, tail = Boolean(expl=expl).decode(
637 encoded + EOC + junk,
640 self.assertTrue(obj.expl_lenindef)
641 self.assertFalse(obj.lenindef)
642 self.assertFalse(obj.ber_encoded)
643 self.assertTrue(obj.bered)
644 self.assertSequenceEqual(tail, junk)
647 pprint(obj, big_blobs=True, with_decode_path=True)
650 integers(min_value=1).map(tag_ctxc),
657 def test_ber_expl(self, expl, values):
663 Boolean(value).encode() +
666 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
668 class SeqOf(SequenceOf):
669 schema = Boolean(expl=expl)
670 with self.assertRaises(LenIndefForm):
671 SeqOf().decode(encoded)
672 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
673 self.assertSequenceEqual(tail, b"")
674 self.assertSequenceEqual([bool(v) for v in seqof], values)
690 len(expl) + 1 + 3 + EOC_LEN,
701 pprint(seqof, big_blobs=True, with_decode_path=True)
705 def integer_values_strategy(draw, do_expl=False):
706 bound_min, value, default, bound_max = sorted(draw(sets(
715 _specs = draw(sets(text_letters()))
718 min_size=len(_specs),
719 max_size=len(_specs),
721 _specs = list(zip(_specs, values))
724 bounds = (bound_min, bound_max)
728 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
730 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
733 optional = draw(one_of(none(), booleans()))
735 draw(integers(min_value=0)),
736 draw(integers(min_value=0)),
737 draw(integers(min_value=0)),
739 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
742 class IntegerInherited(Integer):
746 class TestInteger(CommonMixin, TestCase):
749 def test_invalid_value_type(self):
750 with self.assertRaises(InvalidValueType) as err:
754 @given(sets(text_letters(), min_size=2))
755 def test_unknown_name(self, names_input):
756 missing = names_input.pop()
759 schema = [(n, 123) for n in names_input]
760 with self.assertRaises(ObjUnknown) as err:
764 @given(sets(text_letters(), min_size=2))
765 def test_known_name(self, names_input):
767 schema = [(n, 123) for n in names_input]
768 Int(names_input.pop())
771 def test_optional(self, optional):
772 obj = Integer(default=Integer(0), optional=optional)
773 self.assertTrue(obj.optional)
776 def test_ready(self, value):
778 self.assertFalse(obj.ready)
781 pprint(obj, big_blobs=True, with_decode_path=True)
782 with self.assertRaises(ObjNotReady) as err:
786 self.assertTrue(obj.ready)
789 pprint(obj, big_blobs=True, with_decode_path=True)
792 @given(integers(), integers(), binary(), binary())
793 def test_comparison(self, value1, value2, tag1, tag2):
794 for klass in (Integer, IntegerInherited):
797 self.assertEqual(obj1 == obj2, value1 == value2)
798 self.assertEqual(obj1 != obj2, value1 != value2)
799 self.assertEqual(obj1 == int(obj2), value1 == value2)
800 obj1 = klass(value1, impl=tag1)
801 obj2 = klass(value1, impl=tag2)
802 self.assertEqual(obj1 == obj2, tag1 == tag2)
803 self.assertEqual(obj1 != obj2, tag1 != tag2)
805 @given(lists(integers()))
806 def test_sorted_works(self, values):
807 self.assertSequenceEqual(
808 [int(v) for v in sorted(Integer(v) for v in values)],
812 @given(data_strategy())
813 def test_named(self, d):
814 names_input = list(d.draw(sets(text_letters(), min_size=1)))
815 values_input = list(d.draw(sets(
817 min_size=len(names_input),
818 max_size=len(names_input),
820 chosen_name = d.draw(sampled_from(names_input))
821 names_input = dict(zip(names_input, values_input))
825 _int = Int(chosen_name)
826 self.assertEqual(_int.named, chosen_name)
827 self.assertEqual(int(_int), names_input[chosen_name])
829 @given(integers(), integers(min_value=0), integers(min_value=0))
830 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
831 value = bound_min + value_delta
832 bound_max = value + bound_delta
833 Integer(value=value, bounds=(bound_min, bound_max))
835 @given(sets(integers(), min_size=3, max_size=3))
836 def test_bounds_unsatisfied(self, values):
837 values = sorted(values)
838 with self.assertRaises(BoundsError) as err:
839 Integer(value=values[0], bounds=(values[1], values[2]))
841 with assertRaisesRegex(self, DecodeError, "bounds") as err:
842 Integer(bounds=(values[1], values[2])).decode(
843 Integer(values[0]).encode()
846 with self.assertRaises(BoundsError) as err:
847 Integer(value=values[2], bounds=(values[0], values[1]))
849 with assertRaisesRegex(self, DecodeError, "bounds") as err:
850 Integer(bounds=(values[0], values[1])).decode(
851 Integer(values[2]).encode()
855 @given(data_strategy())
856 def test_call(self, d):
857 for klass in (Integer, IntegerInherited):
867 ) = d.draw(integer_values_strategy())
874 optional_initial or False,
887 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
888 if (default is None) and (obj_initial.default is not None):
892 (value is not None) and
893 (bounds_initial is not None) and
894 not (bounds_initial[0] <= value <= bounds_initial[1])
899 (default is not None) and
900 (bounds_initial is not None) and
901 not (bounds_initial[0] <= default <= bounds_initial[1])
904 obj = obj_initial(value, bounds, impl, expl, default, optional)
906 value_expected = default if value is None else value
908 default_initial if value_expected is None
911 self.assertEqual(obj, value_expected)
912 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
913 self.assertEqual(obj.expl_tag, expl or expl_initial)
916 default_initial if default is None else default,
918 if obj.default is None:
919 optional = optional_initial if optional is None else optional
920 optional = False if optional is None else optional
923 self.assertEqual(obj.optional, optional)
925 (obj._bound_min, obj._bound_max),
926 bounds or bounds_initial or (float("-inf"), float("+inf")),
930 {} if _specs_initial is None else dict(_specs_initial),
933 @given(integer_values_strategy())
934 def test_copy(self, values):
935 for klass in (Integer, IntegerInherited):
937 obj_copied = obj.copy()
938 self.assert_copied_basic_fields(obj, obj_copied)
939 self.assertEqual(obj.specs, obj_copied.specs)
940 self.assertEqual(obj._bound_min, obj_copied._bound_min)
941 self.assertEqual(obj._bound_max, obj_copied._bound_max)
942 self.assertEqual(obj._value, obj_copied._value)
946 integers(min_value=1).map(tag_encode),
948 def test_stripped(self, value, tag_impl):
949 obj = Integer(value, impl=tag_impl)
950 with self.assertRaises(NotEnoughData):
951 obj.decode(obj.encode()[:-1])
955 integers(min_value=1).map(tag_ctxc),
957 def test_stripped_expl(self, value, tag_expl):
958 obj = Integer(value, expl=tag_expl)
959 with self.assertRaises(NotEnoughData):
960 obj.decode(obj.encode()[:-1])
962 def test_zero_len(self):
963 with self.assertRaises(NotEnoughData):
964 Integer().decode(b"".join((
970 integers(min_value=31),
971 integers(min_value=0),
974 def test_bad_tag(self, tag, offset, decode_path):
975 with self.assertRaises(DecodeError) as err:
977 tag_encode(tag)[:-1],
979 decode_path=decode_path,
982 self.assertEqual(err.exception.offset, offset)
983 self.assertEqual(err.exception.decode_path, decode_path)
986 integers(min_value=128),
987 integers(min_value=0),
990 def test_bad_len(self, l, offset, decode_path):
991 with self.assertRaises(DecodeError) as err:
993 Integer.tag_default + len_encode(l)[:-1],
995 decode_path=decode_path,
998 self.assertEqual(err.exception.offset, offset)
999 self.assertEqual(err.exception.decode_path, decode_path)
1002 sets(integers(), min_size=2, max_size=2),
1003 integers(min_value=0),
1006 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1007 value, bound_min = list(sorted(ints))
1010 bounds = (bound_min, bound_min)
1011 with self.assertRaises(DecodeError) as err:
1013 Integer(value).encode(),
1015 decode_path=decode_path,
1018 self.assertEqual(err.exception.offset, offset)
1019 self.assertEqual(err.exception.decode_path, decode_path)
1021 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1023 integer_values_strategy(),
1025 integers(min_value=1).map(tag_ctxc),
1026 integers(min_value=0),
1029 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1030 for klass in (Integer, IntegerInherited):
1031 _, _, _, _, default, optional, _, _decoded = values
1040 pprint(obj, big_blobs=True, with_decode_path=True)
1041 self.assertFalse(obj.expled)
1042 obj_encoded = obj.encode()
1043 obj_expled = obj(value, expl=tag_expl)
1044 self.assertTrue(obj_expled.expled)
1046 list(obj_expled.pps())
1047 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1048 obj_expled_encoded = obj_expled.encode()
1049 ctx_copied = deepcopy(ctx_dummy)
1050 obj_decoded, tail = obj_expled.decode(
1051 obj_expled_encoded + tail_junk,
1055 self.assertDictEqual(ctx_copied, ctx_dummy)
1057 list(obj_decoded.pps())
1058 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1059 self.assertEqual(tail, tail_junk)
1060 self.assertEqual(obj_decoded, obj_expled)
1061 self.assertNotEqual(obj_decoded, obj)
1062 self.assertEqual(int(obj_decoded), int(obj_expled))
1063 self.assertEqual(int(obj_decoded), int(obj))
1064 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1065 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1066 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1068 obj_decoded.expl_llen,
1069 len(len_encode(len(obj_encoded))),
1071 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1072 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1075 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1077 self.assertEqual(obj_decoded.expl_offset, offset)
1079 def test_go_vectors_valid(self):
1080 for data, expect in ((
1084 (b"\xff\x7f", -129),
1088 (b"\xff\x00", -256),
1092 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1093 (b"\x80\x00\x00\x00", -2147483648),
1096 Integer().decode(b"".join((
1097 Integer.tag_default,
1098 len_encode(len(data)),
1104 def test_go_vectors_invalid(self):
1109 with self.assertRaises(DecodeError):
1110 Integer().decode(b"".join((
1111 Integer.tag_default,
1112 len_encode(len(data)),
1118 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1121 if draw(booleans()):
1122 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1124 integers(min_value=0, max_value=255),
1125 min_size=len(schema),
1126 max_size=len(schema),
1128 schema = list(zip(schema, bits))
1130 def _value(value_required):
1131 if not value_required and draw(booleans()):
1133 generation_choice = 0
1135 generation_choice = draw(sampled_from((1, 2, 3)))
1136 if generation_choice == 1 or draw(booleans()):
1137 return "'%s'B" % "".join(draw(lists(
1138 sampled_from(("0", "1")),
1139 max_size=len(schema),
1141 elif generation_choice == 2 or draw(booleans()):
1142 return draw(binary(max_size=len(schema) // 8))
1143 elif generation_choice == 3 or draw(booleans()):
1144 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1146 value = _value(value_required)
1147 default = _value(value_required=False)
1151 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1153 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1154 optional = draw(one_of(none(), booleans()))
1156 draw(integers(min_value=0)),
1157 draw(integers(min_value=0)),
1158 draw(integers(min_value=0)),
1160 return (schema, value, impl, expl, default, optional, _decoded)
1163 class BitStringInherited(BitString):
1167 class TestBitString(CommonMixin, TestCase):
1168 base_klass = BitString
1170 @given(lists(booleans()))
1171 def test_b_encoding(self, bits):
1172 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1173 self.assertEqual(obj.bit_len, len(bits))
1174 self.assertSequenceEqual(list(obj), bits)
1175 for i, bit in enumerate(bits):
1176 self.assertEqual(obj[i], bit)
1178 @given(lists(booleans()))
1179 def test_out_of_bounds_bits(self, bits):
1180 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1181 for i in range(len(bits), len(bits) * 2):
1182 self.assertFalse(obj[i])
1184 def test_bad_b_encoding(self):
1185 with self.assertRaises(ValueError):
1186 BitString("'010120101'B")
1189 integers(min_value=1, max_value=255),
1190 integers(min_value=1, max_value=255),
1192 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1193 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1194 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1195 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1197 class BS(BitString):
1198 schema = (("whatever", 0),)
1199 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1200 self.assertEqual(obj.bit_len, leading_zeros + 1)
1201 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1203 def test_zero_len(self):
1204 with self.assertRaises(NotEnoughData):
1205 BitString().decode(b"".join((
1206 BitString.tag_default,
1210 def test_invalid_value_type(self):
1211 with self.assertRaises(InvalidValueType) as err:
1214 with self.assertRaises(InvalidValueType) as err:
1218 def test_obj_unknown(self):
1219 with self.assertRaises(ObjUnknown) as err:
1220 BitString(b"whatever")["whenever"]
1223 def test_get_invalid_type(self):
1224 with self.assertRaises(InvalidValueType) as err:
1225 BitString(b"whatever")[(1, 2, 3)]
1228 @given(data_strategy())
1229 def test_unknown_name(self, d):
1230 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1231 missing = _schema.pop()
1233 class BS(BitString):
1234 schema = [(n, i) for i, n in enumerate(_schema)]
1235 with self.assertRaises(ObjUnknown) as err:
1240 def test_optional(self, optional):
1241 obj = BitString(default=BitString(b""), optional=optional)
1242 self.assertTrue(obj.optional)
1245 def test_ready(self, value):
1247 self.assertFalse(obj.ready)
1250 pprint(obj, big_blobs=True, with_decode_path=True)
1251 with self.assertRaises(ObjNotReady) as err:
1254 obj = BitString(value)
1255 self.assertTrue(obj.ready)
1258 pprint(obj, big_blobs=True, with_decode_path=True)
1261 tuples(integers(min_value=0), binary()),
1262 tuples(integers(min_value=0), binary()),
1266 def test_comparison(self, value1, value2, tag1, tag2):
1267 for klass in (BitString, BitStringInherited):
1268 obj1 = klass(value1)
1269 obj2 = klass(value2)
1270 self.assertEqual(obj1 == obj2, value1 == value2)
1271 self.assertEqual(obj1 != obj2, value1 != value2)
1272 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1273 obj1 = klass(value1, impl=tag1)
1274 obj2 = klass(value1, impl=tag2)
1275 self.assertEqual(obj1 == obj2, tag1 == tag2)
1276 self.assertEqual(obj1 != obj2, tag1 != tag2)
1278 @given(data_strategy())
1279 def test_call(self, d):
1280 for klass in (BitString, BitStringInherited):
1289 ) = d.draw(bit_string_values_strategy())
1292 schema = schema_initial
1294 value=value_initial,
1297 default=default_initial,
1298 optional=optional_initial or False,
1299 _decoded=_decoded_initial,
1309 ) = d.draw(bit_string_values_strategy(
1310 schema=schema_initial,
1311 do_expl=impl_initial is None,
1320 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1321 self.assertEqual(obj.expl_tag, expl or expl_initial)
1322 if obj.default is None:
1323 optional = optional_initial if optional is None else optional
1324 optional = False if optional is None else optional
1327 self.assertEqual(obj.optional, optional)
1328 self.assertEqual(obj.specs, obj_initial.specs)
1330 @given(bit_string_values_strategy())
1331 def test_copy(self, values):
1332 for klass in (BitString, BitStringInherited):
1333 _schema, value, impl, expl, default, optional, _decoded = values
1342 optional=optional or False,
1345 obj_copied = obj.copy()
1346 self.assert_copied_basic_fields(obj, obj_copied)
1347 self.assertEqual(obj.specs, obj_copied.specs)
1348 self.assertEqual(obj._value, obj_copied._value)
1352 integers(min_value=1).map(tag_encode),
1354 def test_stripped(self, value, tag_impl):
1355 obj = BitString(value, impl=tag_impl)
1356 with self.assertRaises(NotEnoughData):
1357 obj.decode(obj.encode()[:-1])
1361 integers(min_value=1).map(tag_ctxc),
1363 def test_stripped_expl(self, value, tag_expl):
1364 obj = BitString(value, expl=tag_expl)
1365 with self.assertRaises(NotEnoughData):
1366 obj.decode(obj.encode()[:-1])
1369 integers(min_value=31),
1370 integers(min_value=0),
1373 def test_bad_tag(self, tag, offset, decode_path):
1374 with self.assertRaises(DecodeError) as err:
1376 tag_encode(tag)[:-1],
1378 decode_path=decode_path,
1381 self.assertEqual(err.exception.offset, offset)
1382 self.assertEqual(err.exception.decode_path, decode_path)
1385 integers(min_value=128),
1386 integers(min_value=0),
1389 def test_bad_len(self, l, offset, decode_path):
1390 with self.assertRaises(DecodeError) as err:
1392 BitString.tag_default + len_encode(l)[:-1],
1394 decode_path=decode_path,
1397 self.assertEqual(err.exception.offset, offset)
1398 self.assertEqual(err.exception.decode_path, decode_path)
1400 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1401 @given(data_strategy())
1402 def test_symmetric(self, d):
1411 ) = d.draw(bit_string_values_strategy(value_required=True))
1412 tail_junk = d.draw(binary(max_size=5))
1413 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1414 offset = d.draw(integers(min_value=0))
1415 for klass in (BitString, BitStringInherited):
1426 pprint(obj, big_blobs=True, with_decode_path=True)
1427 self.assertFalse(obj.expled)
1428 obj_encoded = obj.encode()
1429 obj_expled = obj(value, expl=tag_expl)
1430 self.assertTrue(obj_expled.expled)
1432 list(obj_expled.pps())
1433 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1434 obj_expled_encoded = obj_expled.encode()
1435 ctx_copied = deepcopy(ctx_dummy)
1436 obj_decoded, tail = obj_expled.decode(
1437 obj_expled_encoded + tail_junk,
1441 self.assertDictEqual(ctx_copied, ctx_dummy)
1443 list(obj_decoded.pps())
1444 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1445 self.assertEqual(tail, tail_junk)
1446 self.assertEqual(obj_decoded, obj_expled)
1447 self.assertNotEqual(obj_decoded, obj)
1448 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1449 self.assertEqual(bytes(obj_decoded), bytes(obj))
1450 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1451 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1452 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1454 obj_decoded.expl_llen,
1455 len(len_encode(len(obj_encoded))),
1457 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1458 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1461 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1463 self.assertEqual(obj_decoded.expl_offset, offset)
1464 if isinstance(value, tuple):
1465 self.assertSetEqual(set(value), set(obj_decoded.named))
1469 @given(integers(min_value=1, max_value=255))
1470 def test_bad_zero_value(self, pad_size):
1471 with self.assertRaises(DecodeError):
1472 BitString().decode(b"".join((
1473 BitString.tag_default,
1478 def test_go_vectors_invalid(self):
1484 with self.assertRaises(DecodeError):
1485 BitString().decode(b"".join((
1486 BitString.tag_default,
1491 def test_go_vectors_valid(self):
1492 obj, _ = BitString().decode(b"".join((
1493 BitString.tag_default,
1497 self.assertEqual(bytes(obj), b"")
1498 self.assertEqual(obj.bit_len, 0)
1500 obj, _ = BitString().decode(b"".join((
1501 BitString.tag_default,
1505 self.assertEqual(bytes(obj), b"\x00")
1506 self.assertEqual(obj.bit_len, 1)
1508 obj = BitString((16, b"\x82\x40"))
1509 self.assertTrue(obj[0])
1510 self.assertFalse(obj[1])
1511 self.assertTrue(obj[6])
1512 self.assertTrue(obj[9])
1513 self.assertFalse(obj[17])
1516 integers(min_value=1, max_value=30),
1519 binary(min_size=1, max_size=5),
1521 binary(min_size=1, max_size=5),
1529 lists(booleans(), min_size=1),
1532 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1533 def chunk_constructed(contents):
1535 tag_encode(form=TagFormConstructed, num=3) +
1537 b"".join(BitString(content).encode() for content in contents) +
1541 payload_expected = b""
1542 bit_len_expected = 0
1543 for chunk_input in chunk_inputs:
1544 if isinstance(chunk_input, binary_type):
1545 chunks.append(BitString(chunk_input).encode())
1546 payload_expected += chunk_input
1547 bit_len_expected += len(chunk_input) * 8
1549 chunks.append(chunk_constructed(chunk_input))
1550 payload = b"".join(chunk_input)
1551 payload_expected += payload
1552 bit_len_expected += len(payload) * 8
1553 chunk_last = BitString("'%s'B" % "".join(
1554 "1" if bit else "0" for bit in chunk_last_bits
1556 payload_expected += bytes(chunk_last)
1557 bit_len_expected += chunk_last.bit_len
1558 encoded_indefinite = (
1559 tag_encode(form=TagFormConstructed, num=impl) +
1562 chunk_last.encode() +
1565 encoded_definite = (
1566 tag_encode(form=TagFormConstructed, num=impl) +
1567 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1571 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1572 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1573 for lenindef_expected, encoded in (
1574 (True, encoded_indefinite),
1575 (False, encoded_definite),
1577 obj, tail = BitString(impl=tag_encode(impl)).decode(
1579 ctx={"bered": True},
1581 self.assertSequenceEqual(tail, junk)
1582 self.assertEqual(obj.bit_len, bit_len_expected)
1583 self.assertSequenceEqual(bytes(obj), payload_expected)
1584 self.assertTrue(obj.ber_encoded)
1585 self.assertEqual(obj.lenindef, lenindef_expected)
1586 self.assertTrue(obj.bered)
1587 self.assertEqual(len(encoded), obj.tlvlen)
1590 integers(min_value=0),
1593 def test_ber_definite_too_short(self, offset, decode_path):
1594 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1596 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1598 decode_path=decode_path,
1599 ctx={"bered": True},
1601 self.assertEqual(err.exception.decode_path, decode_path)
1602 self.assertEqual(err.exception.offset, offset)
1605 integers(min_value=0),
1608 def test_ber_definite_no_data(self, offset, decode_path):
1609 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1611 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1613 decode_path=decode_path,
1614 ctx={"bered": True},
1616 self.assertEqual(err.exception.decode_path, decode_path)
1617 self.assertEqual(err.exception.offset, offset)
1620 integers(min_value=0),
1622 integers(min_value=1, max_value=3),
1624 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1625 bs = BitString(b"data").encode()
1626 with self.assertRaises(NotEnoughData) as err:
1628 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1630 decode_path=decode_path,
1631 ctx={"bered": True},
1633 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1634 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1637 integers(min_value=0),
1639 integers(min_value=1, max_value=3),
1641 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1642 bs = BitString(b"data").encode()
1643 bs_longer = BitString(b"data-longer").encode()
1644 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1647 tag_encode(3, form=TagFormConstructed) +
1648 len_encode((chunks + 1) * len(bs)) +
1653 decode_path=decode_path,
1654 ctx={"bered": True},
1656 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1657 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1660 integers(min_value=0),
1663 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1664 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1666 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1668 decode_path=decode_path,
1669 ctx={"bered": True},
1671 self.assertEqual(err.exception.decode_path, decode_path)
1672 self.assertEqual(err.exception.offset, offset)
1674 @given(data_strategy())
1675 def test_ber_indefinite_not_multiple(self, d):
1676 bs_short = BitString("'A'H").encode()
1677 bs_full = BitString("'AA'H").encode()
1678 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1679 chunks.append(bs_short)
1680 d.draw(permutations(chunks))
1681 chunks.append(bs_short)
1682 offset = d.draw(integers(min_value=0))
1683 decode_path = d.draw(decode_path_strat)
1684 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1687 tag_encode(3, form=TagFormConstructed) +
1693 decode_path=decode_path,
1694 ctx={"bered": True},
1697 err.exception.decode_path,
1698 decode_path + (str(chunks.index(bs_short)),),
1701 err.exception.offset,
1702 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1705 def test_x690_vector(self):
1706 vector = BitString("'0A3B5F291CD'H")
1707 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1708 self.assertSequenceEqual(tail, b"")
1709 self.assertEqual(obj, vector)
1710 obj, tail = BitString().decode(
1711 hexdec("23800303000A3B0305045F291CD00000"),
1712 ctx={"bered": True},
1714 self.assertSequenceEqual(tail, b"")
1715 self.assertEqual(obj, vector)
1716 self.assertTrue(obj.ber_encoded)
1717 self.assertTrue(obj.lenindef)
1718 self.assertTrue(obj.bered)
1722 def octet_string_values_strategy(draw, do_expl=False):
1723 bound_min, bound_max = sorted(draw(sets(
1724 integers(min_value=0, max_value=1 << 7),
1728 value = draw(one_of(
1730 binary(min_size=bound_min, max_size=bound_max),
1732 default = draw(one_of(
1734 binary(min_size=bound_min, max_size=bound_max),
1737 if draw(booleans()):
1738 bounds = (bound_min, bound_max)
1742 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1744 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1745 optional = draw(one_of(none(), booleans()))
1747 draw(integers(min_value=0)),
1748 draw(integers(min_value=0)),
1749 draw(integers(min_value=0)),
1751 return (value, bounds, impl, expl, default, optional, _decoded)
1754 class OctetStringInherited(OctetString):
1758 class TestOctetString(CommonMixin, TestCase):
1759 base_klass = OctetString
1761 def test_invalid_value_type(self):
1762 with self.assertRaises(InvalidValueType) as err:
1763 OctetString(text_type(123))
1767 def test_optional(self, optional):
1768 obj = OctetString(default=OctetString(b""), optional=optional)
1769 self.assertTrue(obj.optional)
1772 def test_ready(self, value):
1774 self.assertFalse(obj.ready)
1777 pprint(obj, big_blobs=True, with_decode_path=True)
1778 with self.assertRaises(ObjNotReady) as err:
1781 obj = OctetString(value)
1782 self.assertTrue(obj.ready)
1785 pprint(obj, big_blobs=True, with_decode_path=True)
1787 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1788 def test_comparison(self, value1, value2, tag1, tag2):
1789 for klass in (OctetString, OctetStringInherited):
1790 obj1 = klass(value1)
1791 obj2 = klass(value2)
1792 self.assertEqual(obj1 == obj2, value1 == value2)
1793 self.assertEqual(obj1 != obj2, value1 != value2)
1794 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1795 obj1 = klass(value1, impl=tag1)
1796 obj2 = klass(value1, impl=tag2)
1797 self.assertEqual(obj1 == obj2, tag1 == tag2)
1798 self.assertEqual(obj1 != obj2, tag1 != tag2)
1800 @given(lists(binary()))
1801 def test_sorted_works(self, values):
1802 self.assertSequenceEqual(
1803 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1807 @given(data_strategy())
1808 def test_bounds_satisfied(self, d):
1809 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1810 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1811 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1812 OctetString(value=value, bounds=(bound_min, bound_max))
1814 @given(data_strategy())
1815 def test_bounds_unsatisfied(self, d):
1816 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1817 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1818 value = d.draw(binary(max_size=bound_min - 1))
1819 with self.assertRaises(BoundsError) as err:
1820 OctetString(value=value, bounds=(bound_min, bound_max))
1822 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1823 OctetString(bounds=(bound_min, bound_max)).decode(
1824 OctetString(value).encode()
1827 value = d.draw(binary(min_size=bound_max + 1))
1828 with self.assertRaises(BoundsError) as err:
1829 OctetString(value=value, bounds=(bound_min, bound_max))
1831 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1832 OctetString(bounds=(bound_min, bound_max)).decode(
1833 OctetString(value).encode()
1837 @given(data_strategy())
1838 def test_call(self, d):
1839 for klass in (OctetString, OctetStringInherited):
1848 ) = d.draw(octet_string_values_strategy())
1849 obj_initial = klass(
1855 optional_initial or False,
1866 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1867 if (default is None) and (obj_initial.default is not None):
1870 (bounds is None) and
1871 (value is not None) and
1872 (bounds_initial is not None) and
1873 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1877 (bounds is None) and
1878 (default is not None) and
1879 (bounds_initial is not None) and
1880 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1883 obj = obj_initial(value, bounds, impl, expl, default, optional)
1885 value_expected = default if value is None else value
1887 default_initial if value_expected is None
1890 self.assertEqual(obj, value_expected)
1891 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1892 self.assertEqual(obj.expl_tag, expl or expl_initial)
1895 default_initial if default is None else default,
1897 if obj.default is None:
1898 optional = optional_initial if optional is None else optional
1899 optional = False if optional is None else optional
1902 self.assertEqual(obj.optional, optional)
1904 (obj._bound_min, obj._bound_max),
1905 bounds or bounds_initial or (0, float("+inf")),
1908 @given(octet_string_values_strategy())
1909 def test_copy(self, values):
1910 for klass in (OctetString, OctetStringInherited):
1911 obj = klass(*values)
1912 obj_copied = obj.copy()
1913 self.assert_copied_basic_fields(obj, obj_copied)
1914 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1915 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1916 self.assertEqual(obj._value, obj_copied._value)
1920 integers(min_value=1).map(tag_encode),
1922 def test_stripped(self, value, tag_impl):
1923 obj = OctetString(value, impl=tag_impl)
1924 with self.assertRaises(NotEnoughData):
1925 obj.decode(obj.encode()[:-1])
1929 integers(min_value=1).map(tag_ctxc),
1931 def test_stripped_expl(self, value, tag_expl):
1932 obj = OctetString(value, expl=tag_expl)
1933 with self.assertRaises(NotEnoughData):
1934 obj.decode(obj.encode()[:-1])
1937 integers(min_value=31),
1938 integers(min_value=0),
1941 def test_bad_tag(self, tag, offset, decode_path):
1942 with self.assertRaises(DecodeError) as err:
1943 OctetString().decode(
1944 tag_encode(tag)[:-1],
1946 decode_path=decode_path,
1949 self.assertEqual(err.exception.offset, offset)
1950 self.assertEqual(err.exception.decode_path, decode_path)
1953 integers(min_value=128),
1954 integers(min_value=0),
1957 def test_bad_len(self, l, offset, decode_path):
1958 with self.assertRaises(DecodeError) as err:
1959 OctetString().decode(
1960 OctetString.tag_default + len_encode(l)[:-1],
1962 decode_path=decode_path,
1965 self.assertEqual(err.exception.offset, offset)
1966 self.assertEqual(err.exception.decode_path, decode_path)
1969 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1970 integers(min_value=0),
1973 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1974 value, bound_min = list(sorted(ints))
1976 class String(OctetString):
1977 bounds = (bound_min, bound_min)
1978 with self.assertRaises(DecodeError) as err:
1980 OctetString(b"\x00" * value).encode(),
1982 decode_path=decode_path,
1985 self.assertEqual(err.exception.offset, offset)
1986 self.assertEqual(err.exception.decode_path, decode_path)
1988 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1990 octet_string_values_strategy(),
1992 integers(min_value=1).map(tag_ctxc),
1993 integers(min_value=0),
1996 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1997 for klass in (OctetString, OctetStringInherited):
1998 _, _, _, _, default, optional, _decoded = values
2007 pprint(obj, big_blobs=True, with_decode_path=True)
2008 self.assertFalse(obj.expled)
2009 obj_encoded = obj.encode()
2010 obj_expled = obj(value, expl=tag_expl)
2011 self.assertTrue(obj_expled.expled)
2013 list(obj_expled.pps())
2014 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2015 obj_expled_encoded = obj_expled.encode()
2016 ctx_copied = deepcopy(ctx_dummy)
2017 obj_decoded, tail = obj_expled.decode(
2018 obj_expled_encoded + tail_junk,
2022 self.assertDictEqual(ctx_copied, ctx_dummy)
2024 list(obj_decoded.pps())
2025 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2026 self.assertEqual(tail, tail_junk)
2027 self.assertEqual(obj_decoded, obj_expled)
2028 self.assertNotEqual(obj_decoded, obj)
2029 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2030 self.assertEqual(bytes(obj_decoded), bytes(obj))
2031 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2032 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2033 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2035 obj_decoded.expl_llen,
2036 len(len_encode(len(obj_encoded))),
2038 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2039 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2042 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2044 self.assertEqual(obj_decoded.expl_offset, offset)
2047 integers(min_value=1, max_value=30),
2050 binary(min_size=1, max_size=5),
2052 binary(min_size=1, max_size=5),
2062 def test_constructed(self, impl, chunk_inputs, junk):
2063 def chunk_constructed(contents):
2065 tag_encode(form=TagFormConstructed, num=4) +
2067 b"".join(OctetString(content).encode() for content in contents) +
2071 payload_expected = b""
2072 for chunk_input in chunk_inputs:
2073 if isinstance(chunk_input, binary_type):
2074 chunks.append(OctetString(chunk_input).encode())
2075 payload_expected += chunk_input
2077 chunks.append(chunk_constructed(chunk_input))
2078 payload = b"".join(chunk_input)
2079 payload_expected += payload
2080 encoded_indefinite = (
2081 tag_encode(form=TagFormConstructed, num=impl) +
2086 encoded_definite = (
2087 tag_encode(form=TagFormConstructed, num=impl) +
2088 len_encode(len(b"".join(chunks))) +
2091 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2092 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2093 for lenindef_expected, encoded in (
2094 (True, encoded_indefinite),
2095 (False, encoded_definite),
2097 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2099 ctx={"bered": True},
2101 self.assertSequenceEqual(tail, junk)
2102 self.assertSequenceEqual(bytes(obj), payload_expected)
2103 self.assertTrue(obj.ber_encoded)
2104 self.assertEqual(obj.lenindef, lenindef_expected)
2105 self.assertTrue(obj.bered)
2106 self.assertEqual(len(encoded), obj.tlvlen)
2109 integers(min_value=0),
2112 def test_ber_definite_too_short(self, offset, decode_path):
2113 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2114 OctetString().decode(
2115 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2117 decode_path=decode_path,
2118 ctx={"bered": True},
2120 self.assertEqual(err.exception.decode_path, decode_path)
2121 self.assertEqual(err.exception.offset, offset)
2124 integers(min_value=0),
2126 integers(min_value=1, max_value=3),
2128 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2129 bs = OctetString(b"data").encode()
2130 with self.assertRaises(NotEnoughData) as err:
2131 OctetString().decode(
2132 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2134 decode_path=decode_path,
2135 ctx={"bered": True},
2137 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2138 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2141 integers(min_value=0),
2143 integers(min_value=1, max_value=3),
2145 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2146 bs = OctetString(b"data").encode()
2147 bs_longer = OctetString(b"data-longer").encode()
2148 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2149 OctetString().decode(
2151 tag_encode(4, form=TagFormConstructed) +
2152 len_encode((chunks + 1) * len(bs)) +
2157 decode_path=decode_path,
2158 ctx={"bered": True},
2160 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2161 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2165 def null_values_strategy(draw, do_expl=False):
2169 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2171 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2172 optional = draw(one_of(none(), booleans()))
2174 draw(integers(min_value=0)),
2175 draw(integers(min_value=0)),
2176 draw(integers(min_value=0)),
2178 return (impl, expl, optional, _decoded)
2181 class NullInherited(Null):
2185 class TestNull(CommonMixin, TestCase):
2188 def test_ready(self):
2190 self.assertTrue(obj.ready)
2193 pprint(obj, big_blobs=True, with_decode_path=True)
2195 @given(binary(), binary())
2196 def test_comparison(self, tag1, tag2):
2197 for klass in (Null, NullInherited):
2198 obj1 = klass(impl=tag1)
2199 obj2 = klass(impl=tag2)
2200 self.assertEqual(obj1 == obj2, tag1 == tag2)
2201 self.assertEqual(obj1 != obj2, tag1 != tag2)
2202 self.assertNotEqual(obj1, tag2)
2204 @given(data_strategy())
2205 def test_call(self, d):
2206 for klass in (Null, NullInherited):
2212 ) = d.draw(null_values_strategy())
2213 obj_initial = klass(
2216 optional=optional_initial or False,
2217 _decoded=_decoded_initial,
2224 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2225 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2226 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2227 self.assertEqual(obj.expl_tag, expl or expl_initial)
2228 optional = optional_initial if optional is None else optional
2229 optional = False if optional is None else optional
2230 self.assertEqual(obj.optional, optional)
2232 @given(null_values_strategy())
2233 def test_copy(self, values):
2234 for klass in (Null, NullInherited):
2235 impl, expl, optional, _decoded = values
2239 optional=optional or False,
2242 obj_copied = obj.copy()
2243 self.assert_copied_basic_fields(obj, obj_copied)
2245 @given(integers(min_value=1).map(tag_encode))
2246 def test_stripped(self, tag_impl):
2247 obj = Null(impl=tag_impl)
2248 with self.assertRaises(NotEnoughData):
2249 obj.decode(obj.encode()[:-1])
2251 @given(integers(min_value=1).map(tag_ctxc))
2252 def test_stripped_expl(self, tag_expl):
2253 obj = Null(expl=tag_expl)
2254 with self.assertRaises(NotEnoughData):
2255 obj.decode(obj.encode()[:-1])
2258 integers(min_value=31),
2259 integers(min_value=0),
2262 def test_bad_tag(self, tag, offset, decode_path):
2263 with self.assertRaises(DecodeError) as err:
2265 tag_encode(tag)[:-1],
2267 decode_path=decode_path,
2270 self.assertEqual(err.exception.offset, offset)
2271 self.assertEqual(err.exception.decode_path, decode_path)
2274 integers(min_value=128),
2275 integers(min_value=0),
2278 def test_bad_len(self, l, offset, decode_path):
2279 with self.assertRaises(DecodeError) as err:
2281 Null.tag_default + len_encode(l)[:-1],
2283 decode_path=decode_path,
2286 self.assertEqual(err.exception.offset, offset)
2287 self.assertEqual(err.exception.decode_path, decode_path)
2289 @given(binary(min_size=1))
2290 def test_tag_mismatch(self, impl):
2291 assume(impl != Null.tag_default)
2292 with self.assertRaises(TagMismatch):
2293 Null(impl=impl).decode(Null().encode())
2296 null_values_strategy(),
2297 integers(min_value=1).map(tag_ctxc),
2298 integers(min_value=0),
2301 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2302 for klass in (Null, NullInherited):
2303 _, _, optional, _decoded = values
2304 obj = klass(optional=optional, _decoded=_decoded)
2307 pprint(obj, big_blobs=True, with_decode_path=True)
2308 self.assertFalse(obj.expled)
2309 obj_encoded = obj.encode()
2310 obj_expled = obj(expl=tag_expl)
2311 self.assertTrue(obj_expled.expled)
2313 list(obj_expled.pps())
2314 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2315 obj_expled_encoded = obj_expled.encode()
2316 ctx_copied = deepcopy(ctx_dummy)
2317 obj_decoded, tail = obj_expled.decode(
2318 obj_expled_encoded + tail_junk,
2322 self.assertDictEqual(ctx_copied, ctx_dummy)
2324 list(obj_decoded.pps())
2325 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2326 self.assertEqual(tail, tail_junk)
2327 self.assertEqual(obj_decoded, obj_expled)
2328 self.assertNotEqual(obj_decoded, obj)
2329 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2330 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2331 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2333 obj_decoded.expl_llen,
2334 len(len_encode(len(obj_encoded))),
2336 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2337 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2340 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2342 self.assertEqual(obj_decoded.expl_offset, offset)
2344 @given(integers(min_value=1))
2345 def test_invalid_len(self, l):
2346 with self.assertRaises(InvalidLength):
2347 Null().decode(b"".join((
2354 def oid_strategy(draw):
2355 first_arc = draw(integers(min_value=0, max_value=2))
2357 if first_arc in (0, 1):
2358 second_arc = draw(integers(min_value=0, max_value=39))
2360 second_arc = draw(integers(min_value=0))
2361 other_arcs = draw(lists(integers(min_value=0)))
2362 return tuple([first_arc, second_arc] + other_arcs)
2366 def oid_values_strategy(draw, do_expl=False):
2367 value = draw(one_of(none(), oid_strategy()))
2371 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2373 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2374 default = draw(one_of(none(), oid_strategy()))
2375 optional = draw(one_of(none(), booleans()))
2377 draw(integers(min_value=0)),
2378 draw(integers(min_value=0)),
2379 draw(integers(min_value=0)),
2381 return (value, impl, expl, default, optional, _decoded)
2384 class ObjectIdentifierInherited(ObjectIdentifier):
2388 class TestObjectIdentifier(CommonMixin, TestCase):
2389 base_klass = ObjectIdentifier
2391 def test_invalid_value_type(self):
2392 with self.assertRaises(InvalidValueType) as err:
2393 ObjectIdentifier(123)
2397 def test_optional(self, optional):
2398 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2399 self.assertTrue(obj.optional)
2401 @given(oid_strategy())
2402 def test_ready(self, value):
2403 obj = ObjectIdentifier()
2404 self.assertFalse(obj.ready)
2407 pprint(obj, big_blobs=True, with_decode_path=True)
2408 with self.assertRaises(ObjNotReady) as err:
2411 obj = ObjectIdentifier(value)
2412 self.assertTrue(obj.ready)
2415 pprint(obj, big_blobs=True, with_decode_path=True)
2418 @given(oid_strategy(), oid_strategy(), binary(), binary())
2419 def test_comparison(self, value1, value2, tag1, tag2):
2420 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2421 obj1 = klass(value1)
2422 obj2 = klass(value2)
2423 self.assertEqual(obj1 == obj2, value1 == value2)
2424 self.assertEqual(obj1 != obj2, value1 != value2)
2425 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2426 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2427 obj1 = klass(value1, impl=tag1)
2428 obj2 = klass(value1, impl=tag2)
2429 self.assertEqual(obj1 == obj2, tag1 == tag2)
2430 self.assertEqual(obj1 != obj2, tag1 != tag2)
2432 @given(lists(oid_strategy()))
2433 def test_sorted_works(self, values):
2434 self.assertSequenceEqual(
2435 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2439 @given(data_strategy())
2440 def test_call(self, d):
2441 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2449 ) = d.draw(oid_values_strategy())
2450 obj_initial = klass(
2451 value=value_initial,
2454 default=default_initial,
2455 optional=optional_initial or False,
2456 _decoded=_decoded_initial,
2465 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2474 value_expected = default if value is None else value
2476 default_initial if value_expected is None
2479 self.assertEqual(obj, value_expected)
2480 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2481 self.assertEqual(obj.expl_tag, expl or expl_initial)
2484 default_initial if default is None else default,
2486 if obj.default is None:
2487 optional = optional_initial if optional is None else optional
2488 optional = False if optional is None else optional
2491 self.assertEqual(obj.optional, optional)
2493 @given(oid_values_strategy())
2494 def test_copy(self, values):
2495 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2512 obj_copied = obj.copy()
2513 self.assert_copied_basic_fields(obj, obj_copied)
2514 self.assertEqual(obj._value, obj_copied._value)
2516 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2519 integers(min_value=1).map(tag_encode),
2521 def test_stripped(self, value, tag_impl):
2522 obj = ObjectIdentifier(value, impl=tag_impl)
2523 with self.assertRaises(NotEnoughData):
2524 obj.decode(obj.encode()[:-1])
2528 integers(min_value=1).map(tag_ctxc),
2530 def test_stripped_expl(self, value, tag_expl):
2531 obj = ObjectIdentifier(value, expl=tag_expl)
2532 with self.assertRaises(NotEnoughData):
2533 obj.decode(obj.encode()[:-1])
2536 integers(min_value=31),
2537 integers(min_value=0),
2540 def test_bad_tag(self, tag, offset, decode_path):
2541 with self.assertRaises(DecodeError) as err:
2542 ObjectIdentifier().decode(
2543 tag_encode(tag)[:-1],
2545 decode_path=decode_path,
2548 self.assertEqual(err.exception.offset, offset)
2549 self.assertEqual(err.exception.decode_path, decode_path)
2552 integers(min_value=128),
2553 integers(min_value=0),
2556 def test_bad_len(self, l, offset, decode_path):
2557 with self.assertRaises(DecodeError) as err:
2558 ObjectIdentifier().decode(
2559 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2561 decode_path=decode_path,
2564 self.assertEqual(err.exception.offset, offset)
2565 self.assertEqual(err.exception.decode_path, decode_path)
2567 def test_zero_oid(self):
2568 with self.assertRaises(NotEnoughData):
2569 ObjectIdentifier().decode(
2570 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2573 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2574 @given(oid_strategy())
2575 def test_unfinished_oid(self, value):
2576 assume(list(value)[-1] > 255)
2577 obj_encoded = ObjectIdentifier(value).encode()
2578 obj, _ = ObjectIdentifier().decode(obj_encoded)
2579 data = obj_encoded[obj.tlen + obj.llen:-1]
2581 ObjectIdentifier.tag_default,
2582 len_encode(len(data)),
2585 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2588 @given(integers(min_value=0))
2589 def test_invalid_short(self, value):
2590 with self.assertRaises(InvalidOID):
2591 ObjectIdentifier((value,))
2592 with self.assertRaises(InvalidOID):
2593 ObjectIdentifier("%d" % value)
2595 @given(integers(min_value=3), integers(min_value=0))
2596 def test_invalid_first_arc(self, first_arc, second_arc):
2597 with self.assertRaises(InvalidOID):
2598 ObjectIdentifier((first_arc, second_arc))
2599 with self.assertRaises(InvalidOID):
2600 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2602 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2603 def test_invalid_second_arc(self, first_arc, second_arc):
2604 with self.assertRaises(InvalidOID):
2605 ObjectIdentifier((first_arc, second_arc))
2606 with self.assertRaises(InvalidOID):
2607 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2609 @given(text(alphabet=ascii_letters + ".", min_size=1))
2610 def test_junk(self, oid):
2611 with self.assertRaises(InvalidOID):
2612 ObjectIdentifier(oid)
2614 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2615 @given(oid_strategy())
2616 def test_validness(self, oid):
2617 obj = ObjectIdentifier(oid)
2618 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2621 pprint(obj, big_blobs=True, with_decode_path=True)
2623 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2625 oid_values_strategy(),
2627 integers(min_value=1).map(tag_ctxc),
2628 integers(min_value=0),
2631 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2632 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2633 _, _, _, default, optional, _decoded = values
2642 pprint(obj, big_blobs=True, with_decode_path=True)
2643 self.assertFalse(obj.expled)
2644 obj_encoded = obj.encode()
2645 obj_expled = obj(value, expl=tag_expl)
2646 self.assertTrue(obj_expled.expled)
2648 list(obj_expled.pps())
2649 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2650 obj_expled_encoded = obj_expled.encode()
2651 ctx_copied = deepcopy(ctx_dummy)
2652 obj_decoded, tail = obj_expled.decode(
2653 obj_expled_encoded + tail_junk,
2657 self.assertDictEqual(ctx_copied, ctx_dummy)
2659 list(obj_decoded.pps())
2660 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2661 self.assertEqual(tail, tail_junk)
2662 self.assertEqual(obj_decoded, obj_expled)
2663 self.assertNotEqual(obj_decoded, obj)
2664 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2665 self.assertEqual(tuple(obj_decoded), tuple(obj))
2666 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2667 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2668 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2670 obj_decoded.expl_llen,
2671 len(len_encode(len(obj_encoded))),
2673 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2674 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2677 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2679 self.assertEqual(obj_decoded.expl_offset, offset)
2682 oid_strategy().map(ObjectIdentifier),
2683 oid_strategy().map(ObjectIdentifier),
2685 def test_add(self, oid1, oid2):
2686 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2687 for oid_to_add in (oid2, tuple(oid2)):
2688 self.assertEqual(oid1 + oid_to_add, oid_expect)
2689 with self.assertRaises(InvalidValueType):
2692 def test_go_vectors_valid(self):
2693 for data, expect in (
2695 (b"\x55\x02", (2, 5, 2)),
2696 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2697 (b"\x81\x34\x03", (2, 100, 3)),
2700 ObjectIdentifier().decode(b"".join((
2701 ObjectIdentifier.tag_default,
2702 len_encode(len(data)),
2708 def test_go_vectors_invalid(self):
2709 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2710 with self.assertRaises(DecodeError):
2711 ObjectIdentifier().decode(b"".join((
2712 Integer.tag_default,
2713 len_encode(len(data)),
2717 def test_x690_vector(self):
2719 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2720 ObjectIdentifier((2, 999, 3)),
2725 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2727 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2728 values = list(draw(sets(
2730 min_size=len(schema),
2731 max_size=len(schema),
2733 schema = list(zip(schema, values))
2734 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2738 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2740 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2741 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2742 optional = draw(one_of(none(), booleans()))
2744 draw(integers(min_value=0)),
2745 draw(integers(min_value=0)),
2746 draw(integers(min_value=0)),
2748 return (schema, value, impl, expl, default, optional, _decoded)
2751 class TestEnumerated(CommonMixin, TestCase):
2752 class EWhatever(Enumerated):
2753 schema = (("whatever", 0),)
2755 base_klass = EWhatever
2757 def test_schema_required(self):
2758 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2761 def test_invalid_value_type(self):
2762 with self.assertRaises(InvalidValueType) as err:
2763 self.base_klass((1, 2))
2766 @given(sets(text_letters(), min_size=2))
2767 def test_unknown_name(self, schema_input):
2768 missing = schema_input.pop()
2770 class E(Enumerated):
2771 schema = [(n, 123) for n in schema_input]
2772 with self.assertRaises(ObjUnknown) as err:
2777 sets(text_letters(), min_size=2),
2778 sets(integers(), min_size=2),
2780 def test_unknown_value(self, schema_input, values_input):
2782 missing_value = values_input.pop()
2783 _input = list(zip(schema_input, values_input))
2785 class E(Enumerated):
2787 with self.assertRaises(DecodeError) as err:
2792 def test_optional(self, optional):
2793 obj = self.base_klass(default="whatever", optional=optional)
2794 self.assertTrue(obj.optional)
2796 def test_ready(self):
2797 obj = self.base_klass()
2798 self.assertFalse(obj.ready)
2801 pprint(obj, big_blobs=True, with_decode_path=True)
2802 with self.assertRaises(ObjNotReady) as err:
2805 obj = self.base_klass("whatever")
2806 self.assertTrue(obj.ready)
2809 pprint(obj, big_blobs=True, with_decode_path=True)
2811 @given(integers(), integers(), binary(), binary())
2812 def test_comparison(self, value1, value2, tag1, tag2):
2813 class E(Enumerated):
2815 ("whatever0", value1),
2816 ("whatever1", value2),
2819 class EInherited(E):
2821 for klass in (E, EInherited):
2822 obj1 = klass(value1)
2823 obj2 = klass(value2)
2824 self.assertEqual(obj1 == obj2, value1 == value2)
2825 self.assertEqual(obj1 != obj2, value1 != value2)
2826 self.assertEqual(obj1 == int(obj2), value1 == value2)
2827 obj1 = klass(value1, impl=tag1)
2828 obj2 = klass(value1, impl=tag2)
2829 self.assertEqual(obj1 == obj2, tag1 == tag2)
2830 self.assertEqual(obj1 != obj2, tag1 != tag2)
2832 @given(data_strategy())
2833 def test_call(self, d):
2842 ) = d.draw(enumerated_values_strategy())
2844 class E(Enumerated):
2845 schema = schema_initial
2847 value=value_initial,
2850 default=default_initial,
2851 optional=optional_initial or False,
2852 _decoded=_decoded_initial,
2862 ) = d.draw(enumerated_values_strategy(
2863 schema=schema_initial,
2864 do_expl=impl_initial is None,
2874 value_expected = default if value is None else value
2876 default_initial if value_expected is None
2881 dict(schema_initial).get(value_expected, value_expected),
2883 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2884 self.assertEqual(obj.expl_tag, expl or expl_initial)
2887 default_initial if default is None else default,
2889 if obj.default is None:
2890 optional = optional_initial if optional is None else optional
2891 optional = False if optional is None else optional
2894 self.assertEqual(obj.optional, optional)
2895 self.assertEqual(obj.specs, dict(schema_initial))
2897 @given(enumerated_values_strategy())
2898 def test_copy(self, values):
2899 schema_input, value, impl, expl, default, optional, _decoded = values
2901 class E(Enumerated):
2902 schema = schema_input
2911 obj_copied = obj.copy()
2912 self.assert_copied_basic_fields(obj, obj_copied)
2913 self.assertEqual(obj.specs, obj_copied.specs)
2915 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2916 @given(data_strategy())
2917 def test_symmetric(self, d):
2918 schema_input, _, _, _, default, optional, _decoded = d.draw(
2919 enumerated_values_strategy(),
2921 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2922 offset = d.draw(integers(min_value=0))
2923 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2924 tail_junk = d.draw(binary(max_size=5))
2926 class E(Enumerated):
2927 schema = schema_input
2936 pprint(obj, big_blobs=True, with_decode_path=True)
2937 self.assertFalse(obj.expled)
2938 obj_encoded = obj.encode()
2939 obj_expled = obj(value, expl=tag_expl)
2940 self.assertTrue(obj_expled.expled)
2942 list(obj_expled.pps())
2943 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2944 obj_expled_encoded = obj_expled.encode()
2945 ctx_copied = deepcopy(ctx_dummy)
2946 obj_decoded, tail = obj_expled.decode(
2947 obj_expled_encoded + tail_junk,
2951 self.assertDictEqual(ctx_copied, ctx_dummy)
2953 list(obj_decoded.pps())
2954 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2955 self.assertEqual(tail, tail_junk)
2956 self.assertEqual(obj_decoded, obj_expled)
2957 self.assertNotEqual(obj_decoded, obj)
2958 self.assertEqual(int(obj_decoded), int(obj_expled))
2959 self.assertEqual(int(obj_decoded), int(obj))
2960 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2961 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2962 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2964 obj_decoded.expl_llen,
2965 len(len_encode(len(obj_encoded))),
2967 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2968 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2971 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2973 self.assertEqual(obj_decoded.expl_offset, offset)
2977 def string_values_strategy(draw, alphabet, do_expl=False):
2978 bound_min, bound_max = sorted(draw(sets(
2979 integers(min_value=0, max_value=1 << 7),
2983 value = draw(one_of(
2985 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2987 default = draw(one_of(
2989 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2992 if draw(booleans()):
2993 bounds = (bound_min, bound_max)
2997 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2999 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3000 optional = draw(one_of(none(), booleans()))
3002 draw(integers(min_value=0)),
3003 draw(integers(min_value=0)),
3004 draw(integers(min_value=0)),
3006 return (value, bounds, impl, expl, default, optional, _decoded)
3009 class StringMixin(object):
3010 def test_invalid_value_type(self):
3011 with self.assertRaises(InvalidValueType) as err:
3012 self.base_klass((1, 2))
3015 def text_alphabet(self):
3016 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3017 return printable + whitespace
3021 def test_optional(self, optional):
3022 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3023 self.assertTrue(obj.optional)
3025 @given(data_strategy())
3026 def test_ready(self, d):
3027 obj = self.base_klass()
3028 self.assertFalse(obj.ready)
3031 pprint(obj, big_blobs=True, with_decode_path=True)
3033 with self.assertRaises(ObjNotReady) as err:
3036 value = d.draw(text(alphabet=self.text_alphabet()))
3037 obj = self.base_klass(value)
3038 self.assertTrue(obj.ready)
3041 pprint(obj, big_blobs=True, with_decode_path=True)
3044 @given(data_strategy())
3045 def test_comparison(self, d):
3046 value1 = d.draw(text(alphabet=self.text_alphabet()))
3047 value2 = d.draw(text(alphabet=self.text_alphabet()))
3048 tag1 = d.draw(binary(min_size=1))
3049 tag2 = d.draw(binary(min_size=1))
3050 obj1 = self.base_klass(value1)
3051 obj2 = self.base_klass(value2)
3052 self.assertEqual(obj1 == obj2, value1 == value2)
3053 self.assertEqual(obj1 != obj2, value1 != value2)
3054 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3055 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3056 obj1 = self.base_klass(value1, impl=tag1)
3057 obj2 = self.base_klass(value1, impl=tag2)
3058 self.assertEqual(obj1 == obj2, tag1 == tag2)
3059 self.assertEqual(obj1 != obj2, tag1 != tag2)
3061 @given(data_strategy())
3062 def test_bounds_satisfied(self, d):
3063 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3064 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3065 value = d.draw(text(
3066 alphabet=self.text_alphabet(),
3070 self.base_klass(value=value, bounds=(bound_min, bound_max))
3072 @given(data_strategy())
3073 def test_bounds_unsatisfied(self, d):
3074 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3075 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3076 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3077 with self.assertRaises(BoundsError) as err:
3078 self.base_klass(value=value, bounds=(bound_min, bound_max))
3080 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3081 self.base_klass(bounds=(bound_min, bound_max)).decode(
3082 self.base_klass(value).encode()
3085 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3086 with self.assertRaises(BoundsError) as err:
3087 self.base_klass(value=value, bounds=(bound_min, bound_max))
3089 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3090 self.base_klass(bounds=(bound_min, bound_max)).decode(
3091 self.base_klass(value).encode()
3095 @given(data_strategy())
3096 def test_call(self, d):
3105 ) = d.draw(string_values_strategy(self.text_alphabet()))
3106 obj_initial = self.base_klass(
3112 optional_initial or False,
3123 ) = d.draw(string_values_strategy(
3124 self.text_alphabet(),
3125 do_expl=impl_initial is None,
3127 if (default is None) and (obj_initial.default is not None):
3130 (bounds is None) and
3131 (value is not None) and
3132 (bounds_initial is not None) and
3133 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3137 (bounds is None) and
3138 (default is not None) and
3139 (bounds_initial is not None) and
3140 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3143 obj = obj_initial(value, bounds, impl, expl, default, optional)
3145 value_expected = default if value is None else value
3147 default_initial if value_expected is None
3150 self.assertEqual(obj, value_expected)
3151 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3152 self.assertEqual(obj.expl_tag, expl or expl_initial)
3155 default_initial if default is None else default,
3157 if obj.default is None:
3158 optional = optional_initial if optional is None else optional
3159 optional = False if optional is None else optional
3162 self.assertEqual(obj.optional, optional)
3164 (obj._bound_min, obj._bound_max),
3165 bounds or bounds_initial or (0, float("+inf")),
3168 @given(data_strategy())
3169 def test_copy(self, d):
3170 values = d.draw(string_values_strategy(self.text_alphabet()))
3171 obj = self.base_klass(*values)
3172 obj_copied = obj.copy()
3173 self.assert_copied_basic_fields(obj, obj_copied)
3174 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3175 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3176 self.assertEqual(obj._value, obj_copied._value)
3178 @given(data_strategy())
3179 def test_stripped(self, d):
3180 value = d.draw(text(alphabet=self.text_alphabet()))
3181 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3182 obj = self.base_klass(value, impl=tag_impl)
3183 with self.assertRaises(NotEnoughData):
3184 obj.decode(obj.encode()[:-1])
3186 @given(data_strategy())
3187 def test_stripped_expl(self, d):
3188 value = d.draw(text(alphabet=self.text_alphabet()))
3189 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3190 obj = self.base_klass(value, expl=tag_expl)
3191 with self.assertRaises(NotEnoughData):
3192 obj.decode(obj.encode()[:-1])
3195 integers(min_value=31),
3196 integers(min_value=0),
3199 def test_bad_tag(self, tag, offset, decode_path):
3200 with self.assertRaises(DecodeError) as err:
3201 self.base_klass().decode(
3202 tag_encode(tag)[:-1],
3204 decode_path=decode_path,
3207 self.assertEqual(err.exception.offset, offset)
3208 self.assertEqual(err.exception.decode_path, decode_path)
3211 integers(min_value=128),
3212 integers(min_value=0),
3215 def test_bad_len(self, l, offset, decode_path):
3216 with self.assertRaises(DecodeError) as err:
3217 self.base_klass().decode(
3218 self.base_klass.tag_default + len_encode(l)[:-1],
3220 decode_path=decode_path,
3223 self.assertEqual(err.exception.offset, offset)
3224 self.assertEqual(err.exception.decode_path, decode_path)
3227 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3228 integers(min_value=0),
3231 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3232 value, bound_min = list(sorted(ints))
3234 class String(self.base_klass):
3235 # Multiply this value by four, to satisfy UTF-32 bounds
3236 # (4 bytes per character) validation
3237 bounds = (bound_min * 4, bound_min * 4)
3238 with self.assertRaises(DecodeError) as err:
3240 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3242 decode_path=decode_path,
3245 self.assertEqual(err.exception.offset, offset)
3246 self.assertEqual(err.exception.decode_path, decode_path)
3248 @given(data_strategy())
3249 def test_symmetric(self, d):
3250 values = d.draw(string_values_strategy(self.text_alphabet()))
3251 value = d.draw(text(alphabet=self.text_alphabet()))
3252 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3253 offset = d.draw(integers(min_value=0))
3254 tail_junk = d.draw(binary(max_size=5))
3255 _, _, _, _, default, optional, _decoded = values
3256 obj = self.base_klass(
3264 pprint(obj, big_blobs=True, with_decode_path=True)
3265 self.assertFalse(obj.expled)
3266 obj_encoded = obj.encode()
3267 obj_expled = obj(value, expl=tag_expl)
3268 self.assertTrue(obj_expled.expled)
3270 list(obj_expled.pps())
3271 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3272 obj_expled_encoded = obj_expled.encode()
3273 ctx_copied = deepcopy(ctx_dummy)
3274 obj_decoded, tail = obj_expled.decode(
3275 obj_expled_encoded + tail_junk,
3279 self.assertDictEqual(ctx_copied, ctx_dummy)
3281 list(obj_decoded.pps())
3282 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3283 self.assertEqual(tail, tail_junk)
3284 self.assertEqual(obj_decoded, obj_expled)
3285 self.assertNotEqual(obj_decoded, obj)
3286 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3287 self.assertEqual(bytes(obj_decoded), bytes(obj))
3288 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3289 self.assertEqual(text_type(obj_decoded), text_type(obj))
3290 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3291 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3292 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3294 obj_decoded.expl_llen,
3295 len(len_encode(len(obj_encoded))),
3297 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3298 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3301 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3303 self.assertEqual(obj_decoded.expl_offset, offset)
3306 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3307 base_klass = UTF8String
3310 cyrillic_letters = text(
3311 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3317 class UnicodeDecodeErrorMixin(object):
3318 @given(cyrillic_letters)
3319 def test_unicode_decode_error(self, cyrillic_text):
3320 with self.assertRaises(DecodeError):
3321 self.base_klass(cyrillic_text)
3324 class TestNumericString(StringMixin, CommonMixin, TestCase):
3325 base_klass = NumericString
3327 def text_alphabet(self):
3330 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3331 def test_non_numeric(self, non_numeric_text):
3332 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3333 self.base_klass(non_numeric_text)
3336 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3337 integers(min_value=0),
3340 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3341 value, bound_min = list(sorted(ints))
3343 class String(self.base_klass):
3344 bounds = (bound_min, bound_min)
3345 with self.assertRaises(DecodeError) as err:
3347 self.base_klass(b"1" * value).encode(),
3349 decode_path=decode_path,
3352 self.assertEqual(err.exception.offset, offset)
3353 self.assertEqual(err.exception.decode_path, decode_path)
3356 class TestPrintableString(
3357 UnicodeDecodeErrorMixin,
3362 base_klass = PrintableString
3364 def text_alphabet(self):
3365 return ascii_letters + digits + " '()+,-./:=?"
3367 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3368 def test_non_printable(self, non_printable_text):
3369 with assertRaisesRegex(self, DecodeError, "non-printable"):
3370 self.base_klass(non_printable_text)
3373 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3374 integers(min_value=0),
3377 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3378 value, bound_min = list(sorted(ints))
3380 class String(self.base_klass):
3381 bounds = (bound_min, bound_min)
3382 with self.assertRaises(DecodeError) as err:
3384 self.base_klass(b"1" * value).encode(),
3386 decode_path=decode_path,
3389 self.assertEqual(err.exception.offset, offset)
3390 self.assertEqual(err.exception.decode_path, decode_path)
3393 class TestTeletexString(
3394 UnicodeDecodeErrorMixin,
3399 base_klass = TeletexString
3402 class TestVideotexString(
3403 UnicodeDecodeErrorMixin,
3408 base_klass = VideotexString
3411 class TestIA5String(
3412 UnicodeDecodeErrorMixin,
3417 base_klass = IA5String
3420 class TestGraphicString(
3421 UnicodeDecodeErrorMixin,
3426 base_klass = GraphicString
3429 class TestVisibleString(
3430 UnicodeDecodeErrorMixin,
3435 base_klass = VisibleString
3437 def test_x690_vector(self):
3438 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3439 self.assertSequenceEqual(tail, b"")
3440 self.assertEqual(str(obj), "Jones")
3441 self.assertFalse(obj.ber_encoded)
3442 self.assertFalse(obj.lenindef)
3443 self.assertFalse(obj.bered)
3445 obj, tail = VisibleString().decode(
3446 hexdec("3A0904034A6F6E04026573"),
3447 ctx={"bered": True},
3449 self.assertSequenceEqual(tail, b"")
3450 self.assertEqual(str(obj), "Jones")
3451 self.assertTrue(obj.ber_encoded)
3452 self.assertFalse(obj.lenindef)
3453 self.assertTrue(obj.bered)
3455 obj, tail = VisibleString().decode(
3456 hexdec("3A8004034A6F6E040265730000"),
3457 ctx={"bered": True},
3459 self.assertSequenceEqual(tail, b"")
3460 self.assertEqual(str(obj), "Jones")
3461 self.assertTrue(obj.ber_encoded)
3462 self.assertTrue(obj.lenindef)
3463 self.assertTrue(obj.bered)
3466 class TestGeneralString(
3467 UnicodeDecodeErrorMixin,
3472 base_klass = GeneralString
3475 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3476 base_klass = UniversalString
3479 class TestBMPString(StringMixin, CommonMixin, TestCase):
3480 base_klass = BMPString
3484 def generalized_time_values_strategy(
3492 if draw(booleans()):
3493 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3495 value = value.replace(microsecond=0)
3497 if draw(booleans()):
3498 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3500 default = default.replace(microsecond=0)
3504 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3506 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3507 optional = draw(one_of(none(), booleans()))
3509 draw(integers(min_value=0)),
3510 draw(integers(min_value=0)),
3511 draw(integers(min_value=0)),
3513 return (value, impl, expl, default, optional, _decoded)
3516 class TimeMixin(object):
3517 def test_invalid_value_type(self):
3518 with self.assertRaises(InvalidValueType) as err:
3519 self.base_klass(datetime.now().timetuple())
3522 @given(data_strategy())
3523 def test_optional(self, d):
3524 default = d.draw(datetimes(
3525 min_value=self.min_datetime,
3526 max_value=self.max_datetime,
3528 optional = d.draw(booleans())
3529 obj = self.base_klass(default=default, optional=optional)
3530 self.assertTrue(obj.optional)
3532 @given(data_strategy())
3533 def test_ready(self, d):
3534 obj = self.base_klass()
3535 self.assertFalse(obj.ready)
3538 pprint(obj, big_blobs=True, with_decode_path=True)
3539 with self.assertRaises(ObjNotReady) as err:
3542 value = d.draw(datetimes(min_value=self.min_datetime))
3543 obj = self.base_klass(value)
3544 self.assertTrue(obj.ready)
3547 pprint(obj, big_blobs=True, with_decode_path=True)
3549 @given(data_strategy())
3550 def test_comparison(self, d):
3551 value1 = d.draw(datetimes(
3552 min_value=self.min_datetime,
3553 max_value=self.max_datetime,
3555 value2 = d.draw(datetimes(
3556 min_value=self.min_datetime,
3557 max_value=self.max_datetime,
3559 tag1 = d.draw(binary(min_size=1))
3560 tag2 = d.draw(binary(min_size=1))
3562 value1 = value1.replace(microsecond=0)
3563 value2 = value2.replace(microsecond=0)
3564 obj1 = self.base_klass(value1)
3565 obj2 = self.base_klass(value2)
3566 self.assertEqual(obj1 == obj2, value1 == value2)
3567 self.assertEqual(obj1 != obj2, value1 != value2)
3568 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3569 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3570 obj1 = self.base_klass(value1, impl=tag1)
3571 obj2 = self.base_klass(value1, impl=tag2)
3572 self.assertEqual(obj1 == obj2, tag1 == tag2)
3573 self.assertEqual(obj1 != obj2, tag1 != tag2)
3575 @given(data_strategy())
3576 def test_call(self, d):
3584 ) = d.draw(generalized_time_values_strategy(
3585 min_datetime=self.min_datetime,
3586 max_datetime=self.max_datetime,
3587 omit_ms=self.omit_ms,
3589 obj_initial = self.base_klass(
3590 value=value_initial,
3593 default=default_initial,
3594 optional=optional_initial or False,
3595 _decoded=_decoded_initial,
3604 ) = d.draw(generalized_time_values_strategy(
3605 min_datetime=self.min_datetime,
3606 max_datetime=self.max_datetime,
3607 omit_ms=self.omit_ms,
3608 do_expl=impl_initial is None,
3618 value_expected = default if value is None else value
3620 default_initial if value_expected is None
3623 self.assertEqual(obj, value_expected)
3624 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3625 self.assertEqual(obj.expl_tag, expl or expl_initial)
3628 default_initial if default is None else default,
3630 if obj.default is None:
3631 optional = optional_initial if optional is None else optional
3632 optional = False if optional is None else optional
3635 self.assertEqual(obj.optional, optional)
3637 @given(data_strategy())
3638 def test_copy(self, d):
3639 values = d.draw(generalized_time_values_strategy(
3640 min_datetime=self.min_datetime,
3641 max_datetime=self.max_datetime,
3643 obj = self.base_klass(*values)
3644 obj_copied = obj.copy()
3645 self.assert_copied_basic_fields(obj, obj_copied)
3646 self.assertEqual(obj._value, obj_copied._value)
3648 @given(data_strategy())
3649 def test_stripped(self, d):
3650 value = d.draw(datetimes(
3651 min_value=self.min_datetime,
3652 max_value=self.max_datetime,
3654 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3655 obj = self.base_klass(value, impl=tag_impl)
3656 with self.assertRaises(NotEnoughData):
3657 obj.decode(obj.encode()[:-1])
3659 @given(data_strategy())
3660 def test_stripped_expl(self, d):
3661 value = d.draw(datetimes(
3662 min_value=self.min_datetime,
3663 max_value=self.max_datetime,
3665 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3666 obj = self.base_klass(value, expl=tag_expl)
3667 with self.assertRaises(NotEnoughData):
3668 obj.decode(obj.encode()[:-1])
3670 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3671 @given(data_strategy())
3672 def test_symmetric(self, d):
3673 values = d.draw(generalized_time_values_strategy(
3674 min_datetime=self.min_datetime,
3675 max_datetime=self.max_datetime,
3677 value = d.draw(datetimes(
3678 min_value=self.min_datetime,
3679 max_value=self.max_datetime,
3681 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3682 offset = d.draw(integers(min_value=0))
3683 tail_junk = d.draw(binary(max_size=5))
3684 _, _, _, default, optional, _decoded = values
3685 obj = self.base_klass(
3693 pprint(obj, big_blobs=True, with_decode_path=True)
3694 self.assertFalse(obj.expled)
3695 obj_encoded = obj.encode()
3696 obj_expled = obj(value, expl=tag_expl)
3697 self.assertTrue(obj_expled.expled)
3699 list(obj_expled.pps())
3700 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3701 obj_expled_encoded = obj_expled.encode()
3702 ctx_copied = deepcopy(ctx_dummy)
3703 obj_decoded, tail = obj_expled.decode(
3704 obj_expled_encoded + tail_junk,
3708 self.assertDictEqual(ctx_copied, ctx_dummy)
3710 list(obj_decoded.pps())
3711 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3712 self.assertEqual(tail, tail_junk)
3713 self.assertEqual(obj_decoded, obj_expled)
3714 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3715 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3716 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3717 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3718 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3720 obj_decoded.expl_llen,
3721 len(len_encode(len(obj_encoded))),
3723 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3724 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3727 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3729 self.assertEqual(obj_decoded.expl_offset, offset)
3732 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3733 base_klass = GeneralizedTime
3735 min_datetime = datetime(1900, 1, 1)
3736 max_datetime = datetime(9999, 12, 31)
3738 def test_go_vectors_invalid(self):
3750 b"-20100102030410Z",
3751 b"2010-0102030410Z",
3752 b"2010-0002030410Z",
3753 b"201001-02030410Z",
3754 b"20100102-030410Z",
3755 b"2010010203-0410Z",
3756 b"201001020304-10Z",
3757 # These ones are INVALID in *DER*, but accepted
3758 # by Go's encoding/asn1
3759 b"20100102030405+0607",
3760 b"20100102030405-0607",
3762 with self.assertRaises(DecodeError) as err:
3763 GeneralizedTime(data)
3766 def test_go_vectors_valid(self):
3768 GeneralizedTime(b"20100102030405Z").todatetime(),
3769 datetime(2010, 1, 2, 3, 4, 5, 0),
3774 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3775 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3777 binary(min_size=1, max_size=1),
3779 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3780 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3783 def test_junk(self, part0, part1, part2):
3784 junk = part0 + part1 + part2
3785 assume(not (set(junk) <= set(digits.encode("ascii"))))
3786 with self.assertRaises(DecodeError):
3787 GeneralizedTime().decode(
3788 GeneralizedTime.tag_default +
3789 len_encode(len(junk)) +
3795 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3796 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3798 binary(min_size=1, max_size=1),
3800 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3801 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3804 def test_junk_dm(self, part0, part1, part2):
3805 junk = part0 + part1 + part2
3806 assume(not (set(junk) <= set(digits.encode("ascii"))))
3807 with self.assertRaises(DecodeError):
3808 GeneralizedTime().decode(
3809 GeneralizedTime.tag_default +
3810 len_encode(len(junk)) +
3815 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3816 base_klass = UTCTime
3818 min_datetime = datetime(2000, 1, 1)
3819 max_datetime = datetime(2049, 12, 31)
3821 def test_go_vectors_invalid(self):
3847 # These ones are INVALID in *DER*, but accepted
3848 # by Go's encoding/asn1
3849 b"910506164540-0700",
3850 b"910506164540+0730",
3854 with self.assertRaises(DecodeError) as err:
3858 def test_go_vectors_valid(self):
3860 UTCTime(b"910506234540Z").todatetime(),
3861 datetime(1991, 5, 6, 23, 45, 40, 0),
3864 @given(integers(min_value=0, max_value=49))
3865 def test_pre50(self, year):
3867 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3871 @given(integers(min_value=50, max_value=99))
3872 def test_post50(self, year):
3874 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3880 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3881 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3883 binary(min_size=1, max_size=1),
3885 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3886 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3889 def test_junk(self, part0, part1, part2):
3890 junk = part0 + part1 + part2
3891 assume(not (set(junk) <= set(digits.encode("ascii"))))
3892 with self.assertRaises(DecodeError):
3894 UTCTime.tag_default +
3895 len_encode(len(junk)) +
3901 def any_values_strategy(draw, do_expl=False):
3902 value = draw(one_of(none(), binary()))
3905 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3906 optional = draw(one_of(none(), booleans()))
3908 draw(integers(min_value=0)),
3909 draw(integers(min_value=0)),
3910 draw(integers(min_value=0)),
3912 return (value, expl, optional, _decoded)
3915 class AnyInherited(Any):
3919 class TestAny(CommonMixin, TestCase):
3922 def test_invalid_value_type(self):
3923 with self.assertRaises(InvalidValueType) as err:
3928 def test_optional(self, optional):
3929 obj = Any(optional=optional)
3930 self.assertEqual(obj.optional, optional)
3933 def test_ready(self, value):
3935 self.assertFalse(obj.ready)
3938 pprint(obj, big_blobs=True, with_decode_path=True)
3939 with self.assertRaises(ObjNotReady) as err:
3943 self.assertTrue(obj.ready)
3946 pprint(obj, big_blobs=True, with_decode_path=True)
3949 def test_basic(self, value):
3950 integer_encoded = Integer(value).encode()
3952 Any(integer_encoded),
3953 Any(Integer(value)),
3954 Any(Any(Integer(value))),
3956 self.assertSequenceEqual(bytes(obj), integer_encoded)
3958 obj.decode(obj.encode())[0].vlen,
3959 len(integer_encoded),
3963 pprint(obj, big_blobs=True, with_decode_path=True)
3964 self.assertSequenceEqual(obj.encode(), integer_encoded)
3966 @given(binary(), binary())
3967 def test_comparison(self, value1, value2):
3968 for klass in (Any, AnyInherited):
3969 obj1 = klass(value1)
3970 obj2 = klass(value2)
3971 self.assertEqual(obj1 == obj2, value1 == value2)
3972 self.assertEqual(obj1 != obj2, value1 != value2)
3973 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3975 @given(data_strategy())
3976 def test_call(self, d):
3977 for klass in (Any, AnyInherited):
3983 ) = d.draw(any_values_strategy())
3984 obj_initial = klass(
3987 optional_initial or False,
3995 ) = d.draw(any_values_strategy(do_expl=True))
3996 obj = obj_initial(value, expl, optional)
3998 value_expected = None if value is None else value
3999 self.assertEqual(obj, value_expected)
4000 self.assertEqual(obj.expl_tag, expl or expl_initial)
4001 if obj.default is None:
4002 optional = optional_initial if optional is None else optional
4003 optional = False if optional is None else optional
4004 self.assertEqual(obj.optional, optional)
4006 def test_simultaneous_impl_expl(self):
4007 # override it, as Any does not have implicit tag
4010 def test_decoded(self):
4011 # override it, as Any does not have implicit tag
4014 @given(any_values_strategy())
4015 def test_copy(self, values):
4016 for klass in (Any, AnyInherited):
4017 obj = klass(*values)
4018 obj_copied = obj.copy()
4019 self.assert_copied_basic_fields(obj, obj_copied)
4020 self.assertEqual(obj._value, obj_copied._value)
4022 @given(binary().map(OctetString))
4023 def test_stripped(self, value):
4025 with self.assertRaises(NotEnoughData):
4026 obj.decode(obj.encode()[:-1])
4030 integers(min_value=1).map(tag_ctxc),
4032 def test_stripped_expl(self, value, tag_expl):
4033 obj = Any(value, expl=tag_expl)
4034 with self.assertRaises(NotEnoughData):
4035 obj.decode(obj.encode()[:-1])
4038 integers(min_value=31),
4039 integers(min_value=0),
4042 def test_bad_tag(self, tag, offset, decode_path):
4043 with self.assertRaises(DecodeError) as err:
4045 tag_encode(tag)[:-1],
4047 decode_path=decode_path,
4050 self.assertEqual(err.exception.offset, offset)
4051 self.assertEqual(err.exception.decode_path, decode_path)
4054 integers(min_value=128),
4055 integers(min_value=0),
4058 def test_bad_len(self, l, offset, decode_path):
4059 with self.assertRaises(DecodeError) as err:
4061 Any.tag_default + len_encode(l)[:-1],
4063 decode_path=decode_path,
4066 self.assertEqual(err.exception.offset, offset)
4067 self.assertEqual(err.exception.decode_path, decode_path)
4069 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4071 any_values_strategy(),
4072 integers().map(lambda x: Integer(x).encode()),
4073 integers(min_value=1).map(tag_ctxc),
4074 integers(min_value=0),
4077 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4078 for klass in (Any, AnyInherited):
4079 _, _, optional, _decoded = values
4080 obj = klass(value=value, optional=optional, _decoded=_decoded)
4083 pprint(obj, big_blobs=True, with_decode_path=True)
4084 self.assertFalse(obj.expled)
4085 obj_encoded = obj.encode()
4086 obj_expled = obj(value, expl=tag_expl)
4087 self.assertTrue(obj_expled.expled)
4089 list(obj_expled.pps())
4090 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4091 obj_expled_encoded = obj_expled.encode()
4092 ctx_copied = deepcopy(ctx_dummy)
4093 obj_decoded, tail = obj_expled.decode(
4094 obj_expled_encoded + tail_junk,
4098 self.assertDictEqual(ctx_copied, ctx_dummy)
4100 list(obj_decoded.pps())
4101 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4102 self.assertEqual(tail, tail_junk)
4103 self.assertEqual(obj_decoded, obj_expled)
4104 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4105 self.assertEqual(bytes(obj_decoded), bytes(obj))
4106 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4107 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4108 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4110 obj_decoded.expl_llen,
4111 len(len_encode(len(obj_encoded))),
4113 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4114 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4117 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4119 self.assertEqual(obj_decoded.expl_offset, offset)
4120 self.assertEqual(obj_decoded.tlen, 0)
4121 self.assertEqual(obj_decoded.llen, 0)
4122 self.assertEqual(obj_decoded.vlen, len(value))
4125 integers(min_value=1).map(tag_ctxc),
4126 integers(min_value=0, max_value=3),
4127 integers(min_value=0),
4131 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4132 chunk = Boolean(False, expl=expl).encode()
4134 OctetString.tag_default +
4136 b"".join([chunk] * chunks) +
4139 with self.assertRaises(LenIndefForm):
4143 decode_path=decode_path,
4145 obj, tail = Any().decode(
4148 decode_path=decode_path,
4149 ctx={"bered": True},
4151 self.assertSequenceEqual(tail, junk)
4152 self.assertEqual(obj.offset, offset)
4153 self.assertEqual(obj.tlvlen, len(encoded))
4154 self.assertTrue(obj.lenindef)
4155 self.assertFalse(obj.ber_encoded)
4156 self.assertTrue(obj.bered)
4159 pprint(obj, big_blobs=True, with_decode_path=True)
4160 with self.assertRaises(NotEnoughData) as err:
4164 decode_path=decode_path,
4165 ctx={"bered": True},
4167 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4168 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4170 class SeqOf(SequenceOf):
4171 schema = Boolean(expl=expl)
4173 class Seq(Sequence):
4175 ("type", ObjectIdentifier(defines=((("value",), {
4176 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4181 ("type", ObjectIdentifier("1.2.3")),
4182 ("value", Any(encoded)),
4184 seq_encoded = seq.encode()
4185 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4186 self.assertIsNotNone(seq_decoded["value"].defined)
4188 list(seq_decoded.pps())
4189 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4190 self.assertTrue(seq_decoded.bered)
4191 self.assertFalse(seq_decoded["type"].bered)
4192 self.assertTrue(seq_decoded["value"].bered)
4194 chunk = chunk[:-1] + b"\x01"
4195 chunks = b"".join([chunk] * (chunks + 1))
4196 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4198 ("type", ObjectIdentifier("1.2.3")),
4199 ("value", Any(encoded)),
4201 seq_encoded = seq.encode()
4202 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4203 self.assertIsNotNone(seq_decoded["value"].defined)
4205 list(seq_decoded.pps())
4206 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4207 self.assertTrue(seq_decoded.bered)
4208 self.assertFalse(seq_decoded["type"].bered)
4209 self.assertTrue(seq_decoded["value"].bered)
4213 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4215 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4216 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4218 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4219 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4221 min_size=len(names),
4222 max_size=len(names),
4225 (name, Integer(**tag_kwargs))
4226 for name, tag_kwargs in zip(names, tags)
4229 if value_required or draw(booleans()):
4230 value = draw(tuples(
4231 sampled_from([name for name, _ in schema]),
4232 integers().map(Integer),
4236 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4237 default = draw(one_of(
4239 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4241 optional = draw(one_of(none(), booleans()))
4243 draw(integers(min_value=0)),
4244 draw(integers(min_value=0)),
4245 draw(integers(min_value=0)),
4247 return (schema, value, expl, default, optional, _decoded)
4250 class ChoiceInherited(Choice):
4254 class TestChoice(CommonMixin, TestCase):
4256 schema = (("whatever", Boolean()),)
4259 def test_schema_required(self):
4260 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4263 def test_impl_forbidden(self):
4264 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4265 Choice(impl=b"whatever")
4267 def test_invalid_value_type(self):
4268 with self.assertRaises(InvalidValueType) as err:
4269 self.base_klass(123)
4271 with self.assertRaises(ObjUnknown) as err:
4272 self.base_klass(("whenever", Boolean(False)))
4274 with self.assertRaises(InvalidValueType) as err:
4275 self.base_klass(("whatever", Integer(123)))
4279 def test_optional(self, optional):
4280 obj = self.base_klass(
4281 default=self.base_klass(("whatever", Boolean(False))),
4284 self.assertTrue(obj.optional)
4287 def test_ready(self, value):
4288 obj = self.base_klass()
4289 self.assertFalse(obj.ready)
4292 pprint(obj, big_blobs=True, with_decode_path=True)
4293 self.assertIsNone(obj["whatever"])
4294 with self.assertRaises(ObjNotReady) as err:
4297 obj["whatever"] = Boolean()
4298 self.assertFalse(obj.ready)
4301 pprint(obj, big_blobs=True, with_decode_path=True)
4302 obj["whatever"] = Boolean(value)
4303 self.assertTrue(obj.ready)
4306 pprint(obj, big_blobs=True, with_decode_path=True)
4308 @given(booleans(), booleans())
4309 def test_comparison(self, value1, value2):
4310 class WahlInherited(self.base_klass):
4312 for klass in (self.base_klass, WahlInherited):
4313 obj1 = klass(("whatever", Boolean(value1)))
4314 obj2 = klass(("whatever", Boolean(value2)))
4315 self.assertEqual(obj1 == obj2, value1 == value2)
4316 self.assertEqual(obj1 != obj2, value1 != value2)
4317 self.assertEqual(obj1 == obj2._value, value1 == value2)
4318 self.assertFalse(obj1 == obj2._value[1])
4320 @given(data_strategy())
4321 def test_call(self, d):
4322 for klass in (Choice, ChoiceInherited):
4330 ) = d.draw(choice_values_strategy())
4333 schema = schema_initial
4335 value=value_initial,
4337 default=default_initial,
4338 optional=optional_initial or False,
4339 _decoded=_decoded_initial,
4348 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4349 obj = obj_initial(value, expl, default, optional)
4351 value_expected = default if value is None else value
4353 default_initial if value_expected is None
4356 self.assertEqual(obj.choice, value_expected[0])
4357 self.assertEqual(obj.value, int(value_expected[1]))
4358 self.assertEqual(obj.expl_tag, expl or expl_initial)
4359 default_expect = default_initial if default is None else default
4360 if default_expect is not None:
4361 self.assertEqual(obj.default.choice, default_expect[0])
4362 self.assertEqual(obj.default.value, int(default_expect[1]))
4363 if obj.default is None:
4364 optional = optional_initial if optional is None else optional
4365 optional = False if optional is None else optional
4368 self.assertEqual(obj.optional, optional)
4369 self.assertEqual(obj.specs, obj_initial.specs)
4371 def test_simultaneous_impl_expl(self):
4372 # override it, as Any does not have implicit tag
4375 def test_decoded(self):
4376 # override it, as Any does not have implicit tag
4379 @given(choice_values_strategy())
4380 def test_copy(self, values):
4381 _schema, value, expl, default, optional, _decoded = values
4383 class Wahl(self.base_klass):
4389 optional=optional or False,
4392 obj_copied = obj.copy()
4393 self.assertIsNone(obj.tag)
4394 self.assertIsNone(obj_copied.tag)
4395 # hack for assert_copied_basic_fields
4396 obj.tag = "whatever"
4397 obj_copied.tag = "whatever"
4398 self.assert_copied_basic_fields(obj, obj_copied)
4399 self.assertEqual(obj._value, obj_copied._value)
4400 self.assertEqual(obj.specs, obj_copied.specs)
4403 def test_stripped(self, value):
4404 obj = self.base_klass(("whatever", Boolean(value)))
4405 with self.assertRaises(NotEnoughData):
4406 obj.decode(obj.encode()[:-1])
4410 integers(min_value=1).map(tag_ctxc),
4412 def test_stripped_expl(self, value, tag_expl):
4413 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4414 with self.assertRaises(NotEnoughData):
4415 obj.decode(obj.encode()[:-1])
4417 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4418 @given(data_strategy())
4419 def test_symmetric(self, d):
4420 _schema, value, _, default, optional, _decoded = d.draw(
4421 choice_values_strategy(value_required=True)
4423 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4424 offset = d.draw(integers(min_value=0))
4425 tail_junk = d.draw(binary(max_size=5))
4427 class Wahl(self.base_klass):
4437 pprint(obj, big_blobs=True, with_decode_path=True)
4438 self.assertFalse(obj.expled)
4439 obj_encoded = obj.encode()
4440 obj_expled = obj(value, expl=tag_expl)
4441 self.assertTrue(obj_expled.expled)
4443 list(obj_expled.pps())
4444 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4445 obj_expled_encoded = obj_expled.encode()
4446 ctx_copied = deepcopy(ctx_dummy)
4447 obj_decoded, tail = obj_expled.decode(
4448 obj_expled_encoded + tail_junk,
4452 self.assertDictEqual(ctx_copied, ctx_dummy)
4454 list(obj_decoded.pps())
4455 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4456 self.assertEqual(tail, tail_junk)
4457 self.assertEqual(obj_decoded, obj_expled)
4458 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4459 self.assertEqual(obj_decoded.value, obj_expled.value)
4460 self.assertEqual(obj_decoded.choice, obj.choice)
4461 self.assertEqual(obj_decoded.value, obj.value)
4462 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4463 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4464 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4466 obj_decoded.expl_llen,
4467 len(len_encode(len(obj_encoded))),
4469 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4470 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4473 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4475 self.assertEqual(obj_decoded.expl_offset, offset)
4476 self.assertSequenceEqual(
4478 obj_decoded.value.fulloffset - offset:
4479 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4485 def test_set_get(self, value):
4488 ("erste", Boolean()),
4489 ("zweite", Integer()),
4492 with self.assertRaises(ObjUnknown) as err:
4493 obj["whatever"] = "whenever"
4494 with self.assertRaises(InvalidValueType) as err:
4495 obj["zweite"] = Boolean(False)
4496 obj["zweite"] = Integer(value)
4498 with self.assertRaises(ObjUnknown) as err:
4501 self.assertIsNone(obj["erste"])
4502 self.assertEqual(obj["zweite"], Integer(value))
4504 def test_tag_mismatch(self):
4507 ("erste", Boolean()),
4509 int_encoded = Integer(123).encode()
4510 bool_encoded = Boolean(False).encode()
4512 obj.decode(bool_encoded)
4513 with self.assertRaises(TagMismatch):
4514 obj.decode(int_encoded)
4516 def test_tag_mismatch_underlying(self):
4517 class SeqOfBoolean(SequenceOf):
4520 class SeqOfInteger(SequenceOf):
4525 ("erste", SeqOfBoolean()),
4528 int_encoded = SeqOfInteger((Integer(123),)).encode()
4529 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4531 obj.decode(bool_encoded)
4532 with self.assertRaises(TagMismatch) as err:
4533 obj.decode(int_encoded)
4534 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4538 def seq_values_strategy(draw, seq_klass, do_expl=False):
4540 if draw(booleans()):
4543 k: v for k, v in draw(dictionaries(
4546 booleans().map(Boolean),
4547 integers().map(Integer),
4552 if draw(booleans()):
4553 schema = list(draw(dictionaries(
4556 booleans().map(Boolean),
4557 integers().map(Integer),
4563 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4565 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4567 if draw(booleans()):
4568 default = seq_klass()
4570 k: v for k, v in draw(dictionaries(
4573 booleans().map(Boolean),
4574 integers().map(Integer),
4578 optional = draw(one_of(none(), booleans()))
4580 draw(integers(min_value=0)),
4581 draw(integers(min_value=0)),
4582 draw(integers(min_value=0)),
4584 return (value, schema, impl, expl, default, optional, _decoded)
4588 def sequence_strategy(draw, seq_klass):
4589 inputs = draw(lists(
4591 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4592 tuples(just(Integer), integers(), one_of(none(), integers())),
4597 integers(min_value=1),
4598 min_size=len(inputs),
4599 max_size=len(inputs),
4602 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4603 for tag, expled in zip(tags, draw(lists(
4605 min_size=len(inputs),
4606 max_size=len(inputs),
4610 for i, optional in enumerate(draw(lists(
4611 sampled_from(("required", "optional", "empty")),
4612 min_size=len(inputs),
4613 max_size=len(inputs),
4615 if optional in ("optional", "empty"):
4616 inits[i]["optional"] = True
4617 if optional == "empty":
4619 empties = set(empties)
4620 names = list(draw(sets(
4622 min_size=len(inputs),
4623 max_size=len(inputs),
4626 for i, (klass, value, default) in enumerate(inputs):
4627 schema.append((names[i], klass(default=default, **inits[i])))
4628 seq_name = draw(text_letters())
4629 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4632 for i, (klass, value, default) in enumerate(inputs):
4639 "default_value": None if spec.default is None else default,
4643 expect["optional"] = True
4645 expect["presented"] = True
4646 expect["value"] = value
4648 expect["optional"] = True
4649 if default is not None and default == value:
4650 expect["presented"] = False
4651 seq[name] = klass(value)
4652 expects.append(expect)
4657 def sequences_strategy(draw, seq_klass):
4658 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4660 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4661 for tag, expled in zip(tags, draw(lists(
4668 i for i, is_default in enumerate(draw(lists(
4674 names = list(draw(sets(
4679 seq_expectses = draw(lists(
4680 sequence_strategy(seq_klass=seq_klass),
4684 seqs = [seq for seq, _ in seq_expectses]
4686 for i, (name, seq) in enumerate(zip(names, seqs)):
4689 seq(default=(seq if i in defaulted else None), **inits[i]),
4691 seq_name = draw(text_letters())
4692 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4695 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4698 "expects": expects_inner,
4701 seq_outer[name] = seq_inner
4702 if seq_outer.specs[name].default is None:
4703 expect["presented"] = True
4704 expect_outers.append(expect)
4705 return seq_outer, expect_outers
4708 class SeqMixing(object):
4709 def test_invalid_value_type(self):
4710 with self.assertRaises(InvalidValueType) as err:
4711 self.base_klass(123)
4714 def test_invalid_value_type_set(self):
4715 class Seq(self.base_klass):
4716 schema = (("whatever", Boolean()),)
4718 with self.assertRaises(InvalidValueType) as err:
4719 seq["whatever"] = Integer(123)
4723 def test_optional(self, optional):
4724 obj = self.base_klass(default=self.base_klass(), optional=optional)
4725 self.assertTrue(obj.optional)
4727 @given(data_strategy())
4728 def test_ready(self, d):
4730 str(i): v for i, v in enumerate(d.draw(lists(
4737 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4744 for name in d.draw(permutations(
4745 list(ready.keys()) + list(non_ready.keys()),
4747 schema_input.append((name, Boolean()))
4749 class Seq(self.base_klass):
4750 schema = tuple(schema_input)
4752 for name in ready.keys():
4754 seq[name] = Boolean()
4755 self.assertFalse(seq.ready)
4758 pprint(seq, big_blobs=True, with_decode_path=True)
4759 for name, value in ready.items():
4760 seq[name] = Boolean(value)
4761 self.assertFalse(seq.ready)
4764 pprint(seq, big_blobs=True, with_decode_path=True)
4765 with self.assertRaises(ObjNotReady) as err:
4768 for name, value in non_ready.items():
4769 seq[name] = Boolean(value)
4770 self.assertTrue(seq.ready)
4773 pprint(seq, big_blobs=True, with_decode_path=True)
4775 @given(data_strategy())
4776 def test_call(self, d):
4777 class SeqInherited(self.base_klass):
4779 for klass in (self.base_klass, SeqInherited):
4788 ) = d.draw(seq_values_strategy(seq_klass=klass))
4789 obj_initial = klass(
4795 optional_initial or False,
4806 ) = d.draw(seq_values_strategy(
4808 do_expl=impl_initial is None,
4810 obj = obj_initial(value, impl, expl, default, optional)
4811 value_expected = default if value is None else value
4813 default_initial if value_expected is None
4816 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4817 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4818 self.assertEqual(obj.expl_tag, expl or expl_initial)
4820 {} if obj.default is None else obj.default._value,
4821 getattr(default_initial if default is None else default, "_value", {}),
4823 if obj.default is None:
4824 optional = optional_initial if optional is None else optional
4825 optional = False if optional is None else optional
4828 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4829 self.assertEqual(obj.optional, optional)
4831 @given(data_strategy())
4832 def test_copy(self, d):
4833 class SeqInherited(self.base_klass):
4835 for klass in (self.base_klass, SeqInherited):
4836 values = d.draw(seq_values_strategy(seq_klass=klass))
4837 obj = klass(*values)
4838 obj_copied = obj.copy()
4839 self.assert_copied_basic_fields(obj, obj_copied)
4840 self.assertEqual(obj.specs, obj_copied.specs)
4841 self.assertEqual(obj._value, obj_copied._value)
4843 @given(data_strategy())
4844 def test_stripped(self, d):
4845 value = d.draw(integers())
4846 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4848 class Seq(self.base_klass):
4850 schema = (("whatever", Integer()),)
4852 seq["whatever"] = Integer(value)
4853 with self.assertRaises(NotEnoughData):
4854 seq.decode(seq.encode()[:-1])
4856 @given(data_strategy())
4857 def test_stripped_expl(self, d):
4858 value = d.draw(integers())
4859 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4861 class Seq(self.base_klass):
4863 schema = (("whatever", Integer()),)
4865 seq["whatever"] = Integer(value)
4866 with self.assertRaises(NotEnoughData):
4867 seq.decode(seq.encode()[:-1])
4869 @given(binary(min_size=2))
4870 def test_non_tag_mismatch_raised(self, junk):
4872 _, _, len_encoded = tag_strip(memoryview(junk))
4873 len_decode(len_encoded)
4879 class Seq(self.base_klass):
4881 ("whatever", Integer()),
4883 ("whenever", Integer()),
4886 seq["whatever"] = Integer(123)
4887 seq["junk"] = Any(junk)
4888 seq["whenever"] = Integer(123)
4889 with self.assertRaises(DecodeError):
4890 seq.decode(seq.encode())
4893 integers(min_value=31),
4894 integers(min_value=0),
4897 def test_bad_tag(self, tag, offset, decode_path):
4898 with self.assertRaises(DecodeError) as err:
4899 self.base_klass().decode(
4900 tag_encode(tag)[:-1],
4902 decode_path=decode_path,
4905 self.assertEqual(err.exception.offset, offset)
4906 self.assertEqual(err.exception.decode_path, decode_path)
4909 integers(min_value=128),
4910 integers(min_value=0),
4913 def test_bad_len(self, l, offset, decode_path):
4914 with self.assertRaises(DecodeError) as err:
4915 self.base_klass().decode(
4916 self.base_klass.tag_default + len_encode(l)[:-1],
4918 decode_path=decode_path,
4921 self.assertEqual(err.exception.offset, offset)
4922 self.assertEqual(err.exception.decode_path, decode_path)
4924 def _assert_expects(self, seq, expects):
4925 for expect in expects:
4927 seq.specs[expect["name"]].optional,
4930 if expect["default_value"] is not None:
4932 seq.specs[expect["name"]].default,
4933 expect["default_value"],
4935 if expect["presented"]:
4936 self.assertIn(expect["name"], seq)
4937 self.assertEqual(seq[expect["name"]], expect["value"])
4939 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4940 @given(data_strategy())
4941 def test_symmetric(self, d):
4942 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4943 tail_junk = d.draw(binary(max_size=5))
4944 self.assertTrue(seq.ready)
4945 self.assertFalse(seq.decoded)
4946 self._assert_expects(seq, expects)
4949 pprint(seq, big_blobs=True, with_decode_path=True)
4950 self.assertTrue(seq.ready)
4951 seq_encoded = seq.encode()
4952 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4953 self.assertFalse(seq_decoded.lenindef)
4954 self.assertFalse(seq_decoded.ber_encoded)
4955 self.assertFalse(seq_decoded.bered)
4957 t, _, lv = tag_strip(seq_encoded)
4958 _, _, v = len_decode(lv)
4959 seq_encoded_lenindef = t + LENINDEF + v + EOC
4960 ctx_copied = deepcopy(ctx_dummy)
4961 ctx_copied["bered"] = True
4962 seq_decoded_lenindef, tail_lenindef = seq.decode(
4963 seq_encoded_lenindef + tail_junk,
4966 del ctx_copied["bered"]
4967 self.assertDictEqual(ctx_copied, ctx_dummy)
4968 self.assertTrue(seq_decoded_lenindef.lenindef)
4969 self.assertTrue(seq_decoded_lenindef.bered)
4970 with self.assertRaises(DecodeError):
4971 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4972 with self.assertRaises(DecodeError):
4973 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4974 repr(seq_decoded_lenindef)
4975 list(seq_decoded_lenindef.pps())
4976 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
4977 self.assertTrue(seq_decoded_lenindef.ready)
4979 for decoded, decoded_tail, encoded in (
4980 (seq_decoded, tail, seq_encoded),
4981 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4983 self.assertEqual(decoded_tail, tail_junk)
4984 self._assert_expects(decoded, expects)
4985 self.assertEqual(seq, decoded)
4986 self.assertEqual(decoded.encode(), seq_encoded)
4987 self.assertEqual(decoded.tlvlen, len(encoded))
4988 for expect in expects:
4989 if not expect["presented"]:
4990 self.assertNotIn(expect["name"], decoded)
4992 self.assertIn(expect["name"], decoded)
4993 obj = decoded[expect["name"]]
4994 self.assertTrue(obj.decoded)
4995 offset = obj.expl_offset if obj.expled else obj.offset
4996 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4997 self.assertSequenceEqual(
4998 seq_encoded[offset:offset + tlvlen],
5002 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5003 @given(data_strategy())
5004 def test_symmetric_with_seq(self, d):
5005 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5006 self.assertTrue(seq.ready)
5007 seq_encoded = seq.encode()
5008 seq_decoded, tail = seq.decode(seq_encoded)
5009 self.assertEqual(tail, b"")
5010 self.assertTrue(seq.ready)
5011 self.assertEqual(seq, seq_decoded)
5012 self.assertEqual(seq_decoded.encode(), seq_encoded)
5013 for expect_outer in expect_outers:
5014 if not expect_outer["presented"]:
5015 self.assertNotIn(expect_outer["name"], seq_decoded)
5017 self.assertIn(expect_outer["name"], seq_decoded)
5018 obj = seq_decoded[expect_outer["name"]]
5019 self.assertTrue(obj.decoded)
5020 offset = obj.expl_offset if obj.expled else obj.offset
5021 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5022 self.assertSequenceEqual(
5023 seq_encoded[offset:offset + tlvlen],
5026 self._assert_expects(obj, expect_outer["expects"])
5028 @given(data_strategy())
5029 def test_default_disappears(self, d):
5030 _schema = list(d.draw(dictionaries(
5032 sets(integers(), min_size=2, max_size=2),
5036 class Seq(self.base_klass):
5038 (n, Integer(default=d))
5039 for n, (_, d) in _schema
5042 for name, (value, _) in _schema:
5043 seq[name] = Integer(value)
5044 self.assertEqual(len(seq._value), len(_schema))
5045 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5046 self.assertGreater(len(seq.encode()), len(empty_seq))
5047 for name, (_, default) in _schema:
5048 seq[name] = Integer(default)
5049 self.assertEqual(len(seq._value), 0)
5050 self.assertSequenceEqual(seq.encode(), empty_seq)
5052 @given(data_strategy())
5053 def test_encoded_default_not_accepted(self, d):
5054 _schema = list(d.draw(dictionaries(
5059 tags = [tag_encode(tag) for tag in d.draw(sets(
5060 integers(min_value=0),
5061 min_size=len(_schema),
5062 max_size=len(_schema),
5065 class SeqWithoutDefault(self.base_klass):
5067 (n, Integer(impl=t))
5068 for (n, _), t in zip(_schema, tags)
5070 seq_without_default = SeqWithoutDefault()
5071 for name, value in _schema:
5072 seq_without_default[name] = Integer(value)
5073 seq_encoded = seq_without_default.encode()
5075 class SeqWithDefault(self.base_klass):
5077 (n, Integer(default=v, impl=t))
5078 for (n, v), t in zip(_schema, tags)
5080 seq_with_default = SeqWithDefault()
5081 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5082 seq_with_default.decode(seq_encoded)
5083 for ctx in ({"bered": True}, {"allow_default_values": True}):
5084 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5085 self.assertTrue(seq_decoded.ber_encoded)
5086 self.assertTrue(seq_decoded.bered)
5087 for name, value in _schema:
5088 self.assertEqual(seq_decoded[name], seq_with_default[name])
5089 self.assertEqual(seq_decoded[name], value)
5091 @given(data_strategy())
5092 def test_missing_from_spec(self, d):
5093 names = list(d.draw(sets(text_letters(), min_size=2)))
5094 tags = [tag_encode(tag) for tag in d.draw(sets(
5095 integers(min_value=0),
5096 min_size=len(names),
5097 max_size=len(names),
5099 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5101 class SeqFull(self.base_klass):
5102 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5103 seq_full = SeqFull()
5104 for i, name in enumerate(names):
5105 seq_full[name] = Integer(i)
5106 seq_encoded = seq_full.encode()
5107 altered = names_tags[:-2] + names_tags[-1:]
5109 class SeqMissing(self.base_klass):
5110 schema = [(n, Integer(impl=t)) for n, t in altered]
5111 seq_missing = SeqMissing()
5112 with self.assertRaises(TagMismatch):
5113 seq_missing.decode(seq_encoded)
5115 @given(data_strategy())
5116 def test_bered(self, d):
5117 class Seq(self.base_klass):
5118 schema = (("underlying", Boolean()),)
5119 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5120 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5121 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5122 self.assertFalse(decoded.ber_encoded)
5123 self.assertFalse(decoded.lenindef)
5124 self.assertTrue(decoded.bered)
5126 class Seq(self.base_klass):
5127 schema = (("underlying", OctetString()),)
5129 tag_encode(form=TagFormConstructed, num=4) +
5131 OctetString(b"whatever").encode() +
5134 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5135 with self.assertRaises(DecodeError):
5136 Seq().decode(encoded)
5137 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5138 self.assertFalse(decoded.ber_encoded)
5139 self.assertFalse(decoded.lenindef)
5140 self.assertTrue(decoded.bered)
5143 class TestSequence(SeqMixing, CommonMixin, TestCase):
5144 base_klass = Sequence
5150 def test_remaining(self, value, junk):
5151 class Seq(Sequence):
5153 ("whatever", Integer()),
5155 int_encoded = Integer(value).encode()
5157 Sequence.tag_default,
5158 len_encode(len(int_encoded + junk)),
5161 with assertRaisesRegex(self, DecodeError, "remaining"):
5162 Seq().decode(junked)
5164 @given(sets(text_letters(), min_size=2))
5165 def test_obj_unknown(self, names):
5166 missing = names.pop()
5168 class Seq(Sequence):
5169 schema = [(n, Boolean()) for n in names]
5171 with self.assertRaises(ObjUnknown) as err:
5174 with self.assertRaises(ObjUnknown) as err:
5175 seq[missing] = Boolean()
5178 def test_x690_vector(self):
5179 class Seq(Sequence):
5181 ("name", IA5String()),
5184 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5185 self.assertEqual(seq["name"], "Smith")
5186 self.assertEqual(seq["ok"], True)
5189 class TestSet(SeqMixing, CommonMixin, TestCase):
5192 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5193 @given(data_strategy())
5194 def test_sorted(self, d):
5196 tag_encode(tag) for tag in
5197 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5201 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5203 for name, _ in Seq.schema:
5204 seq[name] = OctetString(b"")
5205 seq_encoded = seq.encode()
5206 seq_decoded, _ = seq.decode(seq_encoded)
5207 self.assertSequenceEqual(
5208 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5209 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5212 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5213 @given(data_strategy())
5214 def test_unsorted(self, d):
5216 tag_encode(tag) for tag in
5217 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5219 tags = d.draw(permutations(tags))
5220 assume(tags != sorted(tags))
5221 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5222 seq_encoded = b"".join((
5224 len_encode(len(encoded)),
5229 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5231 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5232 seq.decode(seq_encoded)
5233 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5234 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5235 self.assertTrue(seq_decoded.ber_encoded)
5236 self.assertTrue(seq_decoded.bered)
5237 self.assertSequenceEqual(
5238 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5244 def seqof_values_strategy(draw, schema=None, do_expl=False):
5246 schema = draw(sampled_from((Boolean(), Integer())))
5247 bound_min, bound_max = sorted(draw(sets(
5248 integers(min_value=0, max_value=10),
5252 if isinstance(schema, Boolean):
5253 values_generator = booleans().map(Boolean)
5254 elif isinstance(schema, Integer):
5255 values_generator = integers().map(Integer)
5256 values_generator = lists(
5261 values = draw(one_of(none(), values_generator))
5265 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5267 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5268 default = draw(one_of(none(), values_generator))
5269 optional = draw(one_of(none(), booleans()))
5271 draw(integers(min_value=0)),
5272 draw(integers(min_value=0)),
5273 draw(integers(min_value=0)),
5278 (bound_min, bound_max),
5287 class SeqOfMixing(object):
5288 def test_invalid_value_type(self):
5289 with self.assertRaises(InvalidValueType) as err:
5290 self.base_klass(123)
5293 def test_invalid_values_type(self):
5294 class SeqOf(self.base_klass):
5296 with self.assertRaises(InvalidValueType) as err:
5297 SeqOf([Integer(123), Boolean(False), Integer(234)])
5300 def test_schema_required(self):
5301 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5302 self.base_klass.__mro__[1]()
5304 @given(booleans(), booleans(), binary(), binary())
5305 def test_comparison(self, value1, value2, tag1, tag2):
5306 class SeqOf(self.base_klass):
5308 obj1 = SeqOf([Boolean(value1)])
5309 obj2 = SeqOf([Boolean(value2)])
5310 self.assertEqual(obj1 == obj2, value1 == value2)
5311 self.assertEqual(obj1 != obj2, value1 != value2)
5312 self.assertEqual(obj1 == list(obj2), value1 == value2)
5313 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5314 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5315 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5316 self.assertEqual(obj1 == obj2, tag1 == tag2)
5317 self.assertEqual(obj1 != obj2, tag1 != tag2)
5319 @given(lists(booleans()))
5320 def test_iter(self, values):
5321 class SeqOf(self.base_klass):
5323 obj = SeqOf([Boolean(value) for value in values])
5324 self.assertEqual(len(obj), len(values))
5325 for i, value in enumerate(obj):
5326 self.assertEqual(value, values[i])
5328 @given(data_strategy())
5329 def test_ready(self, d):
5330 ready = [Integer(v) for v in d.draw(lists(
5337 range(d.draw(integers(min_value=1, max_value=5)))
5340 class SeqOf(self.base_klass):
5342 values = d.draw(permutations(ready + non_ready))
5344 for value in values:
5346 self.assertFalse(seqof.ready)
5349 pprint(seqof, big_blobs=True, with_decode_path=True)
5350 with self.assertRaises(ObjNotReady) as err:
5353 for i, value in enumerate(values):
5354 self.assertEqual(seqof[i], value)
5355 if not seqof[i].ready:
5356 seqof[i] = Integer(i)
5357 self.assertTrue(seqof.ready)
5360 pprint(seqof, big_blobs=True, with_decode_path=True)
5362 def test_spec_mismatch(self):
5363 class SeqOf(self.base_klass):
5366 seqof.append(Integer(123))
5367 with self.assertRaises(ValueError):
5368 seqof.append(Boolean(False))
5369 with self.assertRaises(ValueError):
5370 seqof[0] = Boolean(False)
5372 @given(data_strategy())
5373 def test_bounds_satisfied(self, d):
5374 class SeqOf(self.base_klass):
5376 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5377 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5378 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5379 SeqOf(value=value, bounds=(bound_min, bound_max))
5381 @given(data_strategy())
5382 def test_bounds_unsatisfied(self, d):
5383 class SeqOf(self.base_klass):
5385 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5386 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5387 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5388 with self.assertRaises(BoundsError) as err:
5389 SeqOf(value=value, bounds=(bound_min, bound_max))
5391 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5392 SeqOf(bounds=(bound_min, bound_max)).decode(
5393 SeqOf(value).encode()
5396 value = [Boolean(True)] * d.draw(integers(
5397 min_value=bound_max + 1,
5398 max_value=bound_max + 10,
5400 with self.assertRaises(BoundsError) as err:
5401 SeqOf(value=value, bounds=(bound_min, bound_max))
5403 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5404 SeqOf(bounds=(bound_min, bound_max)).decode(
5405 SeqOf(value).encode()
5409 @given(integers(min_value=1, max_value=10))
5410 def test_out_of_bounds(self, bound_max):
5411 class SeqOf(self.base_klass):
5413 bounds = (0, bound_max)
5415 for _ in range(bound_max):
5416 seqof.append(Integer(123))
5417 with self.assertRaises(BoundsError):
5418 seqof.append(Integer(123))
5420 @given(data_strategy())
5421 def test_call(self, d):
5431 ) = d.draw(seqof_values_strategy())
5433 class SeqOf(self.base_klass):
5434 schema = schema_initial
5435 obj_initial = SeqOf(
5436 value=value_initial,
5437 bounds=bounds_initial,
5440 default=default_initial,
5441 optional=optional_initial or False,
5442 _decoded=_decoded_initial,
5453 ) = d.draw(seqof_values_strategy(
5454 schema=schema_initial,
5455 do_expl=impl_initial is None,
5457 if (default is None) and (obj_initial.default is not None):
5460 (bounds is None) and
5461 (value is not None) and
5462 (bounds_initial is not None) and
5463 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5467 (bounds is None) and
5468 (default is not None) and
5469 (bounds_initial is not None) and
5470 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5482 value_expected = default if value is None else value
5484 default_initial if value_expected is None
5487 value_expected = () if value_expected is None else value_expected
5488 self.assertEqual(obj, value_expected)
5489 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5490 self.assertEqual(obj.expl_tag, expl or expl_initial)
5493 default_initial if default is None else default,
5495 if obj.default is None:
5496 optional = optional_initial if optional is None else optional
5497 optional = False if optional is None else optional
5500 self.assertEqual(obj.optional, optional)
5502 (obj._bound_min, obj._bound_max),
5503 bounds or bounds_initial or (0, float("+inf")),
5506 @given(seqof_values_strategy())
5507 def test_copy(self, values):
5508 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5510 class SeqOf(self.base_klass):
5518 optional=optional or False,
5521 obj_copied = obj.copy()
5522 self.assert_copied_basic_fields(obj, obj_copied)
5523 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5524 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5525 self.assertEqual(obj._value, obj_copied._value)
5529 integers(min_value=1).map(tag_encode),
5531 def test_stripped(self, values, tag_impl):
5532 class SeqOf(self.base_klass):
5533 schema = OctetString()
5534 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5535 with self.assertRaises(NotEnoughData):
5536 obj.decode(obj.encode()[:-1])
5540 integers(min_value=1).map(tag_ctxc),
5542 def test_stripped_expl(self, values, tag_expl):
5543 class SeqOf(self.base_klass):
5544 schema = OctetString()
5545 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5546 with self.assertRaises(NotEnoughData):
5547 obj.decode(obj.encode()[:-1])
5550 integers(min_value=31),
5551 integers(min_value=0),
5554 def test_bad_tag(self, tag, offset, decode_path):
5555 with self.assertRaises(DecodeError) as err:
5556 self.base_klass().decode(
5557 tag_encode(tag)[:-1],
5559 decode_path=decode_path,
5562 self.assertEqual(err.exception.offset, offset)
5563 self.assertEqual(err.exception.decode_path, decode_path)
5566 integers(min_value=128),
5567 integers(min_value=0),
5570 def test_bad_len(self, l, offset, decode_path):
5571 with self.assertRaises(DecodeError) as err:
5572 self.base_klass().decode(
5573 self.base_klass.tag_default + len_encode(l)[:-1],
5575 decode_path=decode_path,
5578 self.assertEqual(err.exception.offset, offset)
5579 self.assertEqual(err.exception.decode_path, decode_path)
5581 @given(binary(min_size=1))
5582 def test_tag_mismatch(self, impl):
5583 assume(impl != self.base_klass.tag_default)
5584 with self.assertRaises(TagMismatch):
5585 self.base_klass(impl=impl).decode(self.base_klass().encode())
5587 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5589 seqof_values_strategy(schema=Integer()),
5590 lists(integers().map(Integer)),
5591 integers(min_value=1).map(tag_ctxc),
5592 integers(min_value=0),
5595 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5596 _, _, _, _, _, default, optional, _decoded = values
5598 class SeqOf(self.base_klass):
5608 pprint(obj, big_blobs=True, with_decode_path=True)
5609 self.assertFalse(obj.expled)
5610 obj_encoded = obj.encode()
5611 obj_expled = obj(value, expl=tag_expl)
5612 self.assertTrue(obj_expled.expled)
5614 list(obj_expled.pps())
5615 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5616 obj_expled_encoded = obj_expled.encode()
5617 ctx_copied = deepcopy(ctx_dummy)
5618 obj_decoded, tail = obj_expled.decode(
5619 obj_expled_encoded + tail_junk,
5623 self.assertDictEqual(ctx_copied, ctx_dummy)
5625 list(obj_decoded.pps())
5626 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5627 self.assertEqual(tail, tail_junk)
5628 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5629 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5630 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5631 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5633 obj_decoded.expl_llen,
5634 len(len_encode(len(obj_encoded))),
5636 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5637 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5640 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5642 self.assertEqual(obj_decoded.expl_offset, offset)
5643 for obj_inner in obj_decoded:
5644 self.assertIn(obj_inner, obj_decoded)
5645 self.assertSequenceEqual(
5648 obj_inner.offset - offset:
5649 obj_inner.offset + obj_inner.tlvlen - offset
5653 t, _, lv = tag_strip(obj_encoded)
5654 _, _, v = len_decode(lv)
5655 obj_encoded_lenindef = t + LENINDEF + v + EOC
5656 obj_decoded_lenindef, tail_lenindef = obj.decode(
5657 obj_encoded_lenindef + tail_junk,
5658 ctx={"bered": True},
5660 self.assertTrue(obj_decoded_lenindef.lenindef)
5661 self.assertTrue(obj_decoded_lenindef.bered)
5662 repr(obj_decoded_lenindef)
5663 list(obj_decoded_lenindef.pps())
5664 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5665 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5666 with self.assertRaises(DecodeError):
5667 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5668 with self.assertRaises(DecodeError):
5669 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5671 @given(data_strategy())
5672 def test_bered(self, d):
5673 class SeqOf(self.base_klass):
5675 encoded = Boolean(False).encode()
5676 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5677 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5678 with self.assertRaises(DecodeError):
5679 SeqOf().decode(encoded)
5680 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5681 self.assertFalse(decoded.ber_encoded)
5682 self.assertFalse(decoded.lenindef)
5683 self.assertTrue(decoded.bered)
5685 class SeqOf(self.base_klass):
5686 schema = OctetString()
5687 encoded = OctetString(b"whatever").encode()
5689 tag_encode(form=TagFormConstructed, num=4) +
5691 OctetString(b"whatever").encode() +
5694 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5695 with self.assertRaises(DecodeError):
5696 SeqOf().decode(encoded)
5697 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5698 self.assertFalse(decoded.ber_encoded)
5699 self.assertFalse(decoded.lenindef)
5700 self.assertTrue(decoded.bered)
5703 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5704 class SeqOf(SequenceOf):
5708 def _test_symmetric_compare_objs(self, obj1, obj2):
5709 self.assertEqual(obj1, obj2)
5710 self.assertSequenceEqual(list(obj1), list(obj2))
5713 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5718 def _test_symmetric_compare_objs(self, obj1, obj2):
5719 self.assertSetEqual(
5720 set(int(v) for v in obj1),
5721 set(int(v) for v in obj2),
5724 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5725 @given(data_strategy())
5726 def test_sorted(self, d):
5727 values = [OctetString(v) for v in d.draw(lists(binary()))]
5730 schema = OctetString()
5732 seq_encoded = seq.encode()
5733 seq_decoded, _ = seq.decode(seq_encoded)
5734 self.assertSequenceEqual(
5735 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5736 b"".join(sorted([v.encode() for v in values])),
5739 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5740 @given(data_strategy())
5741 def test_unsorted(self, d):
5742 values = [OctetString(v).encode() for v in d.draw(sets(
5743 binary(min_size=1, max_size=5),
5747 values = d.draw(permutations(values))
5748 assume(values != sorted(values))
5749 encoded = b"".join(values)
5750 seq_encoded = b"".join((
5752 len_encode(len(encoded)),
5757 schema = OctetString()
5759 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5760 seq.decode(seq_encoded)
5762 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5763 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5764 self.assertTrue(seq_decoded.ber_encoded)
5765 self.assertTrue(seq_decoded.bered)
5766 self.assertSequenceEqual(
5767 [obj.encode() for obj in seq_decoded],
5772 class TestGoMarshalVectors(TestCase):
5774 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5775 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5776 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5777 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5778 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5780 class Seq(Sequence):
5782 ("erste", Integer()),
5783 ("zweite", Integer(optional=True))
5786 seq["erste"] = Integer(64)
5787 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5788 seq["erste"] = Integer(0x123456)
5789 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5790 seq["erste"] = Integer(64)
5791 seq["zweite"] = Integer(65)
5792 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5794 class NestedSeq(Sequence):
5798 seq["erste"] = Integer(127)
5799 seq["zweite"] = None
5800 nested = NestedSeq()
5801 nested["nest"] = seq
5802 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5804 self.assertSequenceEqual(
5805 OctetString(b"\x01\x02\x03").encode(),
5806 hexdec("0403010203"),
5809 class Seq(Sequence):
5811 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5814 seq["erste"] = Integer(64)
5815 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5817 class Seq(Sequence):
5819 ("erste", Integer(expl=tag_ctxc(5))),
5822 seq["erste"] = Integer(64)
5823 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5825 class Seq(Sequence):
5828 impl=tag_encode(0, klass=TagClassContext),
5833 seq["erste"] = Null()
5834 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5836 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5838 self.assertSequenceEqual(
5839 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5840 hexdec("170d3730303130313030303030305a"),
5842 self.assertSequenceEqual(
5843 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5844 hexdec("170d3039313131353232353631365a"),
5846 self.assertSequenceEqual(
5847 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5848 hexdec("180f32313030303430353132303130315a"),
5851 class Seq(Sequence):
5853 ("erste", GeneralizedTime()),
5856 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5857 self.assertSequenceEqual(
5859 hexdec("3011180f32303039313131353232353631365a"),
5862 self.assertSequenceEqual(
5863 BitString((1, b"\x80")).encode(),
5866 self.assertSequenceEqual(
5867 BitString((12, b"\x81\xF0")).encode(),
5868 hexdec("03030481f0"),
5871 self.assertSequenceEqual(
5872 ObjectIdentifier("1.2.3.4").encode(),
5873 hexdec("06032a0304"),
5875 self.assertSequenceEqual(
5876 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5877 hexdec("06092a864888932d010105"),
5879 self.assertSequenceEqual(
5880 ObjectIdentifier("2.100.3").encode(),
5881 hexdec("0603813403"),
5884 self.assertSequenceEqual(
5885 PrintableString("test").encode(),
5886 hexdec("130474657374"),
5888 self.assertSequenceEqual(
5889 PrintableString("x" * 127).encode(),
5890 hexdec("137F" + "78" * 127),
5892 self.assertSequenceEqual(
5893 PrintableString("x" * 128).encode(),
5894 hexdec("138180" + "78" * 128),
5896 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5898 class Seq(Sequence):
5900 ("erste", IA5String()),
5903 seq["erste"] = IA5String("test")
5904 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5906 class Seq(Sequence):
5908 ("erste", PrintableString()),
5911 seq["erste"] = PrintableString("test")
5912 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5913 # Asterisk is actually not allowable
5914 PrintableString._allowable_chars |= set(b"*")
5915 seq["erste"] = PrintableString("test*")
5916 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5917 PrintableString._allowable_chars -= set(b"*")
5919 class Seq(Sequence):
5921 ("erste", Any(optional=True)),
5922 ("zweite", Integer()),
5925 seq["zweite"] = Integer(64)
5926 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5931 seq.append(Integer(10))
5932 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5934 class _SeqOf(SequenceOf):
5935 schema = PrintableString()
5937 class SeqOf(SequenceOf):
5940 _seqof.append(PrintableString("1"))
5942 seqof.append(_seqof)
5943 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5945 class Seq(Sequence):
5947 ("erste", Integer(default=1)),
5950 seq["erste"] = Integer(0)
5951 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5952 seq["erste"] = Integer(1)
5953 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5954 seq["erste"] = Integer(2)
5955 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5958 class TestPP(TestCase):
5959 @given(data_strategy())
5960 def test_oid_printing(self, d):
5962 str(ObjectIdentifier(k)): v * 2
5963 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5965 chosen = d.draw(sampled_from(sorted(oids)))
5966 chosen_id = oids[chosen]
5967 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5968 self.assertNotIn(chosen_id, pp_console_row(pp))
5969 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5972 class TestAutoAddSlots(TestCase):
5974 class Inher(Integer):
5977 with self.assertRaises(AttributeError):
5979 inher.unexistent = "whatever"
5982 class TestOIDDefines(TestCase):
5983 @given(data_strategy())
5984 def runTest(self, d):
5985 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5986 value_name_chosen = d.draw(sampled_from(value_names))
5988 ObjectIdentifier(oid)
5989 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5991 oid_chosen = d.draw(sampled_from(oids))
5992 values = d.draw(lists(
5994 min_size=len(value_names),
5995 max_size=len(value_names),
5998 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5999 oid: Integer() for oid in oids[:-1]
6002 for i, value_name in enumerate(value_names):
6003 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6005 class Seq(Sequence):
6008 for value_name, value in zip(value_names, values):
6009 seq[value_name] = Any(Integer(value).encode())
6010 seq["type"] = oid_chosen
6011 seq, _ = Seq().decode(seq.encode())
6012 for value_name in value_names:
6013 if value_name == value_name_chosen:
6015 self.assertIsNone(seq[value_name].defined)
6016 if value_name_chosen in oids[:-1]:
6017 self.assertIsNotNone(seq[value_name_chosen].defined)
6018 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6019 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6022 pprint(seq, big_blobs=True, with_decode_path=True)
6025 class TestDefinesByPath(TestCase):
6026 def test_generated(self):
6027 class Seq(Sequence):
6029 ("type", ObjectIdentifier()),
6030 ("value", OctetString(expl=tag_ctxc(123))),
6033 class SeqInner(Sequence):
6035 ("typeInner", ObjectIdentifier()),
6036 ("valueInner", Any()),
6039 class PairValue(SetOf):
6042 class Pair(Sequence):
6044 ("type", ObjectIdentifier()),
6045 ("value", PairValue()),
6048 class Pairs(SequenceOf):
6055 type_octet_stringed,
6057 ObjectIdentifier(oid)
6058 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6060 seq_integered = Seq()
6061 seq_integered["type"] = type_integered
6062 seq_integered["value"] = OctetString(Integer(123).encode())
6063 seq_integered_raw = seq_integered.encode()
6067 (type_octet_stringed, OctetString(b"whatever")),
6068 (type_integered, Integer(123)),
6069 (type_octet_stringed, OctetString(b"whenever")),
6070 (type_integered, Integer(234)),
6072 for t, v in pairs_input:
6075 pair["value"] = PairValue((Any(v),))
6077 seq_inner = SeqInner()
6078 seq_inner["typeInner"] = type_innered
6079 seq_inner["valueInner"] = Any(pairs)
6080 seq_sequenced = Seq()
6081 seq_sequenced["type"] = type_sequenced
6082 seq_sequenced["value"] = OctetString(seq_inner.encode())
6083 seq_sequenced_raw = seq_sequenced.encode()
6085 list(seq_sequenced.pps())
6086 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6088 defines_by_path = []
6089 ctx_copied = deepcopy(ctx_dummy)
6090 seq_integered, _ = Seq().decode(
6094 self.assertDictEqual(ctx_copied, ctx_dummy)
6095 self.assertIsNone(seq_integered["value"].defined)
6096 defines_by_path.append(
6097 (("type",), ((("value",), {
6098 type_integered: Integer(),
6099 type_sequenced: SeqInner(),
6102 ctx_copied["defines_by_path"] = defines_by_path
6103 seq_integered, _ = Seq().decode(
6107 del ctx_copied["defines_by_path"]
6108 self.assertDictEqual(ctx_copied, ctx_dummy)
6109 self.assertIsNotNone(seq_integered["value"].defined)
6110 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6111 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6112 self.assertTrue(seq_integered_raw[
6113 seq_integered["value"].defined[1].offset:
6114 ].startswith(Integer(123).encode()))
6116 list(seq_integered.pps())
6117 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6119 ctx_copied["defines_by_path"] = defines_by_path
6120 seq_sequenced, _ = Seq().decode(
6124 del ctx_copied["defines_by_path"]
6125 self.assertDictEqual(ctx_copied, ctx_dummy)
6126 self.assertIsNotNone(seq_sequenced["value"].defined)
6127 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6128 seq_inner = seq_sequenced["value"].defined[1]
6129 self.assertIsNone(seq_inner["valueInner"].defined)
6131 list(seq_sequenced.pps())
6132 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6134 defines_by_path.append((
6135 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6136 ((("valueInner",), {type_innered: Pairs()}),),
6138 ctx_copied["defines_by_path"] = defines_by_path
6139 seq_sequenced, _ = Seq().decode(
6143 del ctx_copied["defines_by_path"]
6144 self.assertDictEqual(ctx_copied, ctx_dummy)
6145 self.assertIsNotNone(seq_sequenced["value"].defined)
6146 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6147 seq_inner = seq_sequenced["value"].defined[1]
6148 self.assertIsNotNone(seq_inner["valueInner"].defined)
6149 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6150 pairs = seq_inner["valueInner"].defined[1]
6152 self.assertIsNone(pair["value"][0].defined)
6154 list(seq_sequenced.pps())
6155 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6157 defines_by_path.append((
6160 DecodePathDefBy(type_sequenced),
6162 DecodePathDefBy(type_innered),
6167 type_integered: Integer(),
6168 type_octet_stringed: OctetString(),
6171 ctx_copied["defines_by_path"] = defines_by_path
6172 seq_sequenced, _ = Seq().decode(
6176 del ctx_copied["defines_by_path"]
6177 self.assertDictEqual(ctx_copied, ctx_dummy)
6178 self.assertIsNotNone(seq_sequenced["value"].defined)
6179 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6180 seq_inner = seq_sequenced["value"].defined[1]
6181 self.assertIsNotNone(seq_inner["valueInner"].defined)
6182 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6183 pairs_got = seq_inner["valueInner"].defined[1]
6184 for pair_input, pair_got in zip(pairs_input, pairs_got):
6185 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6186 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6188 list(seq_sequenced.pps())
6189 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6191 @given(oid_strategy(), integers())
6192 def test_simple(self, oid, tgt):
6193 class Inner(Sequence):
6195 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6196 ObjectIdentifier(oid): Integer(),
6200 class Outer(Sequence):
6203 ("tgt", OctetString()),
6207 inner["oid"] = ObjectIdentifier(oid)
6209 outer["inner"] = inner
6210 outer["tgt"] = OctetString(Integer(tgt).encode())
6211 decoded, _ = Outer().decode(outer.encode())
6212 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6215 class TestAbsDecodePath(TestCase):
6217 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6218 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6220 def test_concat(self, decode_path, rel_path):
6221 self.assertSequenceEqual(
6222 abs_decode_path(decode_path, rel_path),
6223 decode_path + rel_path,
6227 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6228 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6230 def test_abs(self, decode_path, rel_path):
6231 self.assertSequenceEqual(
6232 abs_decode_path(decode_path, ("/",) + rel_path),
6237 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6238 integers(min_value=1, max_value=3),
6239 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6241 def test_dots(self, decode_path, number_of_dots, rel_path):
6242 self.assertSequenceEqual(
6243 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6244 decode_path[:-number_of_dots] + rel_path,
6248 class TestStrictDefaultExistence(TestCase):
6249 @given(data_strategy())
6250 def runTest(self, d):
6251 count = d.draw(integers(min_value=1, max_value=10))
6252 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6254 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6255 for i in range(count)
6257 for klass in (Sequence, Set):
6261 for i in range(count):
6262 seq["int%d" % i] = Integer(123)
6264 chosen_choice = "int%d" % chosen
6265 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6266 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6268 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6269 self.assertTrue(decoded.ber_encoded)
6270 self.assertTrue(decoded.bered)
6271 decoded, _ = seq.decode(raw, ctx={"bered": True})
6272 self.assertTrue(decoded.ber_encoded)
6273 self.assertTrue(decoded.bered)
6276 class TestX690PrefixedType(TestCase):
6278 self.assertSequenceEqual(
6279 VisibleString("Jones").encode(),
6280 hexdec("1A054A6F6E6573"),
6282 self.assertSequenceEqual(
6285 impl=tag_encode(3, klass=TagClassApplication),
6287 hexdec("43054A6F6E6573"),
6289 self.assertSequenceEqual(
6293 impl=tag_encode(3, klass=TagClassApplication),
6297 hexdec("A20743054A6F6E6573"),
6299 self.assertSequenceEqual(
6303 impl=tag_encode(3, klass=TagClassApplication),
6305 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6307 hexdec("670743054A6F6E6573"),
6309 self.assertSequenceEqual(
6310 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6311 hexdec("82054A6F6E6573"),
6315 class TestExplOOB(TestCase):
6317 expl = tag_ctxc(123)
6318 raw = Integer(123).encode() + Integer(234).encode()
6319 raw = b"".join((expl, len_encode(len(raw)), raw))
6320 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6321 Integer(expl=expl).decode(raw)
6322 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})