2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2019 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from copy import deepcopy
20 from datetime import datetime
21 from string import ascii_letters
22 from string import digits
23 from string import printable
24 from string import whitespace
25 from unittest import TestCase
27 from hypothesis import assume
28 from hypothesis import given
29 from hypothesis import settings
30 from hypothesis.strategies import binary
31 from hypothesis.strategies import booleans
32 from hypothesis.strategies import composite
33 from hypothesis.strategies import data as data_strategy
34 from hypothesis.strategies import datetimes
35 from hypothesis.strategies import dictionaries
36 from hypothesis.strategies import integers
37 from hypothesis.strategies import just
38 from hypothesis.strategies import lists
39 from hypothesis.strategies import none
40 from hypothesis.strategies import one_of
41 from hypothesis.strategies import permutations
42 from hypothesis.strategies import sampled_from
43 from hypothesis.strategies import sets
44 from hypothesis.strategies import text
45 from hypothesis.strategies import tuples
46 from six import assertRaisesRegex
47 from six import binary_type
48 from six import byte2int
49 from six import indexbytes
50 from six import int2byte
51 from six import iterbytes
53 from six import text_type
54 from six import unichr as six_unichr
56 from pyderasn import _pp
57 from pyderasn import abs_decode_path
58 from pyderasn import Any
59 from pyderasn import BitString
60 from pyderasn import BMPString
61 from pyderasn import Boolean
62 from pyderasn import BoundsError
63 from pyderasn import Choice
64 from pyderasn import DecodeError
65 from pyderasn import DecodePathDefBy
66 from pyderasn import Enumerated
67 from pyderasn import EOC
68 from pyderasn import EOC_LEN
69 from pyderasn import GeneralizedTime
70 from pyderasn import GeneralString
71 from pyderasn import GraphicString
72 from pyderasn import hexdec
73 from pyderasn import hexenc
74 from pyderasn import IA5String
75 from pyderasn import Integer
76 from pyderasn import InvalidLength
77 from pyderasn import InvalidOID
78 from pyderasn import InvalidValueType
79 from pyderasn import len_decode
80 from pyderasn import len_encode
81 from pyderasn import LEN_YYMMDDHHMMSSZ
82 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
83 from pyderasn import LEN_YYYYMMDDHHMMSSZ
84 from pyderasn import LENINDEF
85 from pyderasn import LenIndefForm
86 from pyderasn import NotEnoughData
87 from pyderasn import Null
88 from pyderasn import NumericString
89 from pyderasn import ObjectIdentifier
90 from pyderasn import ObjNotReady
91 from pyderasn import ObjUnknown
92 from pyderasn import OctetString
93 from pyderasn import pp_console_row
94 from pyderasn import pprint
95 from pyderasn import PrintableString
96 from pyderasn import Sequence
97 from pyderasn import SequenceOf
98 from pyderasn import Set
99 from pyderasn import SetOf
100 from pyderasn import tag_ctxc
101 from pyderasn import tag_ctxp
102 from pyderasn import tag_decode
103 from pyderasn import tag_encode
104 from pyderasn import tag_strip
105 from pyderasn import TagClassApplication
106 from pyderasn import TagClassContext
107 from pyderasn import TagClassPrivate
108 from pyderasn import TagClassUniversal
109 from pyderasn import TagFormConstructed
110 from pyderasn import TagFormPrimitive
111 from pyderasn import TagMismatch
112 from pyderasn import TeletexString
113 from pyderasn import UniversalString
114 from pyderasn import UTCTime
115 from pyderasn import UTF8String
116 from pyderasn import VideotexString
117 from pyderasn import VisibleString
120 settings.register_profile("local", settings(
123 settings.load_profile("local")
124 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
126 tag_classes = sampled_from((
132 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
133 decode_path_strat = lists(integers(), max_size=3).map(
134 lambda decode_path: tuple(str(dp) for dp in decode_path)
136 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
139 class TestHex(TestCase):
141 def test_symmetric(self, data):
142 self.assertEqual(hexdec(hexenc(data)), data)
145 class TestTagCoder(TestCase):
146 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
150 integers(min_value=0, max_value=30),
153 def test_short(self, klass, form, num, junk):
154 raw = tag_encode(klass=klass, form=form, num=num)
155 self.assertEqual(tag_decode(raw), (klass, form, num))
156 self.assertEqual(len(raw), 1)
158 byte2int(tag_encode(klass=klass, form=form, num=0)),
159 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
161 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
162 self.assertSequenceEqual(stripped.tobytes(), raw)
163 self.assertEqual(tlen, len(raw))
164 self.assertSequenceEqual(tail, junk)
166 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
170 integers(min_value=31),
173 def test_long(self, klass, form, num, junk):
174 raw = tag_encode(klass=klass, form=form, num=num)
175 self.assertEqual(tag_decode(raw), (klass, form, num))
176 self.assertGreater(len(raw), 1)
178 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
181 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
182 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
183 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
184 self.assertSequenceEqual(stripped.tobytes(), raw)
185 self.assertEqual(tlen, len(raw))
186 self.assertSequenceEqual(tail, junk)
188 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
189 @given(integers(min_value=31))
190 def test_unfinished_tag(self, num):
191 raw = bytearray(tag_encode(num=num))
192 for i in range(1, len(raw)):
194 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
195 tag_strip(bytes(raw))
197 def test_go_vectors_valid(self):
198 for data, (eklass, etag, elen, eform) in (
199 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
200 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
201 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
202 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
203 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
204 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
205 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
206 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
207 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
208 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
210 tag, _, len_encoded = tag_strip(memoryview(data))
211 klass, form, num = tag_decode(tag)
212 _len, _, tail = len_decode(len_encoded)
213 self.assertSequenceEqual(tail, b"")
214 self.assertEqual(klass, eklass)
215 self.assertEqual(num, etag)
216 self.assertEqual(_len, elen)
217 self.assertEqual(form, eform)
219 def test_go_vectors_invalid(self):
227 with self.assertRaises(DecodeError):
228 _, _, len_encoded = tag_strip(memoryview(data))
229 len_decode(len_encoded)
232 integers(min_value=0, max_value=127),
233 integers(min_value=0, max_value=2),
235 def test_long_instead_of_short(self, l, dummy_num):
236 octets = (b"\x00" * dummy_num) + int2byte(l)
237 octets = int2byte((dummy_num + 1) | 0x80) + octets
238 with self.assertRaises(DecodeError):
242 class TestLenCoder(TestCase):
243 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
245 integers(min_value=0, max_value=127),
248 def test_short(self, l, junk):
249 raw = len_encode(l) + junk
250 decoded, llen, tail = len_decode(memoryview(raw))
251 self.assertEqual(decoded, l)
252 self.assertEqual(llen, 1)
253 self.assertEqual(len(raw), 1 + len(junk))
254 self.assertEqual(tail.tobytes(), junk)
256 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
258 integers(min_value=128),
261 def test_long(self, l, junk):
262 raw = len_encode(l) + junk
263 decoded, llen, tail = len_decode(memoryview(raw))
264 self.assertEqual(decoded, l)
265 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
266 self.assertEqual(llen, len(raw) - len(junk))
267 self.assertNotEqual(indexbytes(raw, 1), 0)
268 self.assertSequenceEqual(tail.tobytes(), junk)
270 def test_empty(self):
271 with self.assertRaises(NotEnoughData):
274 @given(integers(min_value=128))
275 def test_stripped(self, _len):
276 with self.assertRaises(NotEnoughData):
277 len_decode(len_encode(_len)[:-1])
280 text_printable = text(alphabet=printable, min_size=1)
284 def text_letters(draw):
285 result = draw(text(alphabet=ascii_letters, min_size=1))
287 result = result.encode("ascii")
291 class CommonMixin(object):
292 def test_tag_default(self):
293 obj = self.base_klass()
294 self.assertEqual(obj.tag, obj.tag_default)
296 def test_simultaneous_impl_expl(self):
297 with self.assertRaises(ValueError):
298 self.base_klass(impl=b"whatever", expl=b"whenever")
300 @given(binary(min_size=1), integers(), integers(), integers())
301 def test_decoded(self, impl, offset, llen, vlen):
302 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
303 self.assertEqual(obj.offset, offset)
304 self.assertEqual(obj.llen, llen)
305 self.assertEqual(obj.vlen, vlen)
306 self.assertEqual(obj.tlen, len(impl))
307 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
309 @given(binary(min_size=1))
310 def test_impl_inherited(self, impl_tag):
311 class Inherited(self.base_klass):
314 self.assertSequenceEqual(obj.impl, impl_tag)
315 self.assertFalse(obj.expled)
318 def test_expl_inherited(self, expl_tag):
319 class Inherited(self.base_klass):
322 self.assertSequenceEqual(obj.expl, expl_tag)
323 self.assertTrue(obj.expled)
325 def assert_copied_basic_fields(self, obj, obj_copied):
326 self.assertEqual(obj, obj_copied)
327 self.assertSequenceEqual(obj.tag, obj_copied.tag)
328 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
329 self.assertEqual(obj.default, obj_copied.default)
330 self.assertEqual(obj.optional, obj_copied.optional)
331 self.assertEqual(obj.offset, obj_copied.offset)
332 self.assertEqual(obj.llen, obj_copied.llen)
333 self.assertEqual(obj.vlen, obj_copied.vlen)
337 def boolean_values_strategy(draw, do_expl=False):
338 value = draw(one_of(none(), booleans()))
342 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
344 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
345 default = draw(one_of(none(), booleans()))
346 optional = draw(one_of(none(), booleans()))
348 draw(integers(min_value=0)),
349 draw(integers(min_value=0)),
350 draw(integers(min_value=0)),
352 return (value, impl, expl, default, optional, _decoded)
355 class BooleanInherited(Boolean):
359 class TestBoolean(CommonMixin, TestCase):
362 def test_invalid_value_type(self):
363 with self.assertRaises(InvalidValueType) as err:
368 def test_optional(self, optional):
369 obj = Boolean(default=Boolean(False), optional=optional)
370 self.assertTrue(obj.optional)
373 def test_ready(self, value):
375 self.assertFalse(obj.ready)
378 pprint(obj, big_blobs=True, with_decode_path=True)
379 with self.assertRaises(ObjNotReady) as err:
383 self.assertTrue(obj.ready)
386 pprint(obj, big_blobs=True, with_decode_path=True)
388 @given(booleans(), booleans(), binary(), binary())
389 def test_comparison(self, value1, value2, tag1, tag2):
390 for klass in (Boolean, BooleanInherited):
393 self.assertEqual(obj1 == obj2, value1 == value2)
394 self.assertEqual(obj1 != obj2, value1 != value2)
395 self.assertEqual(obj1 == bool(obj2), value1 == value2)
396 obj1 = klass(value1, impl=tag1)
397 obj2 = klass(value1, impl=tag2)
398 self.assertEqual(obj1 == obj2, tag1 == tag2)
399 self.assertEqual(obj1 != obj2, tag1 != tag2)
401 @given(data_strategy())
402 def test_call(self, d):
403 for klass in (Boolean, BooleanInherited):
411 ) = d.draw(boolean_values_strategy())
417 optional_initial or False,
427 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
428 obj = obj_initial(value, impl, expl, default, optional)
430 value_expected = default if value is None else value
432 default_initial if value_expected is None
435 self.assertEqual(obj, value_expected)
436 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
437 self.assertEqual(obj.expl_tag, expl or expl_initial)
440 default_initial if default is None else default,
442 if obj.default is None:
443 optional = optional_initial if optional is None else optional
444 optional = False if optional is None else optional
447 self.assertEqual(obj.optional, optional)
449 @given(boolean_values_strategy())
450 def test_copy(self, values):
451 for klass in (Boolean, BooleanInherited):
453 obj_copied = obj.copy()
454 self.assert_copied_basic_fields(obj, obj_copied)
458 integers(min_value=1).map(tag_encode),
460 def test_stripped(self, value, tag_impl):
461 obj = Boolean(value, impl=tag_impl)
462 with self.assertRaises(NotEnoughData):
463 obj.decode(obj.encode()[:-1])
467 integers(min_value=1).map(tag_ctxc),
469 def test_stripped_expl(self, value, tag_expl):
470 obj = Boolean(value, expl=tag_expl)
471 with self.assertRaises(NotEnoughData):
472 obj.decode(obj.encode()[:-1])
475 integers(min_value=31),
476 integers(min_value=0),
479 def test_bad_tag(self, tag, offset, decode_path):
480 with self.assertRaises(DecodeError) as err:
482 tag_encode(tag)[:-1],
484 decode_path=decode_path,
487 self.assertEqual(err.exception.offset, offset)
488 self.assertEqual(err.exception.decode_path, decode_path)
491 integers(min_value=31),
492 integers(min_value=0),
495 def test_bad_expl_tag(self, tag, offset, decode_path):
496 with self.assertRaises(DecodeError) as err:
497 Boolean(expl=Boolean.tag_default).decode(
498 tag_encode(tag)[:-1],
500 decode_path=decode_path,
503 self.assertEqual(err.exception.offset, offset)
504 self.assertEqual(err.exception.decode_path, decode_path)
507 integers(min_value=128),
508 integers(min_value=0),
511 def test_bad_len(self, l, offset, decode_path):
512 with self.assertRaises(DecodeError) as err:
514 Boolean.tag_default + len_encode(l)[:-1],
516 decode_path=decode_path,
519 self.assertEqual(err.exception.offset, offset)
520 self.assertEqual(err.exception.decode_path, decode_path)
523 integers(min_value=128),
524 integers(min_value=0),
527 def test_bad_expl_len(self, l, offset, decode_path):
528 with self.assertRaises(DecodeError) as err:
529 Boolean(expl=Boolean.tag_default).decode(
530 Boolean.tag_default + len_encode(l)[:-1],
532 decode_path=decode_path,
535 self.assertEqual(err.exception.offset, offset)
536 self.assertEqual(err.exception.decode_path, decode_path)
538 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
540 boolean_values_strategy(),
542 integers(min_value=1).map(tag_ctxc),
543 integers(min_value=0),
546 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
547 for klass in (Boolean, BooleanInherited):
548 _, _, _, default, optional, _decoded = values
557 pprint(obj, big_blobs=True, with_decode_path=True)
558 self.assertFalse(obj.expled)
559 obj_encoded = obj.encode()
560 obj_expled = obj(value, expl=tag_expl)
561 self.assertTrue(obj_expled.expled)
563 list(obj_expled.pps())
564 pprint(obj_expled, big_blobs=True, with_decode_path=True)
565 obj_expled_encoded = obj_expled.encode()
566 ctx_copied = deepcopy(ctx_dummy)
567 obj_decoded, tail = obj_expled.decode(
568 obj_expled_encoded + tail_junk,
572 self.assertDictEqual(ctx_copied, ctx_dummy)
574 list(obj_decoded.pps())
575 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
576 self.assertEqual(tail, tail_junk)
577 self.assertEqual(obj_decoded, obj_expled)
578 self.assertNotEqual(obj_decoded, obj)
579 self.assertEqual(bool(obj_decoded), bool(obj_expled))
580 self.assertEqual(bool(obj_decoded), bool(obj))
581 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
582 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
583 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
585 obj_decoded.expl_llen,
586 len(len_encode(len(obj_encoded))),
588 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
589 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
592 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
594 self.assertEqual(obj_decoded.expl_offset, offset)
596 @given(integers(min_value=2))
597 def test_invalid_len(self, l):
598 with self.assertRaises(InvalidLength):
599 Boolean().decode(b"".join((
605 @given(integers(min_value=0 + 1, max_value=255 - 1))
606 def test_ber_value(self, value):
607 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
608 Boolean().decode(b"".join((
613 obj, _ = Boolean().decode(
621 self.assertTrue(bool(obj))
622 self.assertTrue(obj.ber_encoded)
623 self.assertFalse(obj.lenindef)
624 self.assertTrue(obj.bered)
626 self.assertTrue(obj.ber_encoded)
627 self.assertFalse(obj.lenindef)
628 self.assertTrue(obj.bered)
631 integers(min_value=1).map(tag_ctxc),
632 binary().filter(lambda x: not x.startswith(EOC)),
634 def test_ber_expl_no_eoc(self, expl, junk):
635 encoded = expl + LENINDEF + Boolean(False).encode()
636 with self.assertRaises(LenIndefForm):
637 Boolean(expl=expl).decode(encoded + junk)
638 with assertRaisesRegex(self, DecodeError, "no EOC"):
639 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
640 obj, tail = Boolean(expl=expl).decode(
641 encoded + EOC + junk,
644 self.assertTrue(obj.expl_lenindef)
645 self.assertFalse(obj.lenindef)
646 self.assertFalse(obj.ber_encoded)
647 self.assertTrue(obj.bered)
649 self.assertTrue(obj.expl_lenindef)
650 self.assertFalse(obj.lenindef)
651 self.assertFalse(obj.ber_encoded)
652 self.assertTrue(obj.bered)
653 self.assertSequenceEqual(tail, junk)
656 pprint(obj, big_blobs=True, with_decode_path=True)
659 integers(min_value=1).map(tag_ctxc),
666 def test_ber_expl(self, expl, values):
672 Boolean(value).encode() +
675 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
677 class SeqOf(SequenceOf):
678 schema = Boolean(expl=expl)
679 with self.assertRaises(LenIndefForm):
680 SeqOf().decode(encoded)
681 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
682 self.assertSequenceEqual(tail, b"")
683 self.assertSequenceEqual([bool(v) for v in seqof], values)
699 len(expl) + 1 + 3 + EOC_LEN,
710 pprint(seqof, big_blobs=True, with_decode_path=True)
714 def integer_values_strategy(draw, do_expl=False):
715 bound_min, value, default, bound_max = sorted(draw(sets(
724 _specs = draw(sets(text_letters()))
727 min_size=len(_specs),
728 max_size=len(_specs),
730 _specs = list(zip(_specs, values))
733 bounds = (bound_min, bound_max)
737 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
739 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
742 optional = draw(one_of(none(), booleans()))
744 draw(integers(min_value=0)),
745 draw(integers(min_value=0)),
746 draw(integers(min_value=0)),
748 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
751 class IntegerInherited(Integer):
755 class TestInteger(CommonMixin, TestCase):
758 def test_invalid_value_type(self):
759 with self.assertRaises(InvalidValueType) as err:
763 @given(sets(text_letters(), min_size=2))
764 def test_unknown_name(self, names_input):
765 missing = names_input.pop()
768 schema = [(n, 123) for n in names_input]
769 with self.assertRaises(ObjUnknown) as err:
773 @given(sets(text_letters(), min_size=2))
774 def test_known_name(self, names_input):
776 schema = [(n, 123) for n in names_input]
777 Int(names_input.pop())
780 def test_optional(self, optional):
781 obj = Integer(default=Integer(0), optional=optional)
782 self.assertTrue(obj.optional)
785 def test_ready(self, value):
787 self.assertFalse(obj.ready)
790 pprint(obj, big_blobs=True, with_decode_path=True)
791 with self.assertRaises(ObjNotReady) as err:
795 self.assertTrue(obj.ready)
798 pprint(obj, big_blobs=True, with_decode_path=True)
801 @given(integers(), integers(), binary(), binary())
802 def test_comparison(self, value1, value2, tag1, tag2):
803 for klass in (Integer, IntegerInherited):
806 self.assertEqual(obj1 == obj2, value1 == value2)
807 self.assertEqual(obj1 != obj2, value1 != value2)
808 self.assertEqual(obj1 == int(obj2), value1 == value2)
809 obj1 = klass(value1, impl=tag1)
810 obj2 = klass(value1, impl=tag2)
811 self.assertEqual(obj1 == obj2, tag1 == tag2)
812 self.assertEqual(obj1 != obj2, tag1 != tag2)
814 @given(lists(integers()))
815 def test_sorted_works(self, values):
816 self.assertSequenceEqual(
817 [int(v) for v in sorted(Integer(v) for v in values)],
821 @given(data_strategy())
822 def test_named(self, d):
823 names_input = list(d.draw(sets(text_letters(), min_size=1)))
824 values_input = list(d.draw(sets(
826 min_size=len(names_input),
827 max_size=len(names_input),
829 chosen_name = d.draw(sampled_from(names_input))
830 names_input = dict(zip(names_input, values_input))
834 _int = Int(chosen_name)
835 self.assertEqual(_int.named, chosen_name)
836 self.assertEqual(int(_int), names_input[chosen_name])
838 @given(integers(), integers(min_value=0), integers(min_value=0))
839 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
840 value = bound_min + value_delta
841 bound_max = value + bound_delta
842 Integer(value=value, bounds=(bound_min, bound_max))
844 @given(sets(integers(), min_size=3, max_size=3))
845 def test_bounds_unsatisfied(self, values):
846 values = sorted(values)
847 with self.assertRaises(BoundsError) as err:
848 Integer(value=values[0], bounds=(values[1], values[2]))
850 with assertRaisesRegex(self, DecodeError, "bounds") as err:
851 Integer(bounds=(values[1], values[2])).decode(
852 Integer(values[0]).encode()
855 with self.assertRaises(BoundsError) as err:
856 Integer(value=values[2], bounds=(values[0], values[1]))
858 with assertRaisesRegex(self, DecodeError, "bounds") as err:
859 Integer(bounds=(values[0], values[1])).decode(
860 Integer(values[2]).encode()
864 @given(data_strategy())
865 def test_call(self, d):
866 for klass in (Integer, IntegerInherited):
876 ) = d.draw(integer_values_strategy())
883 optional_initial or False,
896 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
897 if (default is None) and (obj_initial.default is not None):
901 (value is not None) and
902 (bounds_initial is not None) and
903 not (bounds_initial[0] <= value <= bounds_initial[1])
908 (default is not None) and
909 (bounds_initial is not None) and
910 not (bounds_initial[0] <= default <= bounds_initial[1])
913 obj = obj_initial(value, bounds, impl, expl, default, optional)
915 value_expected = default if value is None else value
917 default_initial if value_expected is None
920 self.assertEqual(obj, value_expected)
921 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
922 self.assertEqual(obj.expl_tag, expl or expl_initial)
925 default_initial if default is None else default,
927 if obj.default is None:
928 optional = optional_initial if optional is None else optional
929 optional = False if optional is None else optional
932 self.assertEqual(obj.optional, optional)
934 (obj._bound_min, obj._bound_max),
935 bounds or bounds_initial or (float("-inf"), float("+inf")),
939 {} if _specs_initial is None else dict(_specs_initial),
942 @given(integer_values_strategy())
943 def test_copy(self, values):
944 for klass in (Integer, IntegerInherited):
946 obj_copied = obj.copy()
947 self.assert_copied_basic_fields(obj, obj_copied)
948 self.assertEqual(obj.specs, obj_copied.specs)
949 self.assertEqual(obj._bound_min, obj_copied._bound_min)
950 self.assertEqual(obj._bound_max, obj_copied._bound_max)
951 self.assertEqual(obj._value, obj_copied._value)
955 integers(min_value=1).map(tag_encode),
957 def test_stripped(self, value, tag_impl):
958 obj = Integer(value, impl=tag_impl)
959 with self.assertRaises(NotEnoughData):
960 obj.decode(obj.encode()[:-1])
964 integers(min_value=1).map(tag_ctxc),
966 def test_stripped_expl(self, value, tag_expl):
967 obj = Integer(value, expl=tag_expl)
968 with self.assertRaises(NotEnoughData):
969 obj.decode(obj.encode()[:-1])
971 def test_zero_len(self):
972 with self.assertRaises(NotEnoughData):
973 Integer().decode(b"".join((
979 integers(min_value=31),
980 integers(min_value=0),
983 def test_bad_tag(self, tag, offset, decode_path):
984 with self.assertRaises(DecodeError) as err:
986 tag_encode(tag)[:-1],
988 decode_path=decode_path,
991 self.assertEqual(err.exception.offset, offset)
992 self.assertEqual(err.exception.decode_path, decode_path)
995 integers(min_value=128),
996 integers(min_value=0),
999 def test_bad_len(self, l, offset, decode_path):
1000 with self.assertRaises(DecodeError) as err:
1002 Integer.tag_default + len_encode(l)[:-1],
1004 decode_path=decode_path,
1007 self.assertEqual(err.exception.offset, offset)
1008 self.assertEqual(err.exception.decode_path, decode_path)
1011 sets(integers(), min_size=2, max_size=2),
1012 integers(min_value=0),
1015 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1016 value, bound_min = list(sorted(ints))
1019 bounds = (bound_min, bound_min)
1020 with self.assertRaises(DecodeError) as err:
1022 Integer(value).encode(),
1024 decode_path=decode_path,
1027 self.assertEqual(err.exception.offset, offset)
1028 self.assertEqual(err.exception.decode_path, decode_path)
1030 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1032 integer_values_strategy(),
1034 integers(min_value=1).map(tag_ctxc),
1035 integers(min_value=0),
1038 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1039 for klass in (Integer, IntegerInherited):
1040 _, _, _, _, default, optional, _, _decoded = values
1049 pprint(obj, big_blobs=True, with_decode_path=True)
1050 self.assertFalse(obj.expled)
1051 obj_encoded = obj.encode()
1052 obj_expled = obj(value, expl=tag_expl)
1053 self.assertTrue(obj_expled.expled)
1055 list(obj_expled.pps())
1056 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1057 obj_expled_encoded = obj_expled.encode()
1058 ctx_copied = deepcopy(ctx_dummy)
1059 obj_decoded, tail = obj_expled.decode(
1060 obj_expled_encoded + tail_junk,
1064 self.assertDictEqual(ctx_copied, ctx_dummy)
1066 list(obj_decoded.pps())
1067 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1068 self.assertEqual(tail, tail_junk)
1069 self.assertEqual(obj_decoded, obj_expled)
1070 self.assertNotEqual(obj_decoded, obj)
1071 self.assertEqual(int(obj_decoded), int(obj_expled))
1072 self.assertEqual(int(obj_decoded), int(obj))
1073 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1074 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1075 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1077 obj_decoded.expl_llen,
1078 len(len_encode(len(obj_encoded))),
1080 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1081 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1084 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1086 self.assertEqual(obj_decoded.expl_offset, offset)
1088 def test_go_vectors_valid(self):
1089 for data, expect in ((
1093 (b"\xff\x7f", -129),
1097 (b"\xff\x00", -256),
1101 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1102 (b"\x80\x00\x00\x00", -2147483648),
1105 Integer().decode(b"".join((
1106 Integer.tag_default,
1107 len_encode(len(data)),
1113 def test_go_vectors_invalid(self):
1118 with self.assertRaises(DecodeError):
1119 Integer().decode(b"".join((
1120 Integer.tag_default,
1121 len_encode(len(data)),
1127 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1130 if draw(booleans()):
1131 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1133 integers(min_value=0, max_value=255),
1134 min_size=len(schema),
1135 max_size=len(schema),
1137 schema = list(zip(schema, bits))
1139 def _value(value_required):
1140 if not value_required and draw(booleans()):
1142 generation_choice = 0
1144 generation_choice = draw(sampled_from((1, 2, 3)))
1145 if generation_choice == 1 or draw(booleans()):
1146 return "'%s'B" % "".join(draw(lists(
1147 sampled_from(("0", "1")),
1148 max_size=len(schema),
1150 elif generation_choice == 2 or draw(booleans()):
1151 return draw(binary(max_size=len(schema) // 8))
1152 elif generation_choice == 3 or draw(booleans()):
1153 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1155 value = _value(value_required)
1156 default = _value(value_required=False)
1160 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1162 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1163 optional = draw(one_of(none(), booleans()))
1165 draw(integers(min_value=0)),
1166 draw(integers(min_value=0)),
1167 draw(integers(min_value=0)),
1169 return (schema, value, impl, expl, default, optional, _decoded)
1172 class BitStringInherited(BitString):
1176 class TestBitString(CommonMixin, TestCase):
1177 base_klass = BitString
1179 @given(lists(booleans()))
1180 def test_b_encoding(self, bits):
1181 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1182 self.assertEqual(obj.bit_len, len(bits))
1183 self.assertSequenceEqual(list(obj), bits)
1184 for i, bit in enumerate(bits):
1185 self.assertEqual(obj[i], bit)
1187 @given(lists(booleans()))
1188 def test_out_of_bounds_bits(self, bits):
1189 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1190 for i in range(len(bits), len(bits) * 2):
1191 self.assertFalse(obj[i])
1193 def test_bad_b_encoding(self):
1194 with self.assertRaises(ValueError):
1195 BitString("'010120101'B")
1198 integers(min_value=1, max_value=255),
1199 integers(min_value=1, max_value=255),
1201 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1202 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1203 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1204 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1206 class BS(BitString):
1207 schema = (("whatever", 0),)
1208 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1209 self.assertEqual(obj.bit_len, leading_zeros + 1)
1210 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1212 def test_zero_len(self):
1213 with self.assertRaises(NotEnoughData):
1214 BitString().decode(b"".join((
1215 BitString.tag_default,
1219 def test_invalid_value_type(self):
1220 with self.assertRaises(InvalidValueType) as err:
1223 with self.assertRaises(InvalidValueType) as err:
1227 def test_obj_unknown(self):
1228 with self.assertRaises(ObjUnknown) as err:
1229 BitString(b"whatever")["whenever"]
1232 def test_get_invalid_type(self):
1233 with self.assertRaises(InvalidValueType) as err:
1234 BitString(b"whatever")[(1, 2, 3)]
1237 @given(data_strategy())
1238 def test_unknown_name(self, d):
1239 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1240 missing = _schema.pop()
1242 class BS(BitString):
1243 schema = [(n, i) for i, n in enumerate(_schema)]
1244 with self.assertRaises(ObjUnknown) as err:
1249 def test_optional(self, optional):
1250 obj = BitString(default=BitString(b""), optional=optional)
1251 self.assertTrue(obj.optional)
1254 def test_ready(self, value):
1256 self.assertFalse(obj.ready)
1259 pprint(obj, big_blobs=True, with_decode_path=True)
1260 with self.assertRaises(ObjNotReady) as err:
1263 obj = BitString(value)
1264 self.assertTrue(obj.ready)
1267 pprint(obj, big_blobs=True, with_decode_path=True)
1270 tuples(integers(min_value=0), binary()),
1271 tuples(integers(min_value=0), binary()),
1275 def test_comparison(self, value1, value2, tag1, tag2):
1276 for klass in (BitString, BitStringInherited):
1277 obj1 = klass(value1)
1278 obj2 = klass(value2)
1279 self.assertEqual(obj1 == obj2, value1 == value2)
1280 self.assertEqual(obj1 != obj2, value1 != value2)
1281 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1282 obj1 = klass(value1, impl=tag1)
1283 obj2 = klass(value1, impl=tag2)
1284 self.assertEqual(obj1 == obj2, tag1 == tag2)
1285 self.assertEqual(obj1 != obj2, tag1 != tag2)
1287 @given(data_strategy())
1288 def test_call(self, d):
1289 for klass in (BitString, BitStringInherited):
1298 ) = d.draw(bit_string_values_strategy())
1301 schema = schema_initial
1303 value=value_initial,
1306 default=default_initial,
1307 optional=optional_initial or False,
1308 _decoded=_decoded_initial,
1318 ) = d.draw(bit_string_values_strategy(
1319 schema=schema_initial,
1320 do_expl=impl_initial is None,
1329 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1330 self.assertEqual(obj.expl_tag, expl or expl_initial)
1331 if obj.default is None:
1332 optional = optional_initial if optional is None else optional
1333 optional = False if optional is None else optional
1336 self.assertEqual(obj.optional, optional)
1337 self.assertEqual(obj.specs, obj_initial.specs)
1339 @given(bit_string_values_strategy())
1340 def test_copy(self, values):
1341 for klass in (BitString, BitStringInherited):
1342 _schema, value, impl, expl, default, optional, _decoded = values
1351 optional=optional or False,
1354 obj_copied = obj.copy()
1355 self.assert_copied_basic_fields(obj, obj_copied)
1356 self.assertEqual(obj.specs, obj_copied.specs)
1357 self.assertEqual(obj._value, obj_copied._value)
1361 integers(min_value=1).map(tag_encode),
1363 def test_stripped(self, value, tag_impl):
1364 obj = BitString(value, impl=tag_impl)
1365 with self.assertRaises(NotEnoughData):
1366 obj.decode(obj.encode()[:-1])
1370 integers(min_value=1).map(tag_ctxc),
1372 def test_stripped_expl(self, value, tag_expl):
1373 obj = BitString(value, expl=tag_expl)
1374 with self.assertRaises(NotEnoughData):
1375 obj.decode(obj.encode()[:-1])
1378 integers(min_value=31),
1379 integers(min_value=0),
1382 def test_bad_tag(self, tag, offset, decode_path):
1383 with self.assertRaises(DecodeError) as err:
1385 tag_encode(tag)[:-1],
1387 decode_path=decode_path,
1390 self.assertEqual(err.exception.offset, offset)
1391 self.assertEqual(err.exception.decode_path, decode_path)
1394 integers(min_value=128),
1395 integers(min_value=0),
1398 def test_bad_len(self, l, offset, decode_path):
1399 with self.assertRaises(DecodeError) as err:
1401 BitString.tag_default + len_encode(l)[:-1],
1403 decode_path=decode_path,
1406 self.assertEqual(err.exception.offset, offset)
1407 self.assertEqual(err.exception.decode_path, decode_path)
1409 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1410 @given(data_strategy())
1411 def test_symmetric(self, d):
1420 ) = d.draw(bit_string_values_strategy(value_required=True))
1421 tail_junk = d.draw(binary(max_size=5))
1422 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1423 offset = d.draw(integers(min_value=0))
1424 for klass in (BitString, BitStringInherited):
1435 pprint(obj, big_blobs=True, with_decode_path=True)
1436 self.assertFalse(obj.expled)
1437 obj_encoded = obj.encode()
1438 obj_expled = obj(value, expl=tag_expl)
1439 self.assertTrue(obj_expled.expled)
1441 list(obj_expled.pps())
1442 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1443 obj_expled_encoded = obj_expled.encode()
1444 ctx_copied = deepcopy(ctx_dummy)
1445 obj_decoded, tail = obj_expled.decode(
1446 obj_expled_encoded + tail_junk,
1450 self.assertDictEqual(ctx_copied, ctx_dummy)
1452 list(obj_decoded.pps())
1453 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1454 self.assertEqual(tail, tail_junk)
1455 self.assertEqual(obj_decoded, obj_expled)
1456 self.assertNotEqual(obj_decoded, obj)
1457 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1458 self.assertEqual(bytes(obj_decoded), bytes(obj))
1459 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1460 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1461 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1463 obj_decoded.expl_llen,
1464 len(len_encode(len(obj_encoded))),
1466 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1467 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1470 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1472 self.assertEqual(obj_decoded.expl_offset, offset)
1473 if isinstance(value, tuple):
1474 self.assertSetEqual(set(value), set(obj_decoded.named))
1478 @given(integers(min_value=1, max_value=255))
1479 def test_bad_zero_value(self, pad_size):
1480 with self.assertRaises(DecodeError):
1481 BitString().decode(b"".join((
1482 BitString.tag_default,
1487 def test_go_vectors_invalid(self):
1493 with self.assertRaises(DecodeError):
1494 BitString().decode(b"".join((
1495 BitString.tag_default,
1500 def test_go_vectors_valid(self):
1501 obj, _ = BitString().decode(b"".join((
1502 BitString.tag_default,
1506 self.assertEqual(bytes(obj), b"")
1507 self.assertEqual(obj.bit_len, 0)
1509 obj, _ = BitString().decode(b"".join((
1510 BitString.tag_default,
1514 self.assertEqual(bytes(obj), b"\x00")
1515 self.assertEqual(obj.bit_len, 1)
1517 obj = BitString((16, b"\x82\x40"))
1518 self.assertTrue(obj[0])
1519 self.assertFalse(obj[1])
1520 self.assertTrue(obj[6])
1521 self.assertTrue(obj[9])
1522 self.assertFalse(obj[17])
1525 integers(min_value=1, max_value=30),
1528 binary(min_size=1, max_size=5),
1530 binary(min_size=1, max_size=5),
1538 lists(booleans(), min_size=1),
1541 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1542 def chunk_constructed(contents):
1544 tag_encode(form=TagFormConstructed, num=3) +
1546 b"".join(BitString(content).encode() for content in contents) +
1550 payload_expected = b""
1551 bit_len_expected = 0
1552 for chunk_input in chunk_inputs:
1553 if isinstance(chunk_input, binary_type):
1554 chunks.append(BitString(chunk_input).encode())
1555 payload_expected += chunk_input
1556 bit_len_expected += len(chunk_input) * 8
1558 chunks.append(chunk_constructed(chunk_input))
1559 payload = b"".join(chunk_input)
1560 payload_expected += payload
1561 bit_len_expected += len(payload) * 8
1562 chunk_last = BitString("'%s'B" % "".join(
1563 "1" if bit else "0" for bit in chunk_last_bits
1565 payload_expected += bytes(chunk_last)
1566 bit_len_expected += chunk_last.bit_len
1567 encoded_indefinite = (
1568 tag_encode(form=TagFormConstructed, num=impl) +
1571 chunk_last.encode() +
1574 encoded_definite = (
1575 tag_encode(form=TagFormConstructed, num=impl) +
1576 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1580 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1581 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1582 for lenindef_expected, encoded in (
1583 (True, encoded_indefinite),
1584 (False, encoded_definite),
1586 obj, tail = BitString(impl=tag_encode(impl)).decode(
1588 ctx={"bered": True},
1590 self.assertSequenceEqual(tail, junk)
1591 self.assertEqual(obj.bit_len, bit_len_expected)
1592 self.assertSequenceEqual(bytes(obj), payload_expected)
1593 self.assertTrue(obj.ber_encoded)
1594 self.assertEqual(obj.lenindef, lenindef_expected)
1595 self.assertTrue(obj.bered)
1597 self.assertTrue(obj.ber_encoded)
1598 self.assertEqual(obj.lenindef, lenindef_expected)
1599 self.assertTrue(obj.bered)
1600 self.assertEqual(len(encoded), obj.tlvlen)
1603 integers(min_value=0),
1606 def test_ber_definite_too_short(self, offset, decode_path):
1607 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1609 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1611 decode_path=decode_path,
1612 ctx={"bered": True},
1614 self.assertEqual(err.exception.decode_path, decode_path)
1615 self.assertEqual(err.exception.offset, offset)
1618 integers(min_value=0),
1621 def test_ber_definite_no_data(self, offset, decode_path):
1622 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1624 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1626 decode_path=decode_path,
1627 ctx={"bered": True},
1629 self.assertEqual(err.exception.decode_path, decode_path)
1630 self.assertEqual(err.exception.offset, offset)
1633 integers(min_value=0),
1635 integers(min_value=1, max_value=3),
1637 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1638 bs = BitString(b"data").encode()
1639 with self.assertRaises(NotEnoughData) as err:
1641 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1643 decode_path=decode_path,
1644 ctx={"bered": True},
1646 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1647 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1650 integers(min_value=0),
1652 integers(min_value=1, max_value=3),
1654 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1655 bs = BitString(b"data").encode()
1656 bs_longer = BitString(b"data-longer").encode()
1657 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1660 tag_encode(3, form=TagFormConstructed) +
1661 len_encode((chunks + 1) * len(bs)) +
1666 decode_path=decode_path,
1667 ctx={"bered": True},
1669 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1670 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1673 integers(min_value=0),
1676 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1677 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1679 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1681 decode_path=decode_path,
1682 ctx={"bered": True},
1684 self.assertEqual(err.exception.decode_path, decode_path)
1685 self.assertEqual(err.exception.offset, offset)
1687 @given(data_strategy())
1688 def test_ber_indefinite_not_multiple(self, d):
1689 bs_short = BitString("'A'H").encode()
1690 bs_full = BitString("'AA'H").encode()
1691 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1692 chunks.append(bs_short)
1693 d.draw(permutations(chunks))
1694 chunks.append(bs_short)
1695 offset = d.draw(integers(min_value=0))
1696 decode_path = d.draw(decode_path_strat)
1697 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1700 tag_encode(3, form=TagFormConstructed) +
1706 decode_path=decode_path,
1707 ctx={"bered": True},
1710 err.exception.decode_path,
1711 decode_path + (str(chunks.index(bs_short)),),
1714 err.exception.offset,
1715 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1718 def test_x690_vector(self):
1719 vector = BitString("'0A3B5F291CD'H")
1720 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1721 self.assertSequenceEqual(tail, b"")
1722 self.assertEqual(obj, vector)
1723 obj, tail = BitString().decode(
1724 hexdec("23800303000A3B0305045F291CD00000"),
1725 ctx={"bered": True},
1727 self.assertSequenceEqual(tail, b"")
1728 self.assertEqual(obj, vector)
1729 self.assertTrue(obj.ber_encoded)
1730 self.assertTrue(obj.lenindef)
1731 self.assertTrue(obj.bered)
1733 self.assertTrue(obj.ber_encoded)
1734 self.assertTrue(obj.lenindef)
1735 self.assertTrue(obj.bered)
1739 def octet_string_values_strategy(draw, do_expl=False):
1740 bound_min, bound_max = sorted(draw(sets(
1741 integers(min_value=0, max_value=1 << 7),
1745 value = draw(one_of(
1747 binary(min_size=bound_min, max_size=bound_max),
1749 default = draw(one_of(
1751 binary(min_size=bound_min, max_size=bound_max),
1754 if draw(booleans()):
1755 bounds = (bound_min, bound_max)
1759 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1761 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1762 optional = draw(one_of(none(), booleans()))
1764 draw(integers(min_value=0)),
1765 draw(integers(min_value=0)),
1766 draw(integers(min_value=0)),
1768 return (value, bounds, impl, expl, default, optional, _decoded)
1771 class OctetStringInherited(OctetString):
1775 class TestOctetString(CommonMixin, TestCase):
1776 base_klass = OctetString
1778 def test_invalid_value_type(self):
1779 with self.assertRaises(InvalidValueType) as err:
1780 OctetString(text_type(123))
1784 def test_optional(self, optional):
1785 obj = OctetString(default=OctetString(b""), optional=optional)
1786 self.assertTrue(obj.optional)
1789 def test_ready(self, value):
1791 self.assertFalse(obj.ready)
1794 pprint(obj, big_blobs=True, with_decode_path=True)
1795 with self.assertRaises(ObjNotReady) as err:
1798 obj = OctetString(value)
1799 self.assertTrue(obj.ready)
1802 pprint(obj, big_blobs=True, with_decode_path=True)
1804 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1805 def test_comparison(self, value1, value2, tag1, tag2):
1806 for klass in (OctetString, OctetStringInherited):
1807 obj1 = klass(value1)
1808 obj2 = klass(value2)
1809 self.assertEqual(obj1 == obj2, value1 == value2)
1810 self.assertEqual(obj1 != obj2, value1 != value2)
1811 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1812 obj1 = klass(value1, impl=tag1)
1813 obj2 = klass(value1, impl=tag2)
1814 self.assertEqual(obj1 == obj2, tag1 == tag2)
1815 self.assertEqual(obj1 != obj2, tag1 != tag2)
1817 @given(lists(binary()))
1818 def test_sorted_works(self, values):
1819 self.assertSequenceEqual(
1820 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1824 @given(data_strategy())
1825 def test_bounds_satisfied(self, d):
1826 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1827 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1828 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1829 OctetString(value=value, bounds=(bound_min, bound_max))
1831 @given(data_strategy())
1832 def test_bounds_unsatisfied(self, d):
1833 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1834 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1835 value = d.draw(binary(max_size=bound_min - 1))
1836 with self.assertRaises(BoundsError) as err:
1837 OctetString(value=value, bounds=(bound_min, bound_max))
1839 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1840 OctetString(bounds=(bound_min, bound_max)).decode(
1841 OctetString(value).encode()
1844 value = d.draw(binary(min_size=bound_max + 1))
1845 with self.assertRaises(BoundsError) as err:
1846 OctetString(value=value, bounds=(bound_min, bound_max))
1848 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1849 OctetString(bounds=(bound_min, bound_max)).decode(
1850 OctetString(value).encode()
1854 @given(data_strategy())
1855 def test_call(self, d):
1856 for klass in (OctetString, OctetStringInherited):
1865 ) = d.draw(octet_string_values_strategy())
1866 obj_initial = klass(
1872 optional_initial or False,
1883 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1884 if (default is None) and (obj_initial.default is not None):
1887 (bounds is None) and
1888 (value is not None) and
1889 (bounds_initial is not None) and
1890 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1894 (bounds is None) and
1895 (default is not None) and
1896 (bounds_initial is not None) and
1897 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1900 obj = obj_initial(value, bounds, impl, expl, default, optional)
1902 value_expected = default if value is None else value
1904 default_initial if value_expected is None
1907 self.assertEqual(obj, value_expected)
1908 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1909 self.assertEqual(obj.expl_tag, expl or expl_initial)
1912 default_initial if default is None else default,
1914 if obj.default is None:
1915 optional = optional_initial if optional is None else optional
1916 optional = False if optional is None else optional
1919 self.assertEqual(obj.optional, optional)
1921 (obj._bound_min, obj._bound_max),
1922 bounds or bounds_initial or (0, float("+inf")),
1925 @given(octet_string_values_strategy())
1926 def test_copy(self, values):
1927 for klass in (OctetString, OctetStringInherited):
1928 obj = klass(*values)
1929 obj_copied = obj.copy()
1930 self.assert_copied_basic_fields(obj, obj_copied)
1931 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1932 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1933 self.assertEqual(obj._value, obj_copied._value)
1937 integers(min_value=1).map(tag_encode),
1939 def test_stripped(self, value, tag_impl):
1940 obj = OctetString(value, impl=tag_impl)
1941 with self.assertRaises(NotEnoughData):
1942 obj.decode(obj.encode()[:-1])
1946 integers(min_value=1).map(tag_ctxc),
1948 def test_stripped_expl(self, value, tag_expl):
1949 obj = OctetString(value, expl=tag_expl)
1950 with self.assertRaises(NotEnoughData):
1951 obj.decode(obj.encode()[:-1])
1954 integers(min_value=31),
1955 integers(min_value=0),
1958 def test_bad_tag(self, tag, offset, decode_path):
1959 with self.assertRaises(DecodeError) as err:
1960 OctetString().decode(
1961 tag_encode(tag)[:-1],
1963 decode_path=decode_path,
1966 self.assertEqual(err.exception.offset, offset)
1967 self.assertEqual(err.exception.decode_path, decode_path)
1970 integers(min_value=128),
1971 integers(min_value=0),
1974 def test_bad_len(self, l, offset, decode_path):
1975 with self.assertRaises(DecodeError) as err:
1976 OctetString().decode(
1977 OctetString.tag_default + len_encode(l)[:-1],
1979 decode_path=decode_path,
1982 self.assertEqual(err.exception.offset, offset)
1983 self.assertEqual(err.exception.decode_path, decode_path)
1986 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1987 integers(min_value=0),
1990 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1991 value, bound_min = list(sorted(ints))
1993 class String(OctetString):
1994 bounds = (bound_min, bound_min)
1995 with self.assertRaises(DecodeError) as err:
1997 OctetString(b"\x00" * value).encode(),
1999 decode_path=decode_path,
2002 self.assertEqual(err.exception.offset, offset)
2003 self.assertEqual(err.exception.decode_path, decode_path)
2005 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2007 octet_string_values_strategy(),
2009 integers(min_value=1).map(tag_ctxc),
2010 integers(min_value=0),
2013 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2014 for klass in (OctetString, OctetStringInherited):
2015 _, _, _, _, default, optional, _decoded = values
2024 pprint(obj, big_blobs=True, with_decode_path=True)
2025 self.assertFalse(obj.expled)
2026 obj_encoded = obj.encode()
2027 obj_expled = obj(value, expl=tag_expl)
2028 self.assertTrue(obj_expled.expled)
2030 list(obj_expled.pps())
2031 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2032 obj_expled_encoded = obj_expled.encode()
2033 ctx_copied = deepcopy(ctx_dummy)
2034 obj_decoded, tail = obj_expled.decode(
2035 obj_expled_encoded + tail_junk,
2039 self.assertDictEqual(ctx_copied, ctx_dummy)
2041 list(obj_decoded.pps())
2042 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2043 self.assertEqual(tail, tail_junk)
2044 self.assertEqual(obj_decoded, obj_expled)
2045 self.assertNotEqual(obj_decoded, obj)
2046 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2047 self.assertEqual(bytes(obj_decoded), bytes(obj))
2048 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2049 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2050 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2052 obj_decoded.expl_llen,
2053 len(len_encode(len(obj_encoded))),
2055 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2056 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2059 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2061 self.assertEqual(obj_decoded.expl_offset, offset)
2064 integers(min_value=1, max_value=30),
2067 binary(min_size=1, max_size=5),
2069 binary(min_size=1, max_size=5),
2079 def test_constructed(self, impl, chunk_inputs, junk):
2080 def chunk_constructed(contents):
2082 tag_encode(form=TagFormConstructed, num=4) +
2084 b"".join(OctetString(content).encode() for content in contents) +
2088 payload_expected = b""
2089 for chunk_input in chunk_inputs:
2090 if isinstance(chunk_input, binary_type):
2091 chunks.append(OctetString(chunk_input).encode())
2092 payload_expected += chunk_input
2094 chunks.append(chunk_constructed(chunk_input))
2095 payload = b"".join(chunk_input)
2096 payload_expected += payload
2097 encoded_indefinite = (
2098 tag_encode(form=TagFormConstructed, num=impl) +
2103 encoded_definite = (
2104 tag_encode(form=TagFormConstructed, num=impl) +
2105 len_encode(len(b"".join(chunks))) +
2108 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2109 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2110 for lenindef_expected, encoded in (
2111 (True, encoded_indefinite),
2112 (False, encoded_definite),
2114 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2116 ctx={"bered": True},
2118 self.assertSequenceEqual(tail, junk)
2119 self.assertSequenceEqual(bytes(obj), payload_expected)
2120 self.assertTrue(obj.ber_encoded)
2121 self.assertEqual(obj.lenindef, lenindef_expected)
2122 self.assertTrue(obj.bered)
2124 self.assertTrue(obj.ber_encoded)
2125 self.assertEqual(obj.lenindef, lenindef_expected)
2126 self.assertTrue(obj.bered)
2127 self.assertEqual(len(encoded), obj.tlvlen)
2130 integers(min_value=0),
2133 def test_ber_definite_too_short(self, offset, decode_path):
2134 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2135 OctetString().decode(
2136 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2138 decode_path=decode_path,
2139 ctx={"bered": True},
2141 self.assertEqual(err.exception.decode_path, decode_path)
2142 self.assertEqual(err.exception.offset, offset)
2145 integers(min_value=0),
2147 integers(min_value=1, max_value=3),
2149 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2150 bs = OctetString(b"data").encode()
2151 with self.assertRaises(NotEnoughData) as err:
2152 OctetString().decode(
2153 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2155 decode_path=decode_path,
2156 ctx={"bered": True},
2158 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2159 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2162 integers(min_value=0),
2164 integers(min_value=1, max_value=3),
2166 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2167 bs = OctetString(b"data").encode()
2168 bs_longer = OctetString(b"data-longer").encode()
2169 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2170 OctetString().decode(
2172 tag_encode(4, form=TagFormConstructed) +
2173 len_encode((chunks + 1) * len(bs)) +
2178 decode_path=decode_path,
2179 ctx={"bered": True},
2181 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2182 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2186 def null_values_strategy(draw, do_expl=False):
2190 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2192 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2193 optional = draw(one_of(none(), booleans()))
2195 draw(integers(min_value=0)),
2196 draw(integers(min_value=0)),
2197 draw(integers(min_value=0)),
2199 return (impl, expl, optional, _decoded)
2202 class NullInherited(Null):
2206 class TestNull(CommonMixin, TestCase):
2209 def test_ready(self):
2211 self.assertTrue(obj.ready)
2214 pprint(obj, big_blobs=True, with_decode_path=True)
2216 @given(binary(), binary())
2217 def test_comparison(self, tag1, tag2):
2218 for klass in (Null, NullInherited):
2219 obj1 = klass(impl=tag1)
2220 obj2 = klass(impl=tag2)
2221 self.assertEqual(obj1 == obj2, tag1 == tag2)
2222 self.assertEqual(obj1 != obj2, tag1 != tag2)
2223 self.assertNotEqual(obj1, tag2)
2225 @given(data_strategy())
2226 def test_call(self, d):
2227 for klass in (Null, NullInherited):
2233 ) = d.draw(null_values_strategy())
2234 obj_initial = klass(
2237 optional=optional_initial or False,
2238 _decoded=_decoded_initial,
2245 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2246 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2247 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2248 self.assertEqual(obj.expl_tag, expl or expl_initial)
2249 optional = optional_initial if optional is None else optional
2250 optional = False if optional is None else optional
2251 self.assertEqual(obj.optional, optional)
2253 @given(null_values_strategy())
2254 def test_copy(self, values):
2255 for klass in (Null, NullInherited):
2256 impl, expl, optional, _decoded = values
2260 optional=optional or False,
2263 obj_copied = obj.copy()
2264 self.assert_copied_basic_fields(obj, obj_copied)
2266 @given(integers(min_value=1).map(tag_encode))
2267 def test_stripped(self, tag_impl):
2268 obj = Null(impl=tag_impl)
2269 with self.assertRaises(NotEnoughData):
2270 obj.decode(obj.encode()[:-1])
2272 @given(integers(min_value=1).map(tag_ctxc))
2273 def test_stripped_expl(self, tag_expl):
2274 obj = Null(expl=tag_expl)
2275 with self.assertRaises(NotEnoughData):
2276 obj.decode(obj.encode()[:-1])
2279 integers(min_value=31),
2280 integers(min_value=0),
2283 def test_bad_tag(self, tag, offset, decode_path):
2284 with self.assertRaises(DecodeError) as err:
2286 tag_encode(tag)[:-1],
2288 decode_path=decode_path,
2291 self.assertEqual(err.exception.offset, offset)
2292 self.assertEqual(err.exception.decode_path, decode_path)
2295 integers(min_value=128),
2296 integers(min_value=0),
2299 def test_bad_len(self, l, offset, decode_path):
2300 with self.assertRaises(DecodeError) as err:
2302 Null.tag_default + len_encode(l)[:-1],
2304 decode_path=decode_path,
2307 self.assertEqual(err.exception.offset, offset)
2308 self.assertEqual(err.exception.decode_path, decode_path)
2310 @given(binary(min_size=1))
2311 def test_tag_mismatch(self, impl):
2312 assume(impl != Null.tag_default)
2313 with self.assertRaises(TagMismatch):
2314 Null(impl=impl).decode(Null().encode())
2317 null_values_strategy(),
2318 integers(min_value=1).map(tag_ctxc),
2319 integers(min_value=0),
2322 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2323 for klass in (Null, NullInherited):
2324 _, _, optional, _decoded = values
2325 obj = klass(optional=optional, _decoded=_decoded)
2328 pprint(obj, big_blobs=True, with_decode_path=True)
2329 self.assertFalse(obj.expled)
2330 obj_encoded = obj.encode()
2331 obj_expled = obj(expl=tag_expl)
2332 self.assertTrue(obj_expled.expled)
2334 list(obj_expled.pps())
2335 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2336 obj_expled_encoded = obj_expled.encode()
2337 ctx_copied = deepcopy(ctx_dummy)
2338 obj_decoded, tail = obj_expled.decode(
2339 obj_expled_encoded + tail_junk,
2343 self.assertDictEqual(ctx_copied, ctx_dummy)
2345 list(obj_decoded.pps())
2346 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2347 self.assertEqual(tail, tail_junk)
2348 self.assertEqual(obj_decoded, obj_expled)
2349 self.assertNotEqual(obj_decoded, obj)
2350 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2351 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2352 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2354 obj_decoded.expl_llen,
2355 len(len_encode(len(obj_encoded))),
2357 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2358 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2361 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2363 self.assertEqual(obj_decoded.expl_offset, offset)
2365 @given(integers(min_value=1))
2366 def test_invalid_len(self, l):
2367 with self.assertRaises(InvalidLength):
2368 Null().decode(b"".join((
2375 def oid_strategy(draw):
2376 first_arc = draw(integers(min_value=0, max_value=2))
2378 if first_arc in (0, 1):
2379 second_arc = draw(integers(min_value=0, max_value=39))
2381 second_arc = draw(integers(min_value=0))
2382 other_arcs = draw(lists(integers(min_value=0)))
2383 return tuple([first_arc, second_arc] + other_arcs)
2387 def oid_values_strategy(draw, do_expl=False):
2388 value = draw(one_of(none(), oid_strategy()))
2392 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2394 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2395 default = draw(one_of(none(), oid_strategy()))
2396 optional = draw(one_of(none(), booleans()))
2398 draw(integers(min_value=0)),
2399 draw(integers(min_value=0)),
2400 draw(integers(min_value=0)),
2402 return (value, impl, expl, default, optional, _decoded)
2405 class ObjectIdentifierInherited(ObjectIdentifier):
2409 class TestObjectIdentifier(CommonMixin, TestCase):
2410 base_klass = ObjectIdentifier
2412 def test_invalid_value_type(self):
2413 with self.assertRaises(InvalidValueType) as err:
2414 ObjectIdentifier(123)
2418 def test_optional(self, optional):
2419 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2420 self.assertTrue(obj.optional)
2422 @given(oid_strategy())
2423 def test_ready(self, value):
2424 obj = ObjectIdentifier()
2425 self.assertFalse(obj.ready)
2428 pprint(obj, big_blobs=True, with_decode_path=True)
2429 with self.assertRaises(ObjNotReady) as err:
2432 obj = ObjectIdentifier(value)
2433 self.assertTrue(obj.ready)
2434 self.assertFalse(obj.ber_encoded)
2437 pprint(obj, big_blobs=True, with_decode_path=True)
2440 @given(oid_strategy(), oid_strategy(), binary(), binary())
2441 def test_comparison(self, value1, value2, tag1, tag2):
2442 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2443 obj1 = klass(value1)
2444 obj2 = klass(value2)
2445 self.assertEqual(obj1 == obj2, value1 == value2)
2446 self.assertEqual(obj1 != obj2, value1 != value2)
2447 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2448 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2449 obj1 = klass(value1, impl=tag1)
2450 obj2 = klass(value1, impl=tag2)
2451 self.assertEqual(obj1 == obj2, tag1 == tag2)
2452 self.assertEqual(obj1 != obj2, tag1 != tag2)
2454 @given(lists(oid_strategy()))
2455 def test_sorted_works(self, values):
2456 self.assertSequenceEqual(
2457 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2461 @given(data_strategy())
2462 def test_call(self, d):
2463 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2471 ) = d.draw(oid_values_strategy())
2472 obj_initial = klass(
2473 value=value_initial,
2476 default=default_initial,
2477 optional=optional_initial or False,
2478 _decoded=_decoded_initial,
2487 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2496 value_expected = default if value is None else value
2498 default_initial if value_expected is None
2501 self.assertEqual(obj, value_expected)
2502 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2503 self.assertEqual(obj.expl_tag, expl or expl_initial)
2506 default_initial if default is None else default,
2508 if obj.default is None:
2509 optional = optional_initial if optional is None else optional
2510 optional = False if optional is None else optional
2513 self.assertEqual(obj.optional, optional)
2515 @given(oid_values_strategy())
2516 def test_copy(self, values):
2517 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2534 obj_copied = obj.copy()
2535 self.assert_copied_basic_fields(obj, obj_copied)
2536 self.assertEqual(obj._value, obj_copied._value)
2538 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2541 integers(min_value=1).map(tag_encode),
2543 def test_stripped(self, value, tag_impl):
2544 obj = ObjectIdentifier(value, impl=tag_impl)
2545 with self.assertRaises(NotEnoughData):
2546 obj.decode(obj.encode()[:-1])
2550 integers(min_value=1).map(tag_ctxc),
2552 def test_stripped_expl(self, value, tag_expl):
2553 obj = ObjectIdentifier(value, expl=tag_expl)
2554 with self.assertRaises(NotEnoughData):
2555 obj.decode(obj.encode()[:-1])
2558 integers(min_value=31),
2559 integers(min_value=0),
2562 def test_bad_tag(self, tag, offset, decode_path):
2563 with self.assertRaises(DecodeError) as err:
2564 ObjectIdentifier().decode(
2565 tag_encode(tag)[:-1],
2567 decode_path=decode_path,
2570 self.assertEqual(err.exception.offset, offset)
2571 self.assertEqual(err.exception.decode_path, decode_path)
2574 integers(min_value=128),
2575 integers(min_value=0),
2578 def test_bad_len(self, l, offset, decode_path):
2579 with self.assertRaises(DecodeError) as err:
2580 ObjectIdentifier().decode(
2581 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2583 decode_path=decode_path,
2586 self.assertEqual(err.exception.offset, offset)
2587 self.assertEqual(err.exception.decode_path, decode_path)
2589 def test_zero_oid(self):
2590 with self.assertRaises(NotEnoughData):
2591 ObjectIdentifier().decode(
2592 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2595 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2596 @given(oid_strategy())
2597 def test_unfinished_oid(self, value):
2598 assume(list(value)[-1] > 255)
2599 obj_encoded = ObjectIdentifier(value).encode()
2600 obj, _ = ObjectIdentifier().decode(obj_encoded)
2601 data = obj_encoded[obj.tlen + obj.llen:-1]
2603 ObjectIdentifier.tag_default,
2604 len_encode(len(data)),
2607 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2610 @given(integers(min_value=0))
2611 def test_invalid_short(self, value):
2612 with self.assertRaises(InvalidOID):
2613 ObjectIdentifier((value,))
2614 with self.assertRaises(InvalidOID):
2615 ObjectIdentifier("%d" % value)
2617 @given(integers(min_value=3), integers(min_value=0))
2618 def test_invalid_first_arc(self, first_arc, second_arc):
2619 with self.assertRaises(InvalidOID):
2620 ObjectIdentifier((first_arc, second_arc))
2621 with self.assertRaises(InvalidOID):
2622 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2624 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2625 def test_invalid_second_arc(self, first_arc, second_arc):
2626 with self.assertRaises(InvalidOID):
2627 ObjectIdentifier((first_arc, second_arc))
2628 with self.assertRaises(InvalidOID):
2629 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2631 @given(text(alphabet=ascii_letters + ".", min_size=1))
2632 def test_junk(self, oid):
2633 with self.assertRaises(InvalidOID):
2634 ObjectIdentifier(oid)
2636 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2637 @given(oid_strategy())
2638 def test_validness(self, oid):
2639 obj = ObjectIdentifier(oid)
2640 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2643 pprint(obj, big_blobs=True, with_decode_path=True)
2645 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2647 oid_values_strategy(),
2649 integers(min_value=1).map(tag_ctxc),
2650 integers(min_value=0),
2653 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2654 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2655 _, _, _, default, optional, _decoded = values
2664 pprint(obj, big_blobs=True, with_decode_path=True)
2665 self.assertFalse(obj.expled)
2666 obj_encoded = obj.encode()
2667 obj_expled = obj(value, expl=tag_expl)
2668 self.assertTrue(obj_expled.expled)
2670 list(obj_expled.pps())
2671 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2672 obj_expled_encoded = obj_expled.encode()
2673 ctx_copied = deepcopy(ctx_dummy)
2674 obj_decoded, tail = obj_expled.decode(
2675 obj_expled_encoded + tail_junk,
2679 self.assertDictEqual(ctx_copied, ctx_dummy)
2681 list(obj_decoded.pps())
2682 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2683 self.assertEqual(tail, tail_junk)
2684 self.assertEqual(obj_decoded, obj_expled)
2685 self.assertNotEqual(obj_decoded, obj)
2686 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2687 self.assertEqual(tuple(obj_decoded), tuple(obj))
2688 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2689 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2690 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2692 obj_decoded.expl_llen,
2693 len(len_encode(len(obj_encoded))),
2695 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2696 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2699 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2701 self.assertEqual(obj_decoded.expl_offset, offset)
2704 oid_strategy().map(ObjectIdentifier),
2705 oid_strategy().map(ObjectIdentifier),
2707 def test_add(self, oid1, oid2):
2708 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2709 for oid_to_add in (oid2, tuple(oid2)):
2710 self.assertEqual(oid1 + oid_to_add, oid_expect)
2711 with self.assertRaises(InvalidValueType):
2714 def test_go_vectors_valid(self):
2715 for data, expect in (
2717 (b"\x55\x02", (2, 5, 2)),
2718 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2719 (b"\x81\x34\x03", (2, 100, 3)),
2722 ObjectIdentifier().decode(b"".join((
2723 ObjectIdentifier.tag_default,
2724 len_encode(len(data)),
2730 def test_go_vectors_invalid(self):
2731 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2732 with self.assertRaises(DecodeError):
2733 ObjectIdentifier().decode(b"".join((
2734 Integer.tag_default,
2735 len_encode(len(data)),
2739 def test_x690_vector(self):
2741 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2742 ObjectIdentifier((2, 999, 3)),
2745 @given(data_strategy())
2746 def test_nonnormalized_first_arc(self, d):
2748 ObjectIdentifier.tag_default +
2751 ObjectIdentifier((1, 0)).encode()[-1:]
2753 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2754 self.assertTrue(obj.ber_encoded)
2755 self.assertTrue(obj.bered)
2757 self.assertTrue(obj.ber_encoded)
2758 self.assertTrue(obj.bered)
2759 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2760 ObjectIdentifier().decode(tampered)
2762 @given(data_strategy())
2763 def test_nonnormalized_arcs(self, d):
2764 arcs = d.draw(lists(
2765 integers(min_value=0, max_value=100),
2769 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2770 _, tlen, lv = tag_strip(dered)
2771 _, llen, v = len_decode(lv)
2772 v_no_first_arc = v[1:]
2773 idx_for_tamper = d.draw(integers(
2775 max_value=len(v_no_first_arc) - 1,
2777 tampered = list(bytearray(v_no_first_arc))
2778 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2779 tampered.insert(idx_for_tamper, 0x80)
2780 tampered = bytes(bytearray(tampered))
2782 ObjectIdentifier.tag_default +
2783 len_encode(len(tampered)) +
2786 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2787 self.assertTrue(obj.ber_encoded)
2788 self.assertTrue(obj.bered)
2790 self.assertTrue(obj.ber_encoded)
2791 self.assertTrue(obj.bered)
2792 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2793 ObjectIdentifier().decode(tampered)
2797 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2799 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2800 values = list(draw(sets(
2802 min_size=len(schema),
2803 max_size=len(schema),
2805 schema = list(zip(schema, values))
2806 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2810 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2812 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2813 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2814 optional = draw(one_of(none(), booleans()))
2816 draw(integers(min_value=0)),
2817 draw(integers(min_value=0)),
2818 draw(integers(min_value=0)),
2820 return (schema, value, impl, expl, default, optional, _decoded)
2823 class TestEnumerated(CommonMixin, TestCase):
2824 class EWhatever(Enumerated):
2825 schema = (("whatever", 0),)
2827 base_klass = EWhatever
2829 def test_schema_required(self):
2830 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2833 def test_invalid_value_type(self):
2834 with self.assertRaises(InvalidValueType) as err:
2835 self.base_klass((1, 2))
2838 @given(sets(text_letters(), min_size=2))
2839 def test_unknown_name(self, schema_input):
2840 missing = schema_input.pop()
2842 class E(Enumerated):
2843 schema = [(n, 123) for n in schema_input]
2844 with self.assertRaises(ObjUnknown) as err:
2849 sets(text_letters(), min_size=2),
2850 sets(integers(), min_size=2),
2852 def test_unknown_value(self, schema_input, values_input):
2854 missing_value = values_input.pop()
2855 _input = list(zip(schema_input, values_input))
2857 class E(Enumerated):
2859 with self.assertRaises(DecodeError) as err:
2864 def test_optional(self, optional):
2865 obj = self.base_klass(default="whatever", optional=optional)
2866 self.assertTrue(obj.optional)
2868 def test_ready(self):
2869 obj = self.base_klass()
2870 self.assertFalse(obj.ready)
2873 pprint(obj, big_blobs=True, with_decode_path=True)
2874 with self.assertRaises(ObjNotReady) as err:
2877 obj = self.base_klass("whatever")
2878 self.assertTrue(obj.ready)
2881 pprint(obj, big_blobs=True, with_decode_path=True)
2883 @given(integers(), integers(), binary(), binary())
2884 def test_comparison(self, value1, value2, tag1, tag2):
2885 class E(Enumerated):
2887 ("whatever0", value1),
2888 ("whatever1", value2),
2891 class EInherited(E):
2893 for klass in (E, EInherited):
2894 obj1 = klass(value1)
2895 obj2 = klass(value2)
2896 self.assertEqual(obj1 == obj2, value1 == value2)
2897 self.assertEqual(obj1 != obj2, value1 != value2)
2898 self.assertEqual(obj1 == int(obj2), value1 == value2)
2899 obj1 = klass(value1, impl=tag1)
2900 obj2 = klass(value1, impl=tag2)
2901 self.assertEqual(obj1 == obj2, tag1 == tag2)
2902 self.assertEqual(obj1 != obj2, tag1 != tag2)
2904 @given(data_strategy())
2905 def test_call(self, d):
2914 ) = d.draw(enumerated_values_strategy())
2916 class E(Enumerated):
2917 schema = schema_initial
2919 value=value_initial,
2922 default=default_initial,
2923 optional=optional_initial or False,
2924 _decoded=_decoded_initial,
2934 ) = d.draw(enumerated_values_strategy(
2935 schema=schema_initial,
2936 do_expl=impl_initial is None,
2946 value_expected = default if value is None else value
2948 default_initial if value_expected is None
2953 dict(schema_initial).get(value_expected, value_expected),
2955 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2956 self.assertEqual(obj.expl_tag, expl or expl_initial)
2959 default_initial if default is None else default,
2961 if obj.default is None:
2962 optional = optional_initial if optional is None else optional
2963 optional = False if optional is None else optional
2966 self.assertEqual(obj.optional, optional)
2967 self.assertEqual(obj.specs, dict(schema_initial))
2969 @given(enumerated_values_strategy())
2970 def test_copy(self, values):
2971 schema_input, value, impl, expl, default, optional, _decoded = values
2973 class E(Enumerated):
2974 schema = schema_input
2983 obj_copied = obj.copy()
2984 self.assert_copied_basic_fields(obj, obj_copied)
2985 self.assertEqual(obj.specs, obj_copied.specs)
2987 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2988 @given(data_strategy())
2989 def test_symmetric(self, d):
2990 schema_input, _, _, _, default, optional, _decoded = d.draw(
2991 enumerated_values_strategy(),
2993 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2994 offset = d.draw(integers(min_value=0))
2995 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2996 tail_junk = d.draw(binary(max_size=5))
2998 class E(Enumerated):
2999 schema = schema_input
3008 pprint(obj, big_blobs=True, with_decode_path=True)
3009 self.assertFalse(obj.expled)
3010 obj_encoded = obj.encode()
3011 obj_expled = obj(value, expl=tag_expl)
3012 self.assertTrue(obj_expled.expled)
3014 list(obj_expled.pps())
3015 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3016 obj_expled_encoded = obj_expled.encode()
3017 ctx_copied = deepcopy(ctx_dummy)
3018 obj_decoded, tail = obj_expled.decode(
3019 obj_expled_encoded + tail_junk,
3023 self.assertDictEqual(ctx_copied, ctx_dummy)
3025 list(obj_decoded.pps())
3026 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3027 self.assertEqual(tail, tail_junk)
3028 self.assertEqual(obj_decoded, obj_expled)
3029 self.assertNotEqual(obj_decoded, obj)
3030 self.assertEqual(int(obj_decoded), int(obj_expled))
3031 self.assertEqual(int(obj_decoded), int(obj))
3032 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3033 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3034 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3036 obj_decoded.expl_llen,
3037 len(len_encode(len(obj_encoded))),
3039 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3040 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3043 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3045 self.assertEqual(obj_decoded.expl_offset, offset)
3049 def string_values_strategy(draw, alphabet, do_expl=False):
3050 bound_min, bound_max = sorted(draw(sets(
3051 integers(min_value=0, max_value=1 << 7),
3055 value = draw(one_of(
3057 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3059 default = draw(one_of(
3061 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3064 if draw(booleans()):
3065 bounds = (bound_min, bound_max)
3069 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3071 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3072 optional = draw(one_of(none(), booleans()))
3074 draw(integers(min_value=0)),
3075 draw(integers(min_value=0)),
3076 draw(integers(min_value=0)),
3078 return (value, bounds, impl, expl, default, optional, _decoded)
3081 class StringMixin(object):
3082 def test_invalid_value_type(self):
3083 with self.assertRaises(InvalidValueType) as err:
3084 self.base_klass((1, 2))
3087 def text_alphabet(self):
3088 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3089 return printable + whitespace
3093 def test_optional(self, optional):
3094 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3095 self.assertTrue(obj.optional)
3097 @given(data_strategy())
3098 def test_ready(self, d):
3099 obj = self.base_klass()
3100 self.assertFalse(obj.ready)
3103 pprint(obj, big_blobs=True, with_decode_path=True)
3105 with self.assertRaises(ObjNotReady) as err:
3108 value = d.draw(text(alphabet=self.text_alphabet()))
3109 obj = self.base_klass(value)
3110 self.assertTrue(obj.ready)
3113 pprint(obj, big_blobs=True, with_decode_path=True)
3116 @given(data_strategy())
3117 def test_comparison(self, d):
3118 value1 = d.draw(text(alphabet=self.text_alphabet()))
3119 value2 = d.draw(text(alphabet=self.text_alphabet()))
3120 tag1 = d.draw(binary(min_size=1))
3121 tag2 = d.draw(binary(min_size=1))
3122 obj1 = self.base_klass(value1)
3123 obj2 = self.base_klass(value2)
3124 self.assertEqual(obj1 == obj2, value1 == value2)
3125 self.assertEqual(obj1 != obj2, value1 != value2)
3126 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3127 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3128 obj1 = self.base_klass(value1, impl=tag1)
3129 obj2 = self.base_klass(value1, impl=tag2)
3130 self.assertEqual(obj1 == obj2, tag1 == tag2)
3131 self.assertEqual(obj1 != obj2, tag1 != tag2)
3133 @given(data_strategy())
3134 def test_bounds_satisfied(self, d):
3135 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3136 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3137 value = d.draw(text(
3138 alphabet=self.text_alphabet(),
3142 self.base_klass(value=value, bounds=(bound_min, bound_max))
3144 @given(data_strategy())
3145 def test_bounds_unsatisfied(self, d):
3146 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3147 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3148 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3149 with self.assertRaises(BoundsError) as err:
3150 self.base_klass(value=value, bounds=(bound_min, bound_max))
3152 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3153 self.base_klass(bounds=(bound_min, bound_max)).decode(
3154 self.base_klass(value).encode()
3157 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3158 with self.assertRaises(BoundsError) as err:
3159 self.base_klass(value=value, bounds=(bound_min, bound_max))
3161 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3162 self.base_klass(bounds=(bound_min, bound_max)).decode(
3163 self.base_klass(value).encode()
3167 @given(data_strategy())
3168 def test_call(self, d):
3177 ) = d.draw(string_values_strategy(self.text_alphabet()))
3178 obj_initial = self.base_klass(
3184 optional_initial or False,
3195 ) = d.draw(string_values_strategy(
3196 self.text_alphabet(),
3197 do_expl=impl_initial is None,
3199 if (default is None) and (obj_initial.default is not None):
3202 (bounds is None) and
3203 (value is not None) and
3204 (bounds_initial is not None) and
3205 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3209 (bounds is None) and
3210 (default is not None) and
3211 (bounds_initial is not None) and
3212 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3215 obj = obj_initial(value, bounds, impl, expl, default, optional)
3217 value_expected = default if value is None else value
3219 default_initial if value_expected is None
3222 self.assertEqual(obj, value_expected)
3223 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3224 self.assertEqual(obj.expl_tag, expl or expl_initial)
3227 default_initial if default is None else default,
3229 if obj.default is None:
3230 optional = optional_initial if optional is None else optional
3231 optional = False if optional is None else optional
3234 self.assertEqual(obj.optional, optional)
3236 (obj._bound_min, obj._bound_max),
3237 bounds or bounds_initial or (0, float("+inf")),
3240 @given(data_strategy())
3241 def test_copy(self, d):
3242 values = d.draw(string_values_strategy(self.text_alphabet()))
3243 obj = self.base_klass(*values)
3244 obj_copied = obj.copy()
3245 self.assert_copied_basic_fields(obj, obj_copied)
3246 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3247 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3248 self.assertEqual(obj._value, obj_copied._value)
3250 @given(data_strategy())
3251 def test_stripped(self, d):
3252 value = d.draw(text(alphabet=self.text_alphabet()))
3253 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3254 obj = self.base_klass(value, impl=tag_impl)
3255 with self.assertRaises(NotEnoughData):
3256 obj.decode(obj.encode()[:-1])
3258 @given(data_strategy())
3259 def test_stripped_expl(self, d):
3260 value = d.draw(text(alphabet=self.text_alphabet()))
3261 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3262 obj = self.base_klass(value, expl=tag_expl)
3263 with self.assertRaises(NotEnoughData):
3264 obj.decode(obj.encode()[:-1])
3267 integers(min_value=31),
3268 integers(min_value=0),
3271 def test_bad_tag(self, tag, offset, decode_path):
3272 with self.assertRaises(DecodeError) as err:
3273 self.base_klass().decode(
3274 tag_encode(tag)[:-1],
3276 decode_path=decode_path,
3279 self.assertEqual(err.exception.offset, offset)
3280 self.assertEqual(err.exception.decode_path, decode_path)
3283 integers(min_value=128),
3284 integers(min_value=0),
3287 def test_bad_len(self, l, offset, decode_path):
3288 with self.assertRaises(DecodeError) as err:
3289 self.base_klass().decode(
3290 self.base_klass.tag_default + len_encode(l)[:-1],
3292 decode_path=decode_path,
3295 self.assertEqual(err.exception.offset, offset)
3296 self.assertEqual(err.exception.decode_path, decode_path)
3299 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3300 integers(min_value=0),
3303 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3304 value, bound_min = list(sorted(ints))
3306 class String(self.base_klass):
3307 # Multiply this value by four, to satisfy UTF-32 bounds
3308 # (4 bytes per character) validation
3309 bounds = (bound_min * 4, bound_min * 4)
3310 with self.assertRaises(DecodeError) as err:
3312 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3314 decode_path=decode_path,
3317 self.assertEqual(err.exception.offset, offset)
3318 self.assertEqual(err.exception.decode_path, decode_path)
3320 @given(data_strategy())
3321 def test_symmetric(self, d):
3322 values = d.draw(string_values_strategy(self.text_alphabet()))
3323 value = d.draw(text(alphabet=self.text_alphabet()))
3324 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3325 offset = d.draw(integers(min_value=0))
3326 tail_junk = d.draw(binary(max_size=5))
3327 _, _, _, _, default, optional, _decoded = values
3328 obj = self.base_klass(
3336 pprint(obj, big_blobs=True, with_decode_path=True)
3337 self.assertFalse(obj.expled)
3338 obj_encoded = obj.encode()
3339 obj_expled = obj(value, expl=tag_expl)
3340 self.assertTrue(obj_expled.expled)
3342 list(obj_expled.pps())
3343 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3344 obj_expled_encoded = obj_expled.encode()
3345 ctx_copied = deepcopy(ctx_dummy)
3346 obj_decoded, tail = obj_expled.decode(
3347 obj_expled_encoded + tail_junk,
3351 self.assertDictEqual(ctx_copied, ctx_dummy)
3353 list(obj_decoded.pps())
3354 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3355 self.assertEqual(tail, tail_junk)
3356 self.assertEqual(obj_decoded, obj_expled)
3357 self.assertNotEqual(obj_decoded, obj)
3358 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3359 self.assertEqual(bytes(obj_decoded), bytes(obj))
3360 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3361 self.assertEqual(text_type(obj_decoded), text_type(obj))
3362 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3363 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3364 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3366 obj_decoded.expl_llen,
3367 len(len_encode(len(obj_encoded))),
3369 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3370 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3373 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3375 self.assertEqual(obj_decoded.expl_offset, offset)
3378 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3379 base_klass = UTF8String
3382 cyrillic_letters = text(
3383 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3389 class UnicodeDecodeErrorMixin(object):
3390 @given(cyrillic_letters)
3391 def test_unicode_decode_error(self, cyrillic_text):
3392 with self.assertRaises(DecodeError):
3393 self.base_klass(cyrillic_text)
3396 class TestNumericString(StringMixin, CommonMixin, TestCase):
3397 base_klass = NumericString
3399 def text_alphabet(self):
3402 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3403 def test_non_numeric(self, non_numeric_text):
3404 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3405 self.base_klass(non_numeric_text)
3408 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3409 integers(min_value=0),
3412 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3413 value, bound_min = list(sorted(ints))
3415 class String(self.base_klass):
3416 bounds = (bound_min, bound_min)
3417 with self.assertRaises(DecodeError) as err:
3419 self.base_klass(b"1" * value).encode(),
3421 decode_path=decode_path,
3424 self.assertEqual(err.exception.offset, offset)
3425 self.assertEqual(err.exception.decode_path, decode_path)
3428 class TestPrintableString(
3429 UnicodeDecodeErrorMixin,
3434 base_klass = PrintableString
3436 def text_alphabet(self):
3437 return ascii_letters + digits + " '()+,-./:=?"
3439 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3440 def test_non_printable(self, non_printable_text):
3441 with assertRaisesRegex(self, DecodeError, "non-printable"):
3442 self.base_klass(non_printable_text)
3445 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3446 integers(min_value=0),
3449 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3450 value, bound_min = list(sorted(ints))
3452 class String(self.base_klass):
3453 bounds = (bound_min, bound_min)
3454 with self.assertRaises(DecodeError) as err:
3456 self.base_klass(b"1" * value).encode(),
3458 decode_path=decode_path,
3461 self.assertEqual(err.exception.offset, offset)
3462 self.assertEqual(err.exception.decode_path, decode_path)
3465 class TestTeletexString(
3466 UnicodeDecodeErrorMixin,
3471 base_klass = TeletexString
3474 class TestVideotexString(
3475 UnicodeDecodeErrorMixin,
3480 base_klass = VideotexString
3483 class TestIA5String(
3484 UnicodeDecodeErrorMixin,
3489 base_klass = IA5String
3492 class TestGraphicString(
3493 UnicodeDecodeErrorMixin,
3498 base_klass = GraphicString
3501 class TestVisibleString(
3502 UnicodeDecodeErrorMixin,
3507 base_klass = VisibleString
3509 def test_x690_vector(self):
3510 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3511 self.assertSequenceEqual(tail, b"")
3512 self.assertEqual(str(obj), "Jones")
3513 self.assertFalse(obj.ber_encoded)
3514 self.assertFalse(obj.lenindef)
3515 self.assertFalse(obj.bered)
3517 obj, tail = VisibleString().decode(
3518 hexdec("3A0904034A6F6E04026573"),
3519 ctx={"bered": True},
3521 self.assertSequenceEqual(tail, b"")
3522 self.assertEqual(str(obj), "Jones")
3523 self.assertTrue(obj.ber_encoded)
3524 self.assertFalse(obj.lenindef)
3525 self.assertTrue(obj.bered)
3527 self.assertTrue(obj.ber_encoded)
3528 self.assertFalse(obj.lenindef)
3529 self.assertTrue(obj.bered)
3531 obj, tail = VisibleString().decode(
3532 hexdec("3A8004034A6F6E040265730000"),
3533 ctx={"bered": True},
3535 self.assertSequenceEqual(tail, b"")
3536 self.assertEqual(str(obj), "Jones")
3537 self.assertTrue(obj.ber_encoded)
3538 self.assertTrue(obj.lenindef)
3539 self.assertTrue(obj.bered)
3541 self.assertTrue(obj.ber_encoded)
3542 self.assertTrue(obj.lenindef)
3543 self.assertTrue(obj.bered)
3546 class TestGeneralString(
3547 UnicodeDecodeErrorMixin,
3552 base_klass = GeneralString
3555 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3556 base_klass = UniversalString
3559 class TestBMPString(StringMixin, CommonMixin, TestCase):
3560 base_klass = BMPString
3564 def generalized_time_values_strategy(
3572 if draw(booleans()):
3573 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3575 value = value.replace(microsecond=0)
3577 if draw(booleans()):
3578 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3580 default = default.replace(microsecond=0)
3584 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3586 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3587 optional = draw(one_of(none(), booleans()))
3589 draw(integers(min_value=0)),
3590 draw(integers(min_value=0)),
3591 draw(integers(min_value=0)),
3593 return (value, impl, expl, default, optional, _decoded)
3596 class TimeMixin(object):
3597 def test_invalid_value_type(self):
3598 with self.assertRaises(InvalidValueType) as err:
3599 self.base_klass(datetime.now().timetuple())
3602 @given(data_strategy())
3603 def test_optional(self, d):
3604 default = d.draw(datetimes(
3605 min_value=self.min_datetime,
3606 max_value=self.max_datetime,
3608 optional = d.draw(booleans())
3609 obj = self.base_klass(default=default, optional=optional)
3610 self.assertTrue(obj.optional)
3612 @given(data_strategy())
3613 def test_ready(self, d):
3614 obj = self.base_klass()
3615 self.assertFalse(obj.ready)
3618 pprint(obj, big_blobs=True, with_decode_path=True)
3619 with self.assertRaises(ObjNotReady) as err:
3622 value = d.draw(datetimes(min_value=self.min_datetime))
3623 obj = self.base_klass(value)
3624 self.assertTrue(obj.ready)
3627 pprint(obj, big_blobs=True, with_decode_path=True)
3629 @given(data_strategy())
3630 def test_comparison(self, d):
3631 value1 = d.draw(datetimes(
3632 min_value=self.min_datetime,
3633 max_value=self.max_datetime,
3635 value2 = d.draw(datetimes(
3636 min_value=self.min_datetime,
3637 max_value=self.max_datetime,
3639 tag1 = d.draw(binary(min_size=1))
3640 tag2 = d.draw(binary(min_size=1))
3642 value1 = value1.replace(microsecond=0)
3643 value2 = value2.replace(microsecond=0)
3644 obj1 = self.base_klass(value1)
3645 obj2 = self.base_klass(value2)
3646 self.assertEqual(obj1 == obj2, value1 == value2)
3647 self.assertEqual(obj1 != obj2, value1 != value2)
3648 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3649 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3650 obj1 = self.base_klass(value1, impl=tag1)
3651 obj2 = self.base_klass(value1, impl=tag2)
3652 self.assertEqual(obj1 == obj2, tag1 == tag2)
3653 self.assertEqual(obj1 != obj2, tag1 != tag2)
3655 @given(data_strategy())
3656 def test_call(self, d):
3664 ) = d.draw(generalized_time_values_strategy(
3665 min_datetime=self.min_datetime,
3666 max_datetime=self.max_datetime,
3667 omit_ms=self.omit_ms,
3669 obj_initial = self.base_klass(
3670 value=value_initial,
3673 default=default_initial,
3674 optional=optional_initial or False,
3675 _decoded=_decoded_initial,
3684 ) = d.draw(generalized_time_values_strategy(
3685 min_datetime=self.min_datetime,
3686 max_datetime=self.max_datetime,
3687 omit_ms=self.omit_ms,
3688 do_expl=impl_initial is None,
3698 value_expected = default if value is None else value
3700 default_initial if value_expected is None
3703 self.assertEqual(obj, value_expected)
3704 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3705 self.assertEqual(obj.expl_tag, expl or expl_initial)
3708 default_initial if default is None else default,
3710 if obj.default is None:
3711 optional = optional_initial if optional is None else optional
3712 optional = False if optional is None else optional
3715 self.assertEqual(obj.optional, optional)
3717 @given(data_strategy())
3718 def test_copy(self, d):
3719 values = d.draw(generalized_time_values_strategy(
3720 min_datetime=self.min_datetime,
3721 max_datetime=self.max_datetime,
3723 obj = self.base_klass(*values)
3724 obj_copied = obj.copy()
3725 self.assert_copied_basic_fields(obj, obj_copied)
3726 self.assertEqual(obj._value, obj_copied._value)
3728 @given(data_strategy())
3729 def test_stripped(self, d):
3730 value = d.draw(datetimes(
3731 min_value=self.min_datetime,
3732 max_value=self.max_datetime,
3734 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3735 obj = self.base_klass(value, impl=tag_impl)
3736 with self.assertRaises(NotEnoughData):
3737 obj.decode(obj.encode()[:-1])
3739 @given(data_strategy())
3740 def test_stripped_expl(self, d):
3741 value = d.draw(datetimes(
3742 min_value=self.min_datetime,
3743 max_value=self.max_datetime,
3745 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3746 obj = self.base_klass(value, expl=tag_expl)
3747 with self.assertRaises(NotEnoughData):
3748 obj.decode(obj.encode()[:-1])
3750 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3751 @given(data_strategy())
3752 def test_symmetric(self, d):
3753 values = d.draw(generalized_time_values_strategy(
3754 min_datetime=self.min_datetime,
3755 max_datetime=self.max_datetime,
3757 value = d.draw(datetimes(
3758 min_value=self.min_datetime,
3759 max_value=self.max_datetime,
3761 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3762 offset = d.draw(integers(min_value=0))
3763 tail_junk = d.draw(binary(max_size=5))
3764 _, _, _, default, optional, _decoded = values
3765 obj = self.base_klass(
3773 pprint(obj, big_blobs=True, with_decode_path=True)
3774 self.assertFalse(obj.expled)
3775 obj_encoded = obj.encode()
3776 obj_expled = obj(value, expl=tag_expl)
3777 self.assertTrue(obj_expled.expled)
3779 list(obj_expled.pps())
3780 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3781 obj_expled_encoded = obj_expled.encode()
3782 ctx_copied = deepcopy(ctx_dummy)
3783 obj_decoded, tail = obj_expled.decode(
3784 obj_expled_encoded + tail_junk,
3788 self.assertDictEqual(ctx_copied, ctx_dummy)
3790 list(obj_decoded.pps())
3791 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3792 self.assertEqual(tail, tail_junk)
3793 self.assertEqual(obj_decoded, obj_expled)
3794 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3795 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3796 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3797 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3798 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3800 obj_decoded.expl_llen,
3801 len(len_encode(len(obj_encoded))),
3803 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3804 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3807 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3809 self.assertEqual(obj_decoded.expl_offset, offset)
3812 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3813 base_klass = GeneralizedTime
3815 min_datetime = datetime(1900, 1, 1)
3816 max_datetime = datetime(9999, 12, 31)
3818 def test_go_vectors_invalid(self):
3830 b"-20100102030410Z",
3831 b"2010-0102030410Z",
3832 b"2010-0002030410Z",
3833 b"201001-02030410Z",
3834 b"20100102-030410Z",
3835 b"2010010203-0410Z",
3836 b"201001020304-10Z",
3837 # These ones are INVALID in *DER*, but accepted
3838 # by Go's encoding/asn1
3839 b"20100102030405+0607",
3840 b"20100102030405-0607",
3842 with self.assertRaises(DecodeError) as err:
3843 GeneralizedTime(data)
3846 def test_go_vectors_valid(self):
3848 GeneralizedTime(b"20100102030405Z").todatetime(),
3849 datetime(2010, 1, 2, 3, 4, 5, 0),
3854 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3855 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3857 binary(min_size=1, max_size=1),
3859 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3860 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3863 def test_junk(self, part0, part1, part2):
3864 junk = part0 + part1 + part2
3865 assume(not (set(junk) <= set(digits.encode("ascii"))))
3866 with self.assertRaises(DecodeError):
3867 GeneralizedTime().decode(
3868 GeneralizedTime.tag_default +
3869 len_encode(len(junk)) +
3875 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3876 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3878 binary(min_size=1, max_size=1),
3880 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3881 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3884 def test_junk_dm(self, part0, part1, part2):
3885 junk = part0 + part1 + part2
3886 assume(not (set(junk) <= set(digits.encode("ascii"))))
3887 with self.assertRaises(DecodeError):
3888 GeneralizedTime().decode(
3889 GeneralizedTime.tag_default +
3890 len_encode(len(junk)) +
3895 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3896 base_klass = UTCTime
3898 min_datetime = datetime(2000, 1, 1)
3899 max_datetime = datetime(2049, 12, 31)
3901 def test_go_vectors_invalid(self):
3927 # These ones are INVALID in *DER*, but accepted
3928 # by Go's encoding/asn1
3929 b"910506164540-0700",
3930 b"910506164540+0730",
3934 with self.assertRaises(DecodeError) as err:
3938 def test_go_vectors_valid(self):
3940 UTCTime(b"910506234540Z").todatetime(),
3941 datetime(1991, 5, 6, 23, 45, 40, 0),
3944 @given(integers(min_value=0, max_value=49))
3945 def test_pre50(self, year):
3947 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3951 @given(integers(min_value=50, max_value=99))
3952 def test_post50(self, year):
3954 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3960 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3961 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3963 binary(min_size=1, max_size=1),
3965 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3966 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3969 def test_junk(self, part0, part1, part2):
3970 junk = part0 + part1 + part2
3971 assume(not (set(junk) <= set(digits.encode("ascii"))))
3972 with self.assertRaises(DecodeError):
3974 UTCTime.tag_default +
3975 len_encode(len(junk)) +
3981 def any_values_strategy(draw, do_expl=False):
3982 value = draw(one_of(none(), binary()))
3985 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3986 optional = draw(one_of(none(), booleans()))
3988 draw(integers(min_value=0)),
3989 draw(integers(min_value=0)),
3990 draw(integers(min_value=0)),
3992 return (value, expl, optional, _decoded)
3995 class AnyInherited(Any):
3999 class TestAny(CommonMixin, TestCase):
4002 def test_invalid_value_type(self):
4003 with self.assertRaises(InvalidValueType) as err:
4008 def test_optional(self, optional):
4009 obj = Any(optional=optional)
4010 self.assertEqual(obj.optional, optional)
4013 def test_ready(self, value):
4015 self.assertFalse(obj.ready)
4018 pprint(obj, big_blobs=True, with_decode_path=True)
4019 with self.assertRaises(ObjNotReady) as err:
4023 self.assertTrue(obj.ready)
4026 pprint(obj, big_blobs=True, with_decode_path=True)
4029 def test_basic(self, value):
4030 integer_encoded = Integer(value).encode()
4032 Any(integer_encoded),
4033 Any(Integer(value)),
4034 Any(Any(Integer(value))),
4036 self.assertSequenceEqual(bytes(obj), integer_encoded)
4038 obj.decode(obj.encode())[0].vlen,
4039 len(integer_encoded),
4043 pprint(obj, big_blobs=True, with_decode_path=True)
4044 self.assertSequenceEqual(obj.encode(), integer_encoded)
4046 @given(binary(), binary())
4047 def test_comparison(self, value1, value2):
4048 for klass in (Any, AnyInherited):
4049 obj1 = klass(value1)
4050 obj2 = klass(value2)
4051 self.assertEqual(obj1 == obj2, value1 == value2)
4052 self.assertEqual(obj1 != obj2, value1 != value2)
4053 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4055 @given(data_strategy())
4056 def test_call(self, d):
4057 for klass in (Any, AnyInherited):
4063 ) = d.draw(any_values_strategy())
4064 obj_initial = klass(
4067 optional_initial or False,
4075 ) = d.draw(any_values_strategy(do_expl=True))
4076 obj = obj_initial(value, expl, optional)
4078 value_expected = None if value is None else value
4079 self.assertEqual(obj, value_expected)
4080 self.assertEqual(obj.expl_tag, expl or expl_initial)
4081 if obj.default is None:
4082 optional = optional_initial if optional is None else optional
4083 optional = False if optional is None else optional
4084 self.assertEqual(obj.optional, optional)
4086 def test_simultaneous_impl_expl(self):
4087 # override it, as Any does not have implicit tag
4090 def test_decoded(self):
4091 # override it, as Any does not have implicit tag
4094 @given(any_values_strategy())
4095 def test_copy(self, values):
4096 for klass in (Any, AnyInherited):
4097 obj = klass(*values)
4098 obj_copied = obj.copy()
4099 self.assert_copied_basic_fields(obj, obj_copied)
4100 self.assertEqual(obj._value, obj_copied._value)
4102 @given(binary().map(OctetString))
4103 def test_stripped(self, value):
4105 with self.assertRaises(NotEnoughData):
4106 obj.decode(obj.encode()[:-1])
4110 integers(min_value=1).map(tag_ctxc),
4112 def test_stripped_expl(self, value, tag_expl):
4113 obj = Any(value, expl=tag_expl)
4114 with self.assertRaises(NotEnoughData):
4115 obj.decode(obj.encode()[:-1])
4118 integers(min_value=31),
4119 integers(min_value=0),
4122 def test_bad_tag(self, tag, offset, decode_path):
4123 with self.assertRaises(DecodeError) as err:
4125 tag_encode(tag)[:-1],
4127 decode_path=decode_path,
4130 self.assertEqual(err.exception.offset, offset)
4131 self.assertEqual(err.exception.decode_path, decode_path)
4134 integers(min_value=128),
4135 integers(min_value=0),
4138 def test_bad_len(self, l, offset, decode_path):
4139 with self.assertRaises(DecodeError) as err:
4141 Any.tag_default + len_encode(l)[:-1],
4143 decode_path=decode_path,
4146 self.assertEqual(err.exception.offset, offset)
4147 self.assertEqual(err.exception.decode_path, decode_path)
4149 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4151 any_values_strategy(),
4152 integers().map(lambda x: Integer(x).encode()),
4153 integers(min_value=1).map(tag_ctxc),
4154 integers(min_value=0),
4157 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4158 for klass in (Any, AnyInherited):
4159 _, _, optional, _decoded = values
4160 obj = klass(value=value, optional=optional, _decoded=_decoded)
4163 pprint(obj, big_blobs=True, with_decode_path=True)
4164 self.assertFalse(obj.expled)
4165 obj_encoded = obj.encode()
4166 obj_expled = obj(value, expl=tag_expl)
4167 self.assertTrue(obj_expled.expled)
4169 list(obj_expled.pps())
4170 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4171 obj_expled_encoded = obj_expled.encode()
4172 ctx_copied = deepcopy(ctx_dummy)
4173 obj_decoded, tail = obj_expled.decode(
4174 obj_expled_encoded + tail_junk,
4178 self.assertDictEqual(ctx_copied, ctx_dummy)
4180 list(obj_decoded.pps())
4181 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4182 self.assertEqual(tail, tail_junk)
4183 self.assertEqual(obj_decoded, obj_expled)
4184 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4185 self.assertEqual(bytes(obj_decoded), bytes(obj))
4186 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4187 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4188 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4190 obj_decoded.expl_llen,
4191 len(len_encode(len(obj_encoded))),
4193 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4194 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4197 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4199 self.assertEqual(obj_decoded.expl_offset, offset)
4200 self.assertEqual(obj_decoded.tlen, 0)
4201 self.assertEqual(obj_decoded.llen, 0)
4202 self.assertEqual(obj_decoded.vlen, len(value))
4205 integers(min_value=1).map(tag_ctxc),
4206 integers(min_value=0, max_value=3),
4207 integers(min_value=0),
4211 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4212 chunk = Boolean(False, expl=expl).encode()
4214 OctetString.tag_default +
4216 b"".join([chunk] * chunks) +
4219 with self.assertRaises(LenIndefForm):
4223 decode_path=decode_path,
4225 obj, tail = Any().decode(
4228 decode_path=decode_path,
4229 ctx={"bered": True},
4231 self.assertSequenceEqual(tail, junk)
4232 self.assertEqual(obj.offset, offset)
4233 self.assertEqual(obj.tlvlen, len(encoded))
4234 self.assertTrue(obj.lenindef)
4235 self.assertFalse(obj.ber_encoded)
4236 self.assertTrue(obj.bered)
4238 self.assertTrue(obj.lenindef)
4239 self.assertFalse(obj.ber_encoded)
4240 self.assertTrue(obj.bered)
4243 pprint(obj, big_blobs=True, with_decode_path=True)
4244 with self.assertRaises(NotEnoughData) as err:
4248 decode_path=decode_path,
4249 ctx={"bered": True},
4251 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4252 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4254 class SeqOf(SequenceOf):
4255 schema = Boolean(expl=expl)
4257 class Seq(Sequence):
4259 ("type", ObjectIdentifier(defines=((("value",), {
4260 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4265 ("type", ObjectIdentifier("1.2.3")),
4266 ("value", Any(encoded)),
4268 seq_encoded = seq.encode()
4269 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4270 self.assertIsNotNone(seq_decoded["value"].defined)
4272 list(seq_decoded.pps())
4273 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4274 self.assertTrue(seq_decoded.bered)
4275 self.assertFalse(seq_decoded["type"].bered)
4276 self.assertTrue(seq_decoded["value"].bered)
4278 chunk = chunk[:-1] + b"\x01"
4279 chunks = b"".join([chunk] * (chunks + 1))
4280 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4282 ("type", ObjectIdentifier("1.2.3")),
4283 ("value", Any(encoded)),
4285 seq_encoded = seq.encode()
4286 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4287 self.assertIsNotNone(seq_decoded["value"].defined)
4289 list(seq_decoded.pps())
4290 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4291 self.assertTrue(seq_decoded.bered)
4292 self.assertFalse(seq_decoded["type"].bered)
4293 self.assertTrue(seq_decoded["value"].bered)
4297 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4299 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4300 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4302 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4303 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4305 min_size=len(names),
4306 max_size=len(names),
4309 (name, Integer(**tag_kwargs))
4310 for name, tag_kwargs in zip(names, tags)
4313 if value_required or draw(booleans()):
4314 value = draw(tuples(
4315 sampled_from([name for name, _ in schema]),
4316 integers().map(Integer),
4320 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4321 default = draw(one_of(
4323 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4325 optional = draw(one_of(none(), booleans()))
4327 draw(integers(min_value=0)),
4328 draw(integers(min_value=0)),
4329 draw(integers(min_value=0)),
4331 return (schema, value, expl, default, optional, _decoded)
4334 class ChoiceInherited(Choice):
4338 class TestChoice(CommonMixin, TestCase):
4340 schema = (("whatever", Boolean()),)
4343 def test_schema_required(self):
4344 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4347 def test_impl_forbidden(self):
4348 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4349 Choice(impl=b"whatever")
4351 def test_invalid_value_type(self):
4352 with self.assertRaises(InvalidValueType) as err:
4353 self.base_klass(123)
4355 with self.assertRaises(ObjUnknown) as err:
4356 self.base_klass(("whenever", Boolean(False)))
4358 with self.assertRaises(InvalidValueType) as err:
4359 self.base_klass(("whatever", Integer(123)))
4363 def test_optional(self, optional):
4364 obj = self.base_klass(
4365 default=self.base_klass(("whatever", Boolean(False))),
4368 self.assertTrue(obj.optional)
4371 def test_ready(self, value):
4372 obj = self.base_klass()
4373 self.assertFalse(obj.ready)
4376 pprint(obj, big_blobs=True, with_decode_path=True)
4377 self.assertIsNone(obj["whatever"])
4378 with self.assertRaises(ObjNotReady) as err:
4381 obj["whatever"] = Boolean()
4382 self.assertFalse(obj.ready)
4385 pprint(obj, big_blobs=True, with_decode_path=True)
4386 obj["whatever"] = Boolean(value)
4387 self.assertTrue(obj.ready)
4390 pprint(obj, big_blobs=True, with_decode_path=True)
4392 @given(booleans(), booleans())
4393 def test_comparison(self, value1, value2):
4394 class WahlInherited(self.base_klass):
4396 for klass in (self.base_klass, WahlInherited):
4397 obj1 = klass(("whatever", Boolean(value1)))
4398 obj2 = klass(("whatever", Boolean(value2)))
4399 self.assertEqual(obj1 == obj2, value1 == value2)
4400 self.assertEqual(obj1 != obj2, value1 != value2)
4401 self.assertEqual(obj1 == obj2._value, value1 == value2)
4402 self.assertFalse(obj1 == obj2._value[1])
4404 @given(data_strategy())
4405 def test_call(self, d):
4406 for klass in (Choice, ChoiceInherited):
4414 ) = d.draw(choice_values_strategy())
4417 schema = schema_initial
4419 value=value_initial,
4421 default=default_initial,
4422 optional=optional_initial or False,
4423 _decoded=_decoded_initial,
4432 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4433 obj = obj_initial(value, expl, default, optional)
4435 value_expected = default if value is None else value
4437 default_initial if value_expected is None
4440 self.assertEqual(obj.choice, value_expected[0])
4441 self.assertEqual(obj.value, int(value_expected[1]))
4442 self.assertEqual(obj.expl_tag, expl or expl_initial)
4443 default_expect = default_initial if default is None else default
4444 if default_expect is not None:
4445 self.assertEqual(obj.default.choice, default_expect[0])
4446 self.assertEqual(obj.default.value, int(default_expect[1]))
4447 if obj.default is None:
4448 optional = optional_initial if optional is None else optional
4449 optional = False if optional is None else optional
4452 self.assertEqual(obj.optional, optional)
4453 self.assertEqual(obj.specs, obj_initial.specs)
4455 def test_simultaneous_impl_expl(self):
4456 # override it, as Any does not have implicit tag
4459 def test_decoded(self):
4460 # override it, as Any does not have implicit tag
4463 @given(choice_values_strategy())
4464 def test_copy(self, values):
4465 _schema, value, expl, default, optional, _decoded = values
4467 class Wahl(self.base_klass):
4473 optional=optional or False,
4476 obj_copied = obj.copy()
4477 self.assertIsNone(obj.tag)
4478 self.assertIsNone(obj_copied.tag)
4479 # hack for assert_copied_basic_fields
4480 obj.tag = "whatever"
4481 obj_copied.tag = "whatever"
4482 self.assert_copied_basic_fields(obj, obj_copied)
4483 self.assertEqual(obj._value, obj_copied._value)
4484 self.assertEqual(obj.specs, obj_copied.specs)
4487 def test_stripped(self, value):
4488 obj = self.base_klass(("whatever", Boolean(value)))
4489 with self.assertRaises(NotEnoughData):
4490 obj.decode(obj.encode()[:-1])
4494 integers(min_value=1).map(tag_ctxc),
4496 def test_stripped_expl(self, value, tag_expl):
4497 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4498 with self.assertRaises(NotEnoughData):
4499 obj.decode(obj.encode()[:-1])
4501 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4502 @given(data_strategy())
4503 def test_symmetric(self, d):
4504 _schema, value, _, default, optional, _decoded = d.draw(
4505 choice_values_strategy(value_required=True)
4507 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4508 offset = d.draw(integers(min_value=0))
4509 tail_junk = d.draw(binary(max_size=5))
4511 class Wahl(self.base_klass):
4521 pprint(obj, big_blobs=True, with_decode_path=True)
4522 self.assertFalse(obj.expled)
4523 obj_encoded = obj.encode()
4524 obj_expled = obj(value, expl=tag_expl)
4525 self.assertTrue(obj_expled.expled)
4527 list(obj_expled.pps())
4528 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4529 obj_expled_encoded = obj_expled.encode()
4530 ctx_copied = deepcopy(ctx_dummy)
4531 obj_decoded, tail = obj_expled.decode(
4532 obj_expled_encoded + tail_junk,
4536 self.assertDictEqual(ctx_copied, ctx_dummy)
4538 list(obj_decoded.pps())
4539 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4540 self.assertEqual(tail, tail_junk)
4541 self.assertEqual(obj_decoded, obj_expled)
4542 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4543 self.assertEqual(obj_decoded.value, obj_expled.value)
4544 self.assertEqual(obj_decoded.choice, obj.choice)
4545 self.assertEqual(obj_decoded.value, obj.value)
4546 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4547 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4548 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4550 obj_decoded.expl_llen,
4551 len(len_encode(len(obj_encoded))),
4553 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4554 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4557 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4559 self.assertEqual(obj_decoded.expl_offset, offset)
4560 self.assertSequenceEqual(
4562 obj_decoded.value.fulloffset - offset:
4563 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4569 def test_set_get(self, value):
4572 ("erste", Boolean()),
4573 ("zweite", Integer()),
4576 with self.assertRaises(ObjUnknown) as err:
4577 obj["whatever"] = "whenever"
4578 with self.assertRaises(InvalidValueType) as err:
4579 obj["zweite"] = Boolean(False)
4580 obj["zweite"] = Integer(value)
4582 with self.assertRaises(ObjUnknown) as err:
4585 self.assertIsNone(obj["erste"])
4586 self.assertEqual(obj["zweite"], Integer(value))
4588 def test_tag_mismatch(self):
4591 ("erste", Boolean()),
4593 int_encoded = Integer(123).encode()
4594 bool_encoded = Boolean(False).encode()
4596 obj.decode(bool_encoded)
4597 with self.assertRaises(TagMismatch):
4598 obj.decode(int_encoded)
4600 def test_tag_mismatch_underlying(self):
4601 class SeqOfBoolean(SequenceOf):
4604 class SeqOfInteger(SequenceOf):
4609 ("erste", SeqOfBoolean()),
4612 int_encoded = SeqOfInteger((Integer(123),)).encode()
4613 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4615 obj.decode(bool_encoded)
4616 with self.assertRaises(TagMismatch) as err:
4617 obj.decode(int_encoded)
4618 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4622 def seq_values_strategy(draw, seq_klass, do_expl=False):
4624 if draw(booleans()):
4627 k: v for k, v in draw(dictionaries(
4630 booleans().map(Boolean),
4631 integers().map(Integer),
4636 if draw(booleans()):
4637 schema = list(draw(dictionaries(
4640 booleans().map(Boolean),
4641 integers().map(Integer),
4647 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4649 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4651 if draw(booleans()):
4652 default = seq_klass()
4654 k: v for k, v in draw(dictionaries(
4657 booleans().map(Boolean),
4658 integers().map(Integer),
4662 optional = draw(one_of(none(), booleans()))
4664 draw(integers(min_value=0)),
4665 draw(integers(min_value=0)),
4666 draw(integers(min_value=0)),
4668 return (value, schema, impl, expl, default, optional, _decoded)
4672 def sequence_strategy(draw, seq_klass):
4673 inputs = draw(lists(
4675 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4676 tuples(just(Integer), integers(), one_of(none(), integers())),
4681 integers(min_value=1),
4682 min_size=len(inputs),
4683 max_size=len(inputs),
4686 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4687 for tag, expled in zip(tags, draw(lists(
4689 min_size=len(inputs),
4690 max_size=len(inputs),
4694 for i, optional in enumerate(draw(lists(
4695 sampled_from(("required", "optional", "empty")),
4696 min_size=len(inputs),
4697 max_size=len(inputs),
4699 if optional in ("optional", "empty"):
4700 inits[i]["optional"] = True
4701 if optional == "empty":
4703 empties = set(empties)
4704 names = list(draw(sets(
4706 min_size=len(inputs),
4707 max_size=len(inputs),
4710 for i, (klass, value, default) in enumerate(inputs):
4711 schema.append((names[i], klass(default=default, **inits[i])))
4712 seq_name = draw(text_letters())
4713 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4716 for i, (klass, value, default) in enumerate(inputs):
4723 "default_value": None if spec.default is None else default,
4727 expect["optional"] = True
4729 expect["presented"] = True
4730 expect["value"] = value
4732 expect["optional"] = True
4733 if default is not None and default == value:
4734 expect["presented"] = False
4735 seq[name] = klass(value)
4736 expects.append(expect)
4741 def sequences_strategy(draw, seq_klass):
4742 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4744 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4745 for tag, expled in zip(tags, draw(lists(
4752 i for i, is_default in enumerate(draw(lists(
4758 names = list(draw(sets(
4763 seq_expectses = draw(lists(
4764 sequence_strategy(seq_klass=seq_klass),
4768 seqs = [seq for seq, _ in seq_expectses]
4770 for i, (name, seq) in enumerate(zip(names, seqs)):
4773 seq(default=(seq if i in defaulted else None), **inits[i]),
4775 seq_name = draw(text_letters())
4776 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4779 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4782 "expects": expects_inner,
4785 seq_outer[name] = seq_inner
4786 if seq_outer.specs[name].default is None:
4787 expect["presented"] = True
4788 expect_outers.append(expect)
4789 return seq_outer, expect_outers
4792 class SeqMixing(object):
4793 def test_invalid_value_type(self):
4794 with self.assertRaises(InvalidValueType) as err:
4795 self.base_klass(123)
4798 def test_invalid_value_type_set(self):
4799 class Seq(self.base_klass):
4800 schema = (("whatever", Boolean()),)
4802 with self.assertRaises(InvalidValueType) as err:
4803 seq["whatever"] = Integer(123)
4807 def test_optional(self, optional):
4808 obj = self.base_klass(default=self.base_klass(), optional=optional)
4809 self.assertTrue(obj.optional)
4811 @given(data_strategy())
4812 def test_ready(self, d):
4814 str(i): v for i, v in enumerate(d.draw(lists(
4821 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4828 for name in d.draw(permutations(
4829 list(ready.keys()) + list(non_ready.keys()),
4831 schema_input.append((name, Boolean()))
4833 class Seq(self.base_klass):
4834 schema = tuple(schema_input)
4836 for name in ready.keys():
4838 seq[name] = Boolean()
4839 self.assertFalse(seq.ready)
4842 pprint(seq, big_blobs=True, with_decode_path=True)
4843 for name, value in ready.items():
4844 seq[name] = Boolean(value)
4845 self.assertFalse(seq.ready)
4848 pprint(seq, big_blobs=True, with_decode_path=True)
4849 with self.assertRaises(ObjNotReady) as err:
4852 for name, value in non_ready.items():
4853 seq[name] = Boolean(value)
4854 self.assertTrue(seq.ready)
4857 pprint(seq, big_blobs=True, with_decode_path=True)
4859 @given(data_strategy())
4860 def test_call(self, d):
4861 class SeqInherited(self.base_klass):
4863 for klass in (self.base_klass, SeqInherited):
4872 ) = d.draw(seq_values_strategy(seq_klass=klass))
4873 obj_initial = klass(
4879 optional_initial or False,
4890 ) = d.draw(seq_values_strategy(
4892 do_expl=impl_initial is None,
4894 obj = obj_initial(value, impl, expl, default, optional)
4895 value_expected = default if value is None else value
4897 default_initial if value_expected is None
4900 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4901 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4902 self.assertEqual(obj.expl_tag, expl or expl_initial)
4904 {} if obj.default is None else obj.default._value,
4905 getattr(default_initial if default is None else default, "_value", {}),
4907 if obj.default is None:
4908 optional = optional_initial if optional is None else optional
4909 optional = False if optional is None else optional
4912 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4913 self.assertEqual(obj.optional, optional)
4915 @given(data_strategy())
4916 def test_copy(self, d):
4917 class SeqInherited(self.base_klass):
4919 for klass in (self.base_klass, SeqInherited):
4920 values = d.draw(seq_values_strategy(seq_klass=klass))
4921 obj = klass(*values)
4922 obj_copied = obj.copy()
4923 self.assert_copied_basic_fields(obj, obj_copied)
4924 self.assertEqual(obj.specs, obj_copied.specs)
4925 self.assertEqual(obj._value, obj_copied._value)
4927 @given(data_strategy())
4928 def test_stripped(self, d):
4929 value = d.draw(integers())
4930 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4932 class Seq(self.base_klass):
4934 schema = (("whatever", Integer()),)
4936 seq["whatever"] = Integer(value)
4937 with self.assertRaises(NotEnoughData):
4938 seq.decode(seq.encode()[:-1])
4940 @given(data_strategy())
4941 def test_stripped_expl(self, d):
4942 value = d.draw(integers())
4943 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4945 class Seq(self.base_klass):
4947 schema = (("whatever", Integer()),)
4949 seq["whatever"] = Integer(value)
4950 with self.assertRaises(NotEnoughData):
4951 seq.decode(seq.encode()[:-1])
4953 @given(binary(min_size=2))
4954 def test_non_tag_mismatch_raised(self, junk):
4956 _, _, len_encoded = tag_strip(memoryview(junk))
4957 len_decode(len_encoded)
4963 class Seq(self.base_klass):
4965 ("whatever", Integer()),
4967 ("whenever", Integer()),
4970 seq["whatever"] = Integer(123)
4971 seq["junk"] = Any(junk)
4972 seq["whenever"] = Integer(123)
4973 with self.assertRaises(DecodeError):
4974 seq.decode(seq.encode())
4977 integers(min_value=31),
4978 integers(min_value=0),
4981 def test_bad_tag(self, tag, offset, decode_path):
4982 with self.assertRaises(DecodeError) as err:
4983 self.base_klass().decode(
4984 tag_encode(tag)[:-1],
4986 decode_path=decode_path,
4989 self.assertEqual(err.exception.offset, offset)
4990 self.assertEqual(err.exception.decode_path, decode_path)
4993 integers(min_value=128),
4994 integers(min_value=0),
4997 def test_bad_len(self, l, offset, decode_path):
4998 with self.assertRaises(DecodeError) as err:
4999 self.base_klass().decode(
5000 self.base_klass.tag_default + len_encode(l)[:-1],
5002 decode_path=decode_path,
5005 self.assertEqual(err.exception.offset, offset)
5006 self.assertEqual(err.exception.decode_path, decode_path)
5008 def _assert_expects(self, seq, expects):
5009 for expect in expects:
5011 seq.specs[expect["name"]].optional,
5014 if expect["default_value"] is not None:
5016 seq.specs[expect["name"]].default,
5017 expect["default_value"],
5019 if expect["presented"]:
5020 self.assertIn(expect["name"], seq)
5021 self.assertEqual(seq[expect["name"]], expect["value"])
5023 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5024 @given(data_strategy())
5025 def test_symmetric(self, d):
5026 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5027 tail_junk = d.draw(binary(max_size=5))
5028 self.assertTrue(seq.ready)
5029 self.assertFalse(seq.decoded)
5030 self._assert_expects(seq, expects)
5033 pprint(seq, big_blobs=True, with_decode_path=True)
5034 self.assertTrue(seq.ready)
5035 seq_encoded = seq.encode()
5036 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5037 self.assertFalse(seq_decoded.lenindef)
5038 self.assertFalse(seq_decoded.ber_encoded)
5039 self.assertFalse(seq_decoded.bered)
5041 t, _, lv = tag_strip(seq_encoded)
5042 _, _, v = len_decode(lv)
5043 seq_encoded_lenindef = t + LENINDEF + v + EOC
5044 ctx_copied = deepcopy(ctx_dummy)
5045 ctx_copied["bered"] = True
5046 seq_decoded_lenindef, tail_lenindef = seq.decode(
5047 seq_encoded_lenindef + tail_junk,
5050 del ctx_copied["bered"]
5051 self.assertDictEqual(ctx_copied, ctx_dummy)
5052 self.assertTrue(seq_decoded_lenindef.lenindef)
5053 self.assertTrue(seq_decoded_lenindef.bered)
5054 seq_decoded_lenindef = seq_decoded_lenindef.copy()
5055 self.assertTrue(seq_decoded_lenindef.lenindef)
5056 self.assertTrue(seq_decoded_lenindef.bered)
5057 with self.assertRaises(DecodeError):
5058 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5059 with self.assertRaises(DecodeError):
5060 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5061 repr(seq_decoded_lenindef)
5062 list(seq_decoded_lenindef.pps())
5063 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5064 self.assertTrue(seq_decoded_lenindef.ready)
5066 for decoded, decoded_tail, encoded in (
5067 (seq_decoded, tail, seq_encoded),
5068 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5070 self.assertEqual(decoded_tail, tail_junk)
5071 self._assert_expects(decoded, expects)
5072 self.assertEqual(seq, decoded)
5073 self.assertEqual(decoded.encode(), seq_encoded)
5074 self.assertEqual(decoded.tlvlen, len(encoded))
5075 for expect in expects:
5076 if not expect["presented"]:
5077 self.assertNotIn(expect["name"], decoded)
5079 self.assertIn(expect["name"], decoded)
5080 obj = decoded[expect["name"]]
5081 self.assertTrue(obj.decoded)
5082 offset = obj.expl_offset if obj.expled else obj.offset
5083 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5084 self.assertSequenceEqual(
5085 seq_encoded[offset:offset + tlvlen],
5089 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5090 @given(data_strategy())
5091 def test_symmetric_with_seq(self, d):
5092 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5093 self.assertTrue(seq.ready)
5094 seq_encoded = seq.encode()
5095 seq_decoded, tail = seq.decode(seq_encoded)
5096 self.assertEqual(tail, b"")
5097 self.assertTrue(seq.ready)
5098 self.assertEqual(seq, seq_decoded)
5099 self.assertEqual(seq_decoded.encode(), seq_encoded)
5100 for expect_outer in expect_outers:
5101 if not expect_outer["presented"]:
5102 self.assertNotIn(expect_outer["name"], seq_decoded)
5104 self.assertIn(expect_outer["name"], seq_decoded)
5105 obj = seq_decoded[expect_outer["name"]]
5106 self.assertTrue(obj.decoded)
5107 offset = obj.expl_offset if obj.expled else obj.offset
5108 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5109 self.assertSequenceEqual(
5110 seq_encoded[offset:offset + tlvlen],
5113 self._assert_expects(obj, expect_outer["expects"])
5115 @given(data_strategy())
5116 def test_default_disappears(self, d):
5117 _schema = list(d.draw(dictionaries(
5119 sets(integers(), min_size=2, max_size=2),
5123 class Seq(self.base_klass):
5125 (n, Integer(default=d))
5126 for n, (_, d) in _schema
5129 for name, (value, _) in _schema:
5130 seq[name] = Integer(value)
5131 self.assertEqual(len(seq._value), len(_schema))
5132 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5133 self.assertGreater(len(seq.encode()), len(empty_seq))
5134 for name, (_, default) in _schema:
5135 seq[name] = Integer(default)
5136 self.assertEqual(len(seq._value), 0)
5137 self.assertSequenceEqual(seq.encode(), empty_seq)
5139 @given(data_strategy())
5140 def test_encoded_default_not_accepted(self, d):
5141 _schema = list(d.draw(dictionaries(
5146 tags = [tag_encode(tag) for tag in d.draw(sets(
5147 integers(min_value=0),
5148 min_size=len(_schema),
5149 max_size=len(_schema),
5152 class SeqWithoutDefault(self.base_klass):
5154 (n, Integer(impl=t))
5155 for (n, _), t in zip(_schema, tags)
5157 seq_without_default = SeqWithoutDefault()
5158 for name, value in _schema:
5159 seq_without_default[name] = Integer(value)
5160 seq_encoded = seq_without_default.encode()
5162 class SeqWithDefault(self.base_klass):
5164 (n, Integer(default=v, impl=t))
5165 for (n, v), t in zip(_schema, tags)
5167 seq_with_default = SeqWithDefault()
5168 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5169 seq_with_default.decode(seq_encoded)
5170 for ctx in ({"bered": True}, {"allow_default_values": True}):
5171 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5172 self.assertTrue(seq_decoded.ber_encoded)
5173 self.assertTrue(seq_decoded.bered)
5174 seq_decoded = seq_decoded.copy()
5175 self.assertTrue(seq_decoded.ber_encoded)
5176 self.assertTrue(seq_decoded.bered)
5177 for name, value in _schema:
5178 self.assertEqual(seq_decoded[name], seq_with_default[name])
5179 self.assertEqual(seq_decoded[name], value)
5181 @given(data_strategy())
5182 def test_missing_from_spec(self, d):
5183 names = list(d.draw(sets(text_letters(), min_size=2)))
5184 tags = [tag_encode(tag) for tag in d.draw(sets(
5185 integers(min_value=0),
5186 min_size=len(names),
5187 max_size=len(names),
5189 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5191 class SeqFull(self.base_klass):
5192 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5193 seq_full = SeqFull()
5194 for i, name in enumerate(names):
5195 seq_full[name] = Integer(i)
5196 seq_encoded = seq_full.encode()
5197 altered = names_tags[:-2] + names_tags[-1:]
5199 class SeqMissing(self.base_klass):
5200 schema = [(n, Integer(impl=t)) for n, t in altered]
5201 seq_missing = SeqMissing()
5202 with self.assertRaises(TagMismatch):
5203 seq_missing.decode(seq_encoded)
5205 @given(data_strategy())
5206 def test_bered(self, d):
5207 class Seq(self.base_klass):
5208 schema = (("underlying", Boolean()),)
5209 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5210 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5211 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5212 self.assertFalse(decoded.ber_encoded)
5213 self.assertFalse(decoded.lenindef)
5214 self.assertTrue(decoded.bered)
5215 decoded = decoded.copy()
5216 self.assertFalse(decoded.ber_encoded)
5217 self.assertFalse(decoded.lenindef)
5218 self.assertTrue(decoded.bered)
5220 class Seq(self.base_klass):
5221 schema = (("underlying", OctetString()),)
5223 tag_encode(form=TagFormConstructed, num=4) +
5225 OctetString(b"whatever").encode() +
5228 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5229 with self.assertRaises(DecodeError):
5230 Seq().decode(encoded)
5231 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5232 self.assertFalse(decoded.ber_encoded)
5233 self.assertFalse(decoded.lenindef)
5234 self.assertTrue(decoded.bered)
5235 decoded = decoded.copy()
5236 self.assertFalse(decoded.ber_encoded)
5237 self.assertFalse(decoded.lenindef)
5238 self.assertTrue(decoded.bered)
5241 class TestSequence(SeqMixing, CommonMixin, TestCase):
5242 base_klass = Sequence
5248 def test_remaining(self, value, junk):
5249 class Seq(Sequence):
5251 ("whatever", Integer()),
5253 int_encoded = Integer(value).encode()
5255 Sequence.tag_default,
5256 len_encode(len(int_encoded + junk)),
5259 with assertRaisesRegex(self, DecodeError, "remaining"):
5260 Seq().decode(junked)
5262 @given(sets(text_letters(), min_size=2))
5263 def test_obj_unknown(self, names):
5264 missing = names.pop()
5266 class Seq(Sequence):
5267 schema = [(n, Boolean()) for n in names]
5269 with self.assertRaises(ObjUnknown) as err:
5272 with self.assertRaises(ObjUnknown) as err:
5273 seq[missing] = Boolean()
5276 def test_x690_vector(self):
5277 class Seq(Sequence):
5279 ("name", IA5String()),
5282 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5283 self.assertEqual(seq["name"], "Smith")
5284 self.assertEqual(seq["ok"], True)
5287 class TestSet(SeqMixing, CommonMixin, TestCase):
5290 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5291 @given(data_strategy())
5292 def test_sorted(self, d):
5294 tag_encode(tag) for tag in
5295 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5299 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5301 for name, _ in Seq.schema:
5302 seq[name] = OctetString(b"")
5303 seq_encoded = seq.encode()
5304 seq_decoded, _ = seq.decode(seq_encoded)
5305 self.assertSequenceEqual(
5306 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5307 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5310 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5311 @given(data_strategy())
5312 def test_unsorted(self, d):
5314 tag_encode(tag) for tag in
5315 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5317 tags = d.draw(permutations(tags))
5318 assume(tags != sorted(tags))
5319 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5320 seq_encoded = b"".join((
5322 len_encode(len(encoded)),
5327 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5329 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5330 seq.decode(seq_encoded)
5331 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5332 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5333 self.assertTrue(seq_decoded.ber_encoded)
5334 self.assertTrue(seq_decoded.bered)
5335 seq_decoded = seq_decoded.copy()
5336 self.assertTrue(seq_decoded.ber_encoded)
5337 self.assertTrue(seq_decoded.bered)
5338 self.assertSequenceEqual(
5339 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5345 def seqof_values_strategy(draw, schema=None, do_expl=False):
5347 schema = draw(sampled_from((Boolean(), Integer())))
5348 bound_min, bound_max = sorted(draw(sets(
5349 integers(min_value=0, max_value=10),
5353 if isinstance(schema, Boolean):
5354 values_generator = booleans().map(Boolean)
5355 elif isinstance(schema, Integer):
5356 values_generator = integers().map(Integer)
5357 values_generator = lists(
5362 values = draw(one_of(none(), values_generator))
5366 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5368 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5369 default = draw(one_of(none(), values_generator))
5370 optional = draw(one_of(none(), booleans()))
5372 draw(integers(min_value=0)),
5373 draw(integers(min_value=0)),
5374 draw(integers(min_value=0)),
5379 (bound_min, bound_max),
5388 class SeqOfMixing(object):
5389 def test_invalid_value_type(self):
5390 with self.assertRaises(InvalidValueType) as err:
5391 self.base_klass(123)
5394 def test_invalid_values_type(self):
5395 class SeqOf(self.base_klass):
5397 with self.assertRaises(InvalidValueType) as err:
5398 SeqOf([Integer(123), Boolean(False), Integer(234)])
5401 def test_schema_required(self):
5402 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5403 self.base_klass.__mro__[1]()
5405 @given(booleans(), booleans(), binary(), binary())
5406 def test_comparison(self, value1, value2, tag1, tag2):
5407 class SeqOf(self.base_klass):
5409 obj1 = SeqOf([Boolean(value1)])
5410 obj2 = SeqOf([Boolean(value2)])
5411 self.assertEqual(obj1 == obj2, value1 == value2)
5412 self.assertEqual(obj1 != obj2, value1 != value2)
5413 self.assertEqual(obj1 == list(obj2), value1 == value2)
5414 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5415 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5416 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5417 self.assertEqual(obj1 == obj2, tag1 == tag2)
5418 self.assertEqual(obj1 != obj2, tag1 != tag2)
5420 @given(lists(booleans()))
5421 def test_iter(self, values):
5422 class SeqOf(self.base_klass):
5424 obj = SeqOf([Boolean(value) for value in values])
5425 self.assertEqual(len(obj), len(values))
5426 for i, value in enumerate(obj):
5427 self.assertEqual(value, values[i])
5429 @given(data_strategy())
5430 def test_ready(self, d):
5431 ready = [Integer(v) for v in d.draw(lists(
5438 range(d.draw(integers(min_value=1, max_value=5)))
5441 class SeqOf(self.base_klass):
5443 values = d.draw(permutations(ready + non_ready))
5445 for value in values:
5447 self.assertFalse(seqof.ready)
5450 pprint(seqof, big_blobs=True, with_decode_path=True)
5451 with self.assertRaises(ObjNotReady) as err:
5454 for i, value in enumerate(values):
5455 self.assertEqual(seqof[i], value)
5456 if not seqof[i].ready:
5457 seqof[i] = Integer(i)
5458 self.assertTrue(seqof.ready)
5461 pprint(seqof, big_blobs=True, with_decode_path=True)
5463 def test_spec_mismatch(self):
5464 class SeqOf(self.base_klass):
5467 seqof.append(Integer(123))
5468 with self.assertRaises(ValueError):
5469 seqof.append(Boolean(False))
5470 with self.assertRaises(ValueError):
5471 seqof[0] = Boolean(False)
5473 @given(data_strategy())
5474 def test_bounds_satisfied(self, d):
5475 class SeqOf(self.base_klass):
5477 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5478 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5479 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5480 SeqOf(value=value, bounds=(bound_min, bound_max))
5482 @given(data_strategy())
5483 def test_bounds_unsatisfied(self, d):
5484 class SeqOf(self.base_klass):
5486 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5487 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5488 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5489 with self.assertRaises(BoundsError) as err:
5490 SeqOf(value=value, bounds=(bound_min, bound_max))
5492 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5493 SeqOf(bounds=(bound_min, bound_max)).decode(
5494 SeqOf(value).encode()
5497 value = [Boolean(True)] * d.draw(integers(
5498 min_value=bound_max + 1,
5499 max_value=bound_max + 10,
5501 with self.assertRaises(BoundsError) as err:
5502 SeqOf(value=value, bounds=(bound_min, bound_max))
5504 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5505 SeqOf(bounds=(bound_min, bound_max)).decode(
5506 SeqOf(value).encode()
5510 @given(integers(min_value=1, max_value=10))
5511 def test_out_of_bounds(self, bound_max):
5512 class SeqOf(self.base_klass):
5514 bounds = (0, bound_max)
5516 for _ in range(bound_max):
5517 seqof.append(Integer(123))
5518 with self.assertRaises(BoundsError):
5519 seqof.append(Integer(123))
5521 @given(data_strategy())
5522 def test_call(self, d):
5532 ) = d.draw(seqof_values_strategy())
5534 class SeqOf(self.base_klass):
5535 schema = schema_initial
5536 obj_initial = SeqOf(
5537 value=value_initial,
5538 bounds=bounds_initial,
5541 default=default_initial,
5542 optional=optional_initial or False,
5543 _decoded=_decoded_initial,
5554 ) = d.draw(seqof_values_strategy(
5555 schema=schema_initial,
5556 do_expl=impl_initial is None,
5558 if (default is None) and (obj_initial.default is not None):
5561 (bounds is None) and
5562 (value is not None) and
5563 (bounds_initial is not None) and
5564 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5568 (bounds is None) and
5569 (default is not None) and
5570 (bounds_initial is not None) and
5571 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5583 value_expected = default if value is None else value
5585 default_initial if value_expected is None
5588 value_expected = () if value_expected is None else value_expected
5589 self.assertEqual(obj, value_expected)
5590 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5591 self.assertEqual(obj.expl_tag, expl or expl_initial)
5594 default_initial if default is None else default,
5596 if obj.default is None:
5597 optional = optional_initial if optional is None else optional
5598 optional = False if optional is None else optional
5601 self.assertEqual(obj.optional, optional)
5603 (obj._bound_min, obj._bound_max),
5604 bounds or bounds_initial or (0, float("+inf")),
5607 @given(seqof_values_strategy())
5608 def test_copy(self, values):
5609 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5611 class SeqOf(self.base_klass):
5619 optional=optional or False,
5622 obj_copied = obj.copy()
5623 self.assert_copied_basic_fields(obj, obj_copied)
5624 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5625 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5626 self.assertEqual(obj._value, obj_copied._value)
5630 integers(min_value=1).map(tag_encode),
5632 def test_stripped(self, values, tag_impl):
5633 class SeqOf(self.base_klass):
5634 schema = OctetString()
5635 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5636 with self.assertRaises(NotEnoughData):
5637 obj.decode(obj.encode()[:-1])
5641 integers(min_value=1).map(tag_ctxc),
5643 def test_stripped_expl(self, values, tag_expl):
5644 class SeqOf(self.base_klass):
5645 schema = OctetString()
5646 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5647 with self.assertRaises(NotEnoughData):
5648 obj.decode(obj.encode()[:-1])
5651 integers(min_value=31),
5652 integers(min_value=0),
5655 def test_bad_tag(self, tag, offset, decode_path):
5656 with self.assertRaises(DecodeError) as err:
5657 self.base_klass().decode(
5658 tag_encode(tag)[:-1],
5660 decode_path=decode_path,
5663 self.assertEqual(err.exception.offset, offset)
5664 self.assertEqual(err.exception.decode_path, decode_path)
5667 integers(min_value=128),
5668 integers(min_value=0),
5671 def test_bad_len(self, l, offset, decode_path):
5672 with self.assertRaises(DecodeError) as err:
5673 self.base_klass().decode(
5674 self.base_klass.tag_default + len_encode(l)[:-1],
5676 decode_path=decode_path,
5679 self.assertEqual(err.exception.offset, offset)
5680 self.assertEqual(err.exception.decode_path, decode_path)
5682 @given(binary(min_size=1))
5683 def test_tag_mismatch(self, impl):
5684 assume(impl != self.base_klass.tag_default)
5685 with self.assertRaises(TagMismatch):
5686 self.base_klass(impl=impl).decode(self.base_klass().encode())
5688 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5690 seqof_values_strategy(schema=Integer()),
5691 lists(integers().map(Integer)),
5692 integers(min_value=1).map(tag_ctxc),
5693 integers(min_value=0),
5696 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5697 _, _, _, _, _, default, optional, _decoded = values
5699 class SeqOf(self.base_klass):
5709 pprint(obj, big_blobs=True, with_decode_path=True)
5710 self.assertFalse(obj.expled)
5711 obj_encoded = obj.encode()
5712 obj_expled = obj(value, expl=tag_expl)
5713 self.assertTrue(obj_expled.expled)
5715 list(obj_expled.pps())
5716 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5717 obj_expled_encoded = obj_expled.encode()
5718 ctx_copied = deepcopy(ctx_dummy)
5719 obj_decoded, tail = obj_expled.decode(
5720 obj_expled_encoded + tail_junk,
5724 self.assertDictEqual(ctx_copied, ctx_dummy)
5726 list(obj_decoded.pps())
5727 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5728 self.assertEqual(tail, tail_junk)
5729 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5730 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5731 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5732 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5734 obj_decoded.expl_llen,
5735 len(len_encode(len(obj_encoded))),
5737 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5738 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5741 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5743 self.assertEqual(obj_decoded.expl_offset, offset)
5744 for obj_inner in obj_decoded:
5745 self.assertIn(obj_inner, obj_decoded)
5746 self.assertSequenceEqual(
5749 obj_inner.offset - offset:
5750 obj_inner.offset + obj_inner.tlvlen - offset
5754 t, _, lv = tag_strip(obj_encoded)
5755 _, _, v = len_decode(lv)
5756 obj_encoded_lenindef = t + LENINDEF + v + EOC
5757 obj_decoded_lenindef, tail_lenindef = obj.decode(
5758 obj_encoded_lenindef + tail_junk,
5759 ctx={"bered": True},
5761 self.assertTrue(obj_decoded_lenindef.lenindef)
5762 self.assertTrue(obj_decoded_lenindef.bered)
5763 obj_decoded_lenindef = obj_decoded_lenindef.copy()
5764 self.assertTrue(obj_decoded_lenindef.lenindef)
5765 self.assertTrue(obj_decoded_lenindef.bered)
5766 repr(obj_decoded_lenindef)
5767 list(obj_decoded_lenindef.pps())
5768 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5769 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5770 with self.assertRaises(DecodeError):
5771 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5772 with self.assertRaises(DecodeError):
5773 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5775 @given(data_strategy())
5776 def test_bered(self, d):
5777 class SeqOf(self.base_klass):
5779 encoded = Boolean(False).encode()
5780 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5781 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5782 with self.assertRaises(DecodeError):
5783 SeqOf().decode(encoded)
5784 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5785 self.assertFalse(decoded.ber_encoded)
5786 self.assertFalse(decoded.lenindef)
5787 self.assertTrue(decoded.bered)
5788 decoded = decoded.copy()
5789 self.assertFalse(decoded.ber_encoded)
5790 self.assertFalse(decoded.lenindef)
5791 self.assertTrue(decoded.bered)
5793 class SeqOf(self.base_klass):
5794 schema = OctetString()
5795 encoded = OctetString(b"whatever").encode()
5797 tag_encode(form=TagFormConstructed, num=4) +
5799 OctetString(b"whatever").encode() +
5802 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5803 with self.assertRaises(DecodeError):
5804 SeqOf().decode(encoded)
5805 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5806 self.assertFalse(decoded.ber_encoded)
5807 self.assertFalse(decoded.lenindef)
5808 self.assertTrue(decoded.bered)
5809 decoded = decoded.copy()
5810 self.assertFalse(decoded.ber_encoded)
5811 self.assertFalse(decoded.lenindef)
5812 self.assertTrue(decoded.bered)
5815 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5816 class SeqOf(SequenceOf):
5820 def _test_symmetric_compare_objs(self, obj1, obj2):
5821 self.assertEqual(obj1, obj2)
5822 self.assertSequenceEqual(list(obj1), list(obj2))
5825 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5830 def _test_symmetric_compare_objs(self, obj1, obj2):
5831 self.assertSetEqual(
5832 set(int(v) for v in obj1),
5833 set(int(v) for v in obj2),
5836 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5837 @given(data_strategy())
5838 def test_sorted(self, d):
5839 values = [OctetString(v) for v in d.draw(lists(binary()))]
5842 schema = OctetString()
5844 seq_encoded = seq.encode()
5845 seq_decoded, _ = seq.decode(seq_encoded)
5846 self.assertSequenceEqual(
5847 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5848 b"".join(sorted([v.encode() for v in values])),
5851 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5852 @given(data_strategy())
5853 def test_unsorted(self, d):
5854 values = [OctetString(v).encode() for v in d.draw(sets(
5855 binary(min_size=1, max_size=5),
5859 values = d.draw(permutations(values))
5860 assume(values != sorted(values))
5861 encoded = b"".join(values)
5862 seq_encoded = b"".join((
5864 len_encode(len(encoded)),
5869 schema = OctetString()
5871 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5872 seq.decode(seq_encoded)
5874 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5875 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5876 self.assertTrue(seq_decoded.ber_encoded)
5877 self.assertTrue(seq_decoded.bered)
5878 seq_decoded = seq_decoded.copy()
5879 self.assertTrue(seq_decoded.ber_encoded)
5880 self.assertTrue(seq_decoded.bered)
5881 self.assertSequenceEqual(
5882 [obj.encode() for obj in seq_decoded],
5887 class TestGoMarshalVectors(TestCase):
5889 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5890 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5891 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5892 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5893 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5895 class Seq(Sequence):
5897 ("erste", Integer()),
5898 ("zweite", Integer(optional=True))
5901 seq["erste"] = Integer(64)
5902 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5903 seq["erste"] = Integer(0x123456)
5904 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5905 seq["erste"] = Integer(64)
5906 seq["zweite"] = Integer(65)
5907 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5909 class NestedSeq(Sequence):
5913 seq["erste"] = Integer(127)
5914 seq["zweite"] = None
5915 nested = NestedSeq()
5916 nested["nest"] = seq
5917 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5919 self.assertSequenceEqual(
5920 OctetString(b"\x01\x02\x03").encode(),
5921 hexdec("0403010203"),
5924 class Seq(Sequence):
5926 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5929 seq["erste"] = Integer(64)
5930 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5932 class Seq(Sequence):
5934 ("erste", Integer(expl=tag_ctxc(5))),
5937 seq["erste"] = Integer(64)
5938 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5940 class Seq(Sequence):
5943 impl=tag_encode(0, klass=TagClassContext),
5948 seq["erste"] = Null()
5949 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5951 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5953 self.assertSequenceEqual(
5954 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5955 hexdec("170d3730303130313030303030305a"),
5957 self.assertSequenceEqual(
5958 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5959 hexdec("170d3039313131353232353631365a"),
5961 self.assertSequenceEqual(
5962 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5963 hexdec("180f32313030303430353132303130315a"),
5966 class Seq(Sequence):
5968 ("erste", GeneralizedTime()),
5971 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5972 self.assertSequenceEqual(
5974 hexdec("3011180f32303039313131353232353631365a"),
5977 self.assertSequenceEqual(
5978 BitString((1, b"\x80")).encode(),
5981 self.assertSequenceEqual(
5982 BitString((12, b"\x81\xF0")).encode(),
5983 hexdec("03030481f0"),
5986 self.assertSequenceEqual(
5987 ObjectIdentifier("1.2.3.4").encode(),
5988 hexdec("06032a0304"),
5990 self.assertSequenceEqual(
5991 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5992 hexdec("06092a864888932d010105"),
5994 self.assertSequenceEqual(
5995 ObjectIdentifier("2.100.3").encode(),
5996 hexdec("0603813403"),
5999 self.assertSequenceEqual(
6000 PrintableString("test").encode(),
6001 hexdec("130474657374"),
6003 self.assertSequenceEqual(
6004 PrintableString("x" * 127).encode(),
6005 hexdec("137F" + "78" * 127),
6007 self.assertSequenceEqual(
6008 PrintableString("x" * 128).encode(),
6009 hexdec("138180" + "78" * 128),
6011 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6013 class Seq(Sequence):
6015 ("erste", IA5String()),
6018 seq["erste"] = IA5String("test")
6019 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6021 class Seq(Sequence):
6023 ("erste", PrintableString()),
6026 seq["erste"] = PrintableString("test")
6027 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6028 # Asterisk is actually not allowable
6029 PrintableString._allowable_chars |= set(b"*")
6030 seq["erste"] = PrintableString("test*")
6031 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6032 PrintableString._allowable_chars -= set(b"*")
6034 class Seq(Sequence):
6036 ("erste", Any(optional=True)),
6037 ("zweite", Integer()),
6040 seq["zweite"] = Integer(64)
6041 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6046 seq.append(Integer(10))
6047 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6049 class _SeqOf(SequenceOf):
6050 schema = PrintableString()
6052 class SeqOf(SequenceOf):
6055 _seqof.append(PrintableString("1"))
6057 seqof.append(_seqof)
6058 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6060 class Seq(Sequence):
6062 ("erste", Integer(default=1)),
6065 seq["erste"] = Integer(0)
6066 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6067 seq["erste"] = Integer(1)
6068 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6069 seq["erste"] = Integer(2)
6070 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6073 class TestPP(TestCase):
6074 @given(data_strategy())
6075 def test_oid_printing(self, d):
6077 str(ObjectIdentifier(k)): v * 2
6078 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6080 chosen = d.draw(sampled_from(sorted(oids)))
6081 chosen_id = oids[chosen]
6082 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6083 self.assertNotIn(chosen_id, pp_console_row(pp))
6084 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
6087 class TestAutoAddSlots(TestCase):
6089 class Inher(Integer):
6092 with self.assertRaises(AttributeError):
6094 inher.unexistent = "whatever"
6097 class TestOIDDefines(TestCase):
6098 @given(data_strategy())
6099 def runTest(self, d):
6100 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6101 value_name_chosen = d.draw(sampled_from(value_names))
6103 ObjectIdentifier(oid)
6104 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6106 oid_chosen = d.draw(sampled_from(oids))
6107 values = d.draw(lists(
6109 min_size=len(value_names),
6110 max_size=len(value_names),
6113 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6114 oid: Integer() for oid in oids[:-1]
6117 for i, value_name in enumerate(value_names):
6118 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6120 class Seq(Sequence):
6123 for value_name, value in zip(value_names, values):
6124 seq[value_name] = Any(Integer(value).encode())
6125 seq["type"] = oid_chosen
6126 seq, _ = Seq().decode(seq.encode())
6127 for value_name in value_names:
6128 if value_name == value_name_chosen:
6130 self.assertIsNone(seq[value_name].defined)
6131 if value_name_chosen in oids[:-1]:
6132 self.assertIsNotNone(seq[value_name_chosen].defined)
6133 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6134 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6137 pprint(seq, big_blobs=True, with_decode_path=True)
6140 class TestDefinesByPath(TestCase):
6141 def test_generated(self):
6142 class Seq(Sequence):
6144 ("type", ObjectIdentifier()),
6145 ("value", OctetString(expl=tag_ctxc(123))),
6148 class SeqInner(Sequence):
6150 ("typeInner", ObjectIdentifier()),
6151 ("valueInner", Any()),
6154 class PairValue(SetOf):
6157 class Pair(Sequence):
6159 ("type", ObjectIdentifier()),
6160 ("value", PairValue()),
6163 class Pairs(SequenceOf):
6170 type_octet_stringed,
6172 ObjectIdentifier(oid)
6173 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6175 seq_integered = Seq()
6176 seq_integered["type"] = type_integered
6177 seq_integered["value"] = OctetString(Integer(123).encode())
6178 seq_integered_raw = seq_integered.encode()
6182 (type_octet_stringed, OctetString(b"whatever")),
6183 (type_integered, Integer(123)),
6184 (type_octet_stringed, OctetString(b"whenever")),
6185 (type_integered, Integer(234)),
6187 for t, v in pairs_input:
6190 pair["value"] = PairValue((Any(v),))
6192 seq_inner = SeqInner()
6193 seq_inner["typeInner"] = type_innered
6194 seq_inner["valueInner"] = Any(pairs)
6195 seq_sequenced = Seq()
6196 seq_sequenced["type"] = type_sequenced
6197 seq_sequenced["value"] = OctetString(seq_inner.encode())
6198 seq_sequenced_raw = seq_sequenced.encode()
6200 list(seq_sequenced.pps())
6201 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6203 defines_by_path = []
6204 ctx_copied = deepcopy(ctx_dummy)
6205 seq_integered, _ = Seq().decode(
6209 self.assertDictEqual(ctx_copied, ctx_dummy)
6210 self.assertIsNone(seq_integered["value"].defined)
6211 defines_by_path.append(
6212 (("type",), ((("value",), {
6213 type_integered: Integer(),
6214 type_sequenced: SeqInner(),
6217 ctx_copied["defines_by_path"] = defines_by_path
6218 seq_integered, _ = Seq().decode(
6222 del ctx_copied["defines_by_path"]
6223 self.assertDictEqual(ctx_copied, ctx_dummy)
6224 self.assertIsNotNone(seq_integered["value"].defined)
6225 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6226 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6227 self.assertTrue(seq_integered_raw[
6228 seq_integered["value"].defined[1].offset:
6229 ].startswith(Integer(123).encode()))
6231 list(seq_integered.pps())
6232 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6234 ctx_copied["defines_by_path"] = defines_by_path
6235 seq_sequenced, _ = Seq().decode(
6239 del ctx_copied["defines_by_path"]
6240 self.assertDictEqual(ctx_copied, ctx_dummy)
6241 self.assertIsNotNone(seq_sequenced["value"].defined)
6242 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6243 seq_inner = seq_sequenced["value"].defined[1]
6244 self.assertIsNone(seq_inner["valueInner"].defined)
6246 list(seq_sequenced.pps())
6247 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6249 defines_by_path.append((
6250 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6251 ((("valueInner",), {type_innered: Pairs()}),),
6253 ctx_copied["defines_by_path"] = defines_by_path
6254 seq_sequenced, _ = Seq().decode(
6258 del ctx_copied["defines_by_path"]
6259 self.assertDictEqual(ctx_copied, ctx_dummy)
6260 self.assertIsNotNone(seq_sequenced["value"].defined)
6261 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6262 seq_inner = seq_sequenced["value"].defined[1]
6263 self.assertIsNotNone(seq_inner["valueInner"].defined)
6264 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6265 pairs = seq_inner["valueInner"].defined[1]
6267 self.assertIsNone(pair["value"][0].defined)
6269 list(seq_sequenced.pps())
6270 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6272 defines_by_path.append((
6275 DecodePathDefBy(type_sequenced),
6277 DecodePathDefBy(type_innered),
6282 type_integered: Integer(),
6283 type_octet_stringed: OctetString(),
6286 ctx_copied["defines_by_path"] = defines_by_path
6287 seq_sequenced, _ = Seq().decode(
6291 del ctx_copied["defines_by_path"]
6292 self.assertDictEqual(ctx_copied, ctx_dummy)
6293 self.assertIsNotNone(seq_sequenced["value"].defined)
6294 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6295 seq_inner = seq_sequenced["value"].defined[1]
6296 self.assertIsNotNone(seq_inner["valueInner"].defined)
6297 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6298 pairs_got = seq_inner["valueInner"].defined[1]
6299 for pair_input, pair_got in zip(pairs_input, pairs_got):
6300 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6301 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6303 list(seq_sequenced.pps())
6304 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6306 @given(oid_strategy(), integers())
6307 def test_simple(self, oid, tgt):
6308 class Inner(Sequence):
6310 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6311 ObjectIdentifier(oid): Integer(),
6315 class Outer(Sequence):
6318 ("tgt", OctetString()),
6322 inner["oid"] = ObjectIdentifier(oid)
6324 outer["inner"] = inner
6325 outer["tgt"] = OctetString(Integer(tgt).encode())
6326 decoded, _ = Outer().decode(outer.encode())
6327 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6330 class TestAbsDecodePath(TestCase):
6332 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6333 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6335 def test_concat(self, decode_path, rel_path):
6336 self.assertSequenceEqual(
6337 abs_decode_path(decode_path, rel_path),
6338 decode_path + rel_path,
6342 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6343 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6345 def test_abs(self, decode_path, rel_path):
6346 self.assertSequenceEqual(
6347 abs_decode_path(decode_path, ("/",) + rel_path),
6352 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6353 integers(min_value=1, max_value=3),
6354 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6356 def test_dots(self, decode_path, number_of_dots, rel_path):
6357 self.assertSequenceEqual(
6358 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6359 decode_path[:-number_of_dots] + rel_path,
6363 class TestStrictDefaultExistence(TestCase):
6364 @given(data_strategy())
6365 def runTest(self, d):
6366 count = d.draw(integers(min_value=1, max_value=10))
6367 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6369 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6370 for i in range(count)
6372 for klass in (Sequence, Set):
6376 for i in range(count):
6377 seq["int%d" % i] = Integer(123)
6379 chosen_choice = "int%d" % chosen
6380 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6381 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6383 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6384 self.assertTrue(decoded.ber_encoded)
6385 self.assertTrue(decoded.bered)
6386 decoded = decoded.copy()
6387 self.assertTrue(decoded.ber_encoded)
6388 self.assertTrue(decoded.bered)
6389 decoded, _ = seq.decode(raw, ctx={"bered": True})
6390 self.assertTrue(decoded.ber_encoded)
6391 self.assertTrue(decoded.bered)
6392 decoded = decoded.copy()
6393 self.assertTrue(decoded.ber_encoded)
6394 self.assertTrue(decoded.bered)
6397 class TestX690PrefixedType(TestCase):
6399 self.assertSequenceEqual(
6400 VisibleString("Jones").encode(),
6401 hexdec("1A054A6F6E6573"),
6403 self.assertSequenceEqual(
6406 impl=tag_encode(3, klass=TagClassApplication),
6408 hexdec("43054A6F6E6573"),
6410 self.assertSequenceEqual(
6414 impl=tag_encode(3, klass=TagClassApplication),
6418 hexdec("A20743054A6F6E6573"),
6420 self.assertSequenceEqual(
6424 impl=tag_encode(3, klass=TagClassApplication),
6426 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6428 hexdec("670743054A6F6E6573"),
6430 self.assertSequenceEqual(
6431 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6432 hexdec("82054A6F6E6573"),
6436 class TestExplOOB(TestCase):
6438 expl = tag_ctxc(123)
6439 raw = Integer(123).encode() + Integer(234).encode()
6440 raw = b"".join((expl, len_encode(len(raw)), raw))
6441 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6442 Integer(expl=expl).decode(raw)
6443 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})