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 self.additional_symmetric_check(value, obj_encoded)
3777 obj_expled = obj(value, expl=tag_expl)
3778 self.assertTrue(obj_expled.expled)
3780 list(obj_expled.pps())
3781 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3782 obj_expled_encoded = obj_expled.encode()
3783 ctx_copied = deepcopy(ctx_dummy)
3784 obj_decoded, tail = obj_expled.decode(
3785 obj_expled_encoded + tail_junk,
3789 self.assertDictEqual(ctx_copied, ctx_dummy)
3791 list(obj_decoded.pps())
3792 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3793 self.assertEqual(tail, tail_junk)
3794 self.assertEqual(obj_decoded, obj_expled)
3795 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3796 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3797 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3798 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3799 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3801 obj_decoded.expl_llen,
3802 len(len_encode(len(obj_encoded))),
3804 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3805 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3808 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3810 self.assertEqual(obj_decoded.expl_offset, offset)
3813 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3814 base_klass = GeneralizedTime
3816 min_datetime = datetime(1900, 1, 1)
3817 max_datetime = datetime(9999, 12, 31)
3819 def additional_symmetric_check(self, value, obj_encoded):
3820 if value.microsecond > 0:
3821 self.assertFalse(obj_encoded.endswith(b"0Z"))
3823 def test_x690_vector_valid(self):
3827 b"19920722132100.3Z",
3829 GeneralizedTime(data)
3831 def test_x690_vector_invalid(self):
3834 b"19920622123421.0Z",
3835 b"19920722132100.30Z",
3837 with self.assertRaises(DecodeError) as err:
3838 GeneralizedTime(data)
3841 def test_go_vectors_invalid(self):
3853 b"-20100102030410Z",
3854 b"2010-0102030410Z",
3855 b"2010-0002030410Z",
3856 b"201001-02030410Z",
3857 b"20100102-030410Z",
3858 b"2010010203-0410Z",
3859 b"201001020304-10Z",
3860 # These ones are INVALID in *DER*, but accepted
3861 # by Go's encoding/asn1
3862 b"20100102030405+0607",
3863 b"20100102030405-0607",
3865 with self.assertRaises(DecodeError) as err:
3866 GeneralizedTime(data)
3869 def test_go_vectors_valid(self):
3871 GeneralizedTime(b"20100102030405Z").todatetime(),
3872 datetime(2010, 1, 2, 3, 4, 5, 0),
3877 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3878 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3880 binary(min_size=1, max_size=1),
3882 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3883 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3886 def test_junk(self, part0, part1, part2):
3887 junk = part0 + part1 + part2
3888 assume(not (set(junk) <= set(digits.encode("ascii"))))
3889 with self.assertRaises(DecodeError):
3890 GeneralizedTime().decode(
3891 GeneralizedTime.tag_default +
3892 len_encode(len(junk)) +
3898 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3899 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3901 binary(min_size=1, max_size=1),
3903 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3904 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3907 def test_junk_dm(self, part0, part1, part2):
3908 junk = part0 + part1 + part2
3909 assume(not (set(junk) <= set(digits.encode("ascii"))))
3910 with self.assertRaises(DecodeError):
3911 GeneralizedTime().decode(
3912 GeneralizedTime.tag_default +
3913 len_encode(len(junk)) +
3917 def test_ns_fractions(self):
3918 GeneralizedTime(b"20010101000000.000001Z")
3919 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
3920 GeneralizedTime(b"20010101000000.0000001Z")
3923 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3924 base_klass = UTCTime
3926 min_datetime = datetime(2000, 1, 1)
3927 max_datetime = datetime(2049, 12, 31)
3929 def additional_symmetric_check(self, value, obj_encoded):
3932 def test_x690_vector_valid(self):
3940 def test_x690_vector_invalid(self):
3945 with self.assertRaises(DecodeError) as err:
3949 def test_go_vectors_invalid(self):
3975 # These ones are INVALID in *DER*, but accepted
3976 # by Go's encoding/asn1
3977 b"910506164540-0700",
3978 b"910506164540+0730",
3982 with self.assertRaises(DecodeError) as err:
3986 def test_go_vectors_valid(self):
3988 UTCTime(b"910506234540Z").todatetime(),
3989 datetime(1991, 5, 6, 23, 45, 40, 0),
3992 @given(integers(min_value=0, max_value=49))
3993 def test_pre50(self, year):
3995 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3999 @given(integers(min_value=50, max_value=99))
4000 def test_post50(self, year):
4002 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4008 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4009 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4011 binary(min_size=1, max_size=1),
4013 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4014 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4017 def test_junk(self, part0, part1, part2):
4018 junk = part0 + part1 + part2
4019 assume(not (set(junk) <= set(digits.encode("ascii"))))
4020 with self.assertRaises(DecodeError):
4022 UTCTime.tag_default +
4023 len_encode(len(junk)) +
4029 def any_values_strategy(draw, do_expl=False):
4030 value = draw(one_of(none(), binary()))
4033 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4034 optional = draw(one_of(none(), booleans()))
4036 draw(integers(min_value=0)),
4037 draw(integers(min_value=0)),
4038 draw(integers(min_value=0)),
4040 return (value, expl, optional, _decoded)
4043 class AnyInherited(Any):
4047 class TestAny(CommonMixin, TestCase):
4050 def test_invalid_value_type(self):
4051 with self.assertRaises(InvalidValueType) as err:
4056 def test_optional(self, optional):
4057 obj = Any(optional=optional)
4058 self.assertEqual(obj.optional, optional)
4061 def test_ready(self, value):
4063 self.assertFalse(obj.ready)
4066 pprint(obj, big_blobs=True, with_decode_path=True)
4067 with self.assertRaises(ObjNotReady) as err:
4071 self.assertTrue(obj.ready)
4074 pprint(obj, big_blobs=True, with_decode_path=True)
4077 def test_basic(self, value):
4078 integer_encoded = Integer(value).encode()
4080 Any(integer_encoded),
4081 Any(Integer(value)),
4082 Any(Any(Integer(value))),
4084 self.assertSequenceEqual(bytes(obj), integer_encoded)
4086 obj.decode(obj.encode())[0].vlen,
4087 len(integer_encoded),
4091 pprint(obj, big_blobs=True, with_decode_path=True)
4092 self.assertSequenceEqual(obj.encode(), integer_encoded)
4094 @given(binary(), binary())
4095 def test_comparison(self, value1, value2):
4096 for klass in (Any, AnyInherited):
4097 obj1 = klass(value1)
4098 obj2 = klass(value2)
4099 self.assertEqual(obj1 == obj2, value1 == value2)
4100 self.assertEqual(obj1 != obj2, value1 != value2)
4101 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4103 @given(data_strategy())
4104 def test_call(self, d):
4105 for klass in (Any, AnyInherited):
4111 ) = d.draw(any_values_strategy())
4112 obj_initial = klass(
4115 optional_initial or False,
4123 ) = d.draw(any_values_strategy(do_expl=True))
4124 obj = obj_initial(value, expl, optional)
4126 value_expected = None if value is None else value
4127 self.assertEqual(obj, value_expected)
4128 self.assertEqual(obj.expl_tag, expl or expl_initial)
4129 if obj.default is None:
4130 optional = optional_initial if optional is None else optional
4131 optional = False if optional is None else optional
4132 self.assertEqual(obj.optional, optional)
4134 def test_simultaneous_impl_expl(self):
4135 # override it, as Any does not have implicit tag
4138 def test_decoded(self):
4139 # override it, as Any does not have implicit tag
4142 @given(any_values_strategy())
4143 def test_copy(self, values):
4144 for klass in (Any, AnyInherited):
4145 obj = klass(*values)
4146 obj_copied = obj.copy()
4147 self.assert_copied_basic_fields(obj, obj_copied)
4148 self.assertEqual(obj._value, obj_copied._value)
4150 @given(binary().map(OctetString))
4151 def test_stripped(self, value):
4153 with self.assertRaises(NotEnoughData):
4154 obj.decode(obj.encode()[:-1])
4158 integers(min_value=1).map(tag_ctxc),
4160 def test_stripped_expl(self, value, tag_expl):
4161 obj = Any(value, expl=tag_expl)
4162 with self.assertRaises(NotEnoughData):
4163 obj.decode(obj.encode()[:-1])
4166 integers(min_value=31),
4167 integers(min_value=0),
4170 def test_bad_tag(self, tag, offset, decode_path):
4171 with self.assertRaises(DecodeError) as err:
4173 tag_encode(tag)[:-1],
4175 decode_path=decode_path,
4178 self.assertEqual(err.exception.offset, offset)
4179 self.assertEqual(err.exception.decode_path, decode_path)
4182 integers(min_value=128),
4183 integers(min_value=0),
4186 def test_bad_len(self, l, offset, decode_path):
4187 with self.assertRaises(DecodeError) as err:
4189 Any.tag_default + len_encode(l)[:-1],
4191 decode_path=decode_path,
4194 self.assertEqual(err.exception.offset, offset)
4195 self.assertEqual(err.exception.decode_path, decode_path)
4197 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4199 any_values_strategy(),
4200 integers().map(lambda x: Integer(x).encode()),
4201 integers(min_value=1).map(tag_ctxc),
4202 integers(min_value=0),
4205 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4206 for klass in (Any, AnyInherited):
4207 _, _, optional, _decoded = values
4208 obj = klass(value=value, optional=optional, _decoded=_decoded)
4211 pprint(obj, big_blobs=True, with_decode_path=True)
4212 self.assertFalse(obj.expled)
4213 obj_encoded = obj.encode()
4214 obj_expled = obj(value, expl=tag_expl)
4215 self.assertTrue(obj_expled.expled)
4217 list(obj_expled.pps())
4218 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4219 obj_expled_encoded = obj_expled.encode()
4220 ctx_copied = deepcopy(ctx_dummy)
4221 obj_decoded, tail = obj_expled.decode(
4222 obj_expled_encoded + tail_junk,
4226 self.assertDictEqual(ctx_copied, ctx_dummy)
4228 list(obj_decoded.pps())
4229 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4230 self.assertEqual(tail, tail_junk)
4231 self.assertEqual(obj_decoded, obj_expled)
4232 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4233 self.assertEqual(bytes(obj_decoded), bytes(obj))
4234 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4235 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4236 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4238 obj_decoded.expl_llen,
4239 len(len_encode(len(obj_encoded))),
4241 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4242 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4245 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4247 self.assertEqual(obj_decoded.expl_offset, offset)
4248 self.assertEqual(obj_decoded.tlen, 0)
4249 self.assertEqual(obj_decoded.llen, 0)
4250 self.assertEqual(obj_decoded.vlen, len(value))
4253 integers(min_value=1).map(tag_ctxc),
4254 integers(min_value=0, max_value=3),
4255 integers(min_value=0),
4259 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4260 chunk = Boolean(False, expl=expl).encode()
4262 OctetString.tag_default +
4264 b"".join([chunk] * chunks) +
4267 with self.assertRaises(LenIndefForm):
4271 decode_path=decode_path,
4273 obj, tail = Any().decode(
4276 decode_path=decode_path,
4277 ctx={"bered": True},
4279 self.assertSequenceEqual(tail, junk)
4280 self.assertEqual(obj.offset, offset)
4281 self.assertEqual(obj.tlvlen, len(encoded))
4282 self.assertTrue(obj.lenindef)
4283 self.assertFalse(obj.ber_encoded)
4284 self.assertTrue(obj.bered)
4286 self.assertTrue(obj.lenindef)
4287 self.assertFalse(obj.ber_encoded)
4288 self.assertTrue(obj.bered)
4291 pprint(obj, big_blobs=True, with_decode_path=True)
4292 with self.assertRaises(NotEnoughData) as err:
4296 decode_path=decode_path,
4297 ctx={"bered": True},
4299 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4300 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4302 class SeqOf(SequenceOf):
4303 schema = Boolean(expl=expl)
4305 class Seq(Sequence):
4307 ("type", ObjectIdentifier(defines=((("value",), {
4308 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4313 ("type", ObjectIdentifier("1.2.3")),
4314 ("value", Any(encoded)),
4316 seq_encoded = seq.encode()
4317 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4318 self.assertIsNotNone(seq_decoded["value"].defined)
4320 list(seq_decoded.pps())
4321 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4322 self.assertTrue(seq_decoded.bered)
4323 self.assertFalse(seq_decoded["type"].bered)
4324 self.assertTrue(seq_decoded["value"].bered)
4326 chunk = chunk[:-1] + b"\x01"
4327 chunks = b"".join([chunk] * (chunks + 1))
4328 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4330 ("type", ObjectIdentifier("1.2.3")),
4331 ("value", Any(encoded)),
4333 seq_encoded = seq.encode()
4334 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4335 self.assertIsNotNone(seq_decoded["value"].defined)
4337 list(seq_decoded.pps())
4338 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4339 self.assertTrue(seq_decoded.bered)
4340 self.assertFalse(seq_decoded["type"].bered)
4341 self.assertTrue(seq_decoded["value"].bered)
4345 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4347 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4348 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4350 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4351 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4353 min_size=len(names),
4354 max_size=len(names),
4357 (name, Integer(**tag_kwargs))
4358 for name, tag_kwargs in zip(names, tags)
4361 if value_required or draw(booleans()):
4362 value = draw(tuples(
4363 sampled_from([name for name, _ in schema]),
4364 integers().map(Integer),
4368 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4369 default = draw(one_of(
4371 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4373 optional = draw(one_of(none(), booleans()))
4375 draw(integers(min_value=0)),
4376 draw(integers(min_value=0)),
4377 draw(integers(min_value=0)),
4379 return (schema, value, expl, default, optional, _decoded)
4382 class ChoiceInherited(Choice):
4386 class TestChoice(CommonMixin, TestCase):
4388 schema = (("whatever", Boolean()),)
4391 def test_schema_required(self):
4392 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4395 def test_impl_forbidden(self):
4396 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4397 Choice(impl=b"whatever")
4399 def test_invalid_value_type(self):
4400 with self.assertRaises(InvalidValueType) as err:
4401 self.base_klass(123)
4403 with self.assertRaises(ObjUnknown) as err:
4404 self.base_klass(("whenever", Boolean(False)))
4406 with self.assertRaises(InvalidValueType) as err:
4407 self.base_klass(("whatever", Integer(123)))
4411 def test_optional(self, optional):
4412 obj = self.base_klass(
4413 default=self.base_klass(("whatever", Boolean(False))),
4416 self.assertTrue(obj.optional)
4419 def test_ready(self, value):
4420 obj = self.base_klass()
4421 self.assertFalse(obj.ready)
4424 pprint(obj, big_blobs=True, with_decode_path=True)
4425 self.assertIsNone(obj["whatever"])
4426 with self.assertRaises(ObjNotReady) as err:
4429 obj["whatever"] = Boolean()
4430 self.assertFalse(obj.ready)
4433 pprint(obj, big_blobs=True, with_decode_path=True)
4434 obj["whatever"] = Boolean(value)
4435 self.assertTrue(obj.ready)
4438 pprint(obj, big_blobs=True, with_decode_path=True)
4440 @given(booleans(), booleans())
4441 def test_comparison(self, value1, value2):
4442 class WahlInherited(self.base_klass):
4444 for klass in (self.base_klass, WahlInherited):
4445 obj1 = klass(("whatever", Boolean(value1)))
4446 obj2 = klass(("whatever", Boolean(value2)))
4447 self.assertEqual(obj1 == obj2, value1 == value2)
4448 self.assertEqual(obj1 != obj2, value1 != value2)
4449 self.assertEqual(obj1 == obj2._value, value1 == value2)
4450 self.assertFalse(obj1 == obj2._value[1])
4452 @given(data_strategy())
4453 def test_call(self, d):
4454 for klass in (Choice, ChoiceInherited):
4462 ) = d.draw(choice_values_strategy())
4465 schema = schema_initial
4467 value=value_initial,
4469 default=default_initial,
4470 optional=optional_initial or False,
4471 _decoded=_decoded_initial,
4480 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4481 obj = obj_initial(value, expl, default, optional)
4483 value_expected = default if value is None else value
4485 default_initial if value_expected is None
4488 self.assertEqual(obj.choice, value_expected[0])
4489 self.assertEqual(obj.value, int(value_expected[1]))
4490 self.assertEqual(obj.expl_tag, expl or expl_initial)
4491 default_expect = default_initial if default is None else default
4492 if default_expect is not None:
4493 self.assertEqual(obj.default.choice, default_expect[0])
4494 self.assertEqual(obj.default.value, int(default_expect[1]))
4495 if obj.default is None:
4496 optional = optional_initial if optional is None else optional
4497 optional = False if optional is None else optional
4500 self.assertEqual(obj.optional, optional)
4501 self.assertEqual(obj.specs, obj_initial.specs)
4503 def test_simultaneous_impl_expl(self):
4504 # override it, as Any does not have implicit tag
4507 def test_decoded(self):
4508 # override it, as Any does not have implicit tag
4511 @given(choice_values_strategy())
4512 def test_copy(self, values):
4513 _schema, value, expl, default, optional, _decoded = values
4515 class Wahl(self.base_klass):
4521 optional=optional or False,
4524 obj_copied = obj.copy()
4525 self.assertIsNone(obj.tag)
4526 self.assertIsNone(obj_copied.tag)
4527 # hack for assert_copied_basic_fields
4528 obj.tag = "whatever"
4529 obj_copied.tag = "whatever"
4530 self.assert_copied_basic_fields(obj, obj_copied)
4531 self.assertEqual(obj._value, obj_copied._value)
4532 self.assertEqual(obj.specs, obj_copied.specs)
4535 def test_stripped(self, value):
4536 obj = self.base_klass(("whatever", Boolean(value)))
4537 with self.assertRaises(NotEnoughData):
4538 obj.decode(obj.encode()[:-1])
4542 integers(min_value=1).map(tag_ctxc),
4544 def test_stripped_expl(self, value, tag_expl):
4545 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4546 with self.assertRaises(NotEnoughData):
4547 obj.decode(obj.encode()[:-1])
4549 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4550 @given(data_strategy())
4551 def test_symmetric(self, d):
4552 _schema, value, _, default, optional, _decoded = d.draw(
4553 choice_values_strategy(value_required=True)
4555 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4556 offset = d.draw(integers(min_value=0))
4557 tail_junk = d.draw(binary(max_size=5))
4559 class Wahl(self.base_klass):
4569 pprint(obj, big_blobs=True, with_decode_path=True)
4570 self.assertFalse(obj.expled)
4571 obj_encoded = obj.encode()
4572 obj_expled = obj(value, expl=tag_expl)
4573 self.assertTrue(obj_expled.expled)
4575 list(obj_expled.pps())
4576 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4577 obj_expled_encoded = obj_expled.encode()
4578 ctx_copied = deepcopy(ctx_dummy)
4579 obj_decoded, tail = obj_expled.decode(
4580 obj_expled_encoded + tail_junk,
4584 self.assertDictEqual(ctx_copied, ctx_dummy)
4586 list(obj_decoded.pps())
4587 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4588 self.assertEqual(tail, tail_junk)
4589 self.assertEqual(obj_decoded, obj_expled)
4590 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4591 self.assertEqual(obj_decoded.value, obj_expled.value)
4592 self.assertEqual(obj_decoded.choice, obj.choice)
4593 self.assertEqual(obj_decoded.value, obj.value)
4594 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4595 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4596 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4598 obj_decoded.expl_llen,
4599 len(len_encode(len(obj_encoded))),
4601 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4602 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4605 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4607 self.assertEqual(obj_decoded.expl_offset, offset)
4608 self.assertSequenceEqual(
4610 obj_decoded.value.fulloffset - offset:
4611 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4617 def test_set_get(self, value):
4620 ("erste", Boolean()),
4621 ("zweite", Integer()),
4624 with self.assertRaises(ObjUnknown) as err:
4625 obj["whatever"] = "whenever"
4626 with self.assertRaises(InvalidValueType) as err:
4627 obj["zweite"] = Boolean(False)
4628 obj["zweite"] = Integer(value)
4630 with self.assertRaises(ObjUnknown) as err:
4633 self.assertIsNone(obj["erste"])
4634 self.assertEqual(obj["zweite"], Integer(value))
4636 def test_tag_mismatch(self):
4639 ("erste", Boolean()),
4641 int_encoded = Integer(123).encode()
4642 bool_encoded = Boolean(False).encode()
4644 obj.decode(bool_encoded)
4645 with self.assertRaises(TagMismatch):
4646 obj.decode(int_encoded)
4648 def test_tag_mismatch_underlying(self):
4649 class SeqOfBoolean(SequenceOf):
4652 class SeqOfInteger(SequenceOf):
4657 ("erste", SeqOfBoolean()),
4660 int_encoded = SeqOfInteger((Integer(123),)).encode()
4661 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4663 obj.decode(bool_encoded)
4664 with self.assertRaises(TagMismatch) as err:
4665 obj.decode(int_encoded)
4666 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4670 def seq_values_strategy(draw, seq_klass, do_expl=False):
4672 if draw(booleans()):
4675 k: v for k, v in draw(dictionaries(
4678 booleans().map(Boolean),
4679 integers().map(Integer),
4684 if draw(booleans()):
4685 schema = list(draw(dictionaries(
4688 booleans().map(Boolean),
4689 integers().map(Integer),
4695 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4697 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4699 if draw(booleans()):
4700 default = seq_klass()
4702 k: v for k, v in draw(dictionaries(
4705 booleans().map(Boolean),
4706 integers().map(Integer),
4710 optional = draw(one_of(none(), booleans()))
4712 draw(integers(min_value=0)),
4713 draw(integers(min_value=0)),
4714 draw(integers(min_value=0)),
4716 return (value, schema, impl, expl, default, optional, _decoded)
4720 def sequence_strategy(draw, seq_klass):
4721 inputs = draw(lists(
4723 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4724 tuples(just(Integer), integers(), one_of(none(), integers())),
4729 integers(min_value=1),
4730 min_size=len(inputs),
4731 max_size=len(inputs),
4734 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4735 for tag, expled in zip(tags, draw(lists(
4737 min_size=len(inputs),
4738 max_size=len(inputs),
4742 for i, optional in enumerate(draw(lists(
4743 sampled_from(("required", "optional", "empty")),
4744 min_size=len(inputs),
4745 max_size=len(inputs),
4747 if optional in ("optional", "empty"):
4748 inits[i]["optional"] = True
4749 if optional == "empty":
4751 empties = set(empties)
4752 names = list(draw(sets(
4754 min_size=len(inputs),
4755 max_size=len(inputs),
4758 for i, (klass, value, default) in enumerate(inputs):
4759 schema.append((names[i], klass(default=default, **inits[i])))
4760 seq_name = draw(text_letters())
4761 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4764 for i, (klass, value, default) in enumerate(inputs):
4771 "default_value": None if spec.default is None else default,
4775 expect["optional"] = True
4777 expect["presented"] = True
4778 expect["value"] = value
4780 expect["optional"] = True
4781 if default is not None and default == value:
4782 expect["presented"] = False
4783 seq[name] = klass(value)
4784 expects.append(expect)
4789 def sequences_strategy(draw, seq_klass):
4790 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4792 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4793 for tag, expled in zip(tags, draw(lists(
4800 i for i, is_default in enumerate(draw(lists(
4806 names = list(draw(sets(
4811 seq_expectses = draw(lists(
4812 sequence_strategy(seq_klass=seq_klass),
4816 seqs = [seq for seq, _ in seq_expectses]
4818 for i, (name, seq) in enumerate(zip(names, seqs)):
4821 seq(default=(seq if i in defaulted else None), **inits[i]),
4823 seq_name = draw(text_letters())
4824 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4827 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4830 "expects": expects_inner,
4833 seq_outer[name] = seq_inner
4834 if seq_outer.specs[name].default is None:
4835 expect["presented"] = True
4836 expect_outers.append(expect)
4837 return seq_outer, expect_outers
4840 class SeqMixing(object):
4841 def test_invalid_value_type(self):
4842 with self.assertRaises(InvalidValueType) as err:
4843 self.base_klass(123)
4846 def test_invalid_value_type_set(self):
4847 class Seq(self.base_klass):
4848 schema = (("whatever", Boolean()),)
4850 with self.assertRaises(InvalidValueType) as err:
4851 seq["whatever"] = Integer(123)
4855 def test_optional(self, optional):
4856 obj = self.base_klass(default=self.base_klass(), optional=optional)
4857 self.assertTrue(obj.optional)
4859 @given(data_strategy())
4860 def test_ready(self, d):
4862 str(i): v for i, v in enumerate(d.draw(lists(
4869 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4876 for name in d.draw(permutations(
4877 list(ready.keys()) + list(non_ready.keys()),
4879 schema_input.append((name, Boolean()))
4881 class Seq(self.base_klass):
4882 schema = tuple(schema_input)
4884 for name in ready.keys():
4886 seq[name] = Boolean()
4887 self.assertFalse(seq.ready)
4890 pprint(seq, big_blobs=True, with_decode_path=True)
4891 for name, value in ready.items():
4892 seq[name] = Boolean(value)
4893 self.assertFalse(seq.ready)
4896 pprint(seq, big_blobs=True, with_decode_path=True)
4897 with self.assertRaises(ObjNotReady) as err:
4900 for name, value in non_ready.items():
4901 seq[name] = Boolean(value)
4902 self.assertTrue(seq.ready)
4905 pprint(seq, big_blobs=True, with_decode_path=True)
4907 @given(data_strategy())
4908 def test_call(self, d):
4909 class SeqInherited(self.base_klass):
4911 for klass in (self.base_klass, SeqInherited):
4920 ) = d.draw(seq_values_strategy(seq_klass=klass))
4921 obj_initial = klass(
4927 optional_initial or False,
4938 ) = d.draw(seq_values_strategy(
4940 do_expl=impl_initial is None,
4942 obj = obj_initial(value, impl, expl, default, optional)
4943 value_expected = default if value is None else value
4945 default_initial if value_expected is None
4948 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4949 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4950 self.assertEqual(obj.expl_tag, expl or expl_initial)
4952 {} if obj.default is None else obj.default._value,
4953 getattr(default_initial if default is None else default, "_value", {}),
4955 if obj.default is None:
4956 optional = optional_initial if optional is None else optional
4957 optional = False if optional is None else optional
4960 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4961 self.assertEqual(obj.optional, optional)
4963 @given(data_strategy())
4964 def test_copy(self, d):
4965 class SeqInherited(self.base_klass):
4967 for klass in (self.base_klass, SeqInherited):
4968 values = d.draw(seq_values_strategy(seq_klass=klass))
4969 obj = klass(*values)
4970 obj_copied = obj.copy()
4971 self.assert_copied_basic_fields(obj, obj_copied)
4972 self.assertEqual(obj.specs, obj_copied.specs)
4973 self.assertEqual(obj._value, obj_copied._value)
4975 @given(data_strategy())
4976 def test_stripped(self, d):
4977 value = d.draw(integers())
4978 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4980 class Seq(self.base_klass):
4982 schema = (("whatever", Integer()),)
4984 seq["whatever"] = Integer(value)
4985 with self.assertRaises(NotEnoughData):
4986 seq.decode(seq.encode()[:-1])
4988 @given(data_strategy())
4989 def test_stripped_expl(self, d):
4990 value = d.draw(integers())
4991 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4993 class Seq(self.base_klass):
4995 schema = (("whatever", Integer()),)
4997 seq["whatever"] = Integer(value)
4998 with self.assertRaises(NotEnoughData):
4999 seq.decode(seq.encode()[:-1])
5001 @given(binary(min_size=2))
5002 def test_non_tag_mismatch_raised(self, junk):
5004 _, _, len_encoded = tag_strip(memoryview(junk))
5005 len_decode(len_encoded)
5011 class Seq(self.base_klass):
5013 ("whatever", Integer()),
5015 ("whenever", Integer()),
5018 seq["whatever"] = Integer(123)
5019 seq["junk"] = Any(junk)
5020 seq["whenever"] = Integer(123)
5021 with self.assertRaises(DecodeError):
5022 seq.decode(seq.encode())
5025 integers(min_value=31),
5026 integers(min_value=0),
5029 def test_bad_tag(self, tag, offset, decode_path):
5030 with self.assertRaises(DecodeError) as err:
5031 self.base_klass().decode(
5032 tag_encode(tag)[:-1],
5034 decode_path=decode_path,
5037 self.assertEqual(err.exception.offset, offset)
5038 self.assertEqual(err.exception.decode_path, decode_path)
5041 integers(min_value=128),
5042 integers(min_value=0),
5045 def test_bad_len(self, l, offset, decode_path):
5046 with self.assertRaises(DecodeError) as err:
5047 self.base_klass().decode(
5048 self.base_klass.tag_default + len_encode(l)[:-1],
5050 decode_path=decode_path,
5053 self.assertEqual(err.exception.offset, offset)
5054 self.assertEqual(err.exception.decode_path, decode_path)
5056 def _assert_expects(self, seq, expects):
5057 for expect in expects:
5059 seq.specs[expect["name"]].optional,
5062 if expect["default_value"] is not None:
5064 seq.specs[expect["name"]].default,
5065 expect["default_value"],
5067 if expect["presented"]:
5068 self.assertIn(expect["name"], seq)
5069 self.assertEqual(seq[expect["name"]], expect["value"])
5071 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5072 @given(data_strategy())
5073 def test_symmetric(self, d):
5074 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5075 tail_junk = d.draw(binary(max_size=5))
5076 self.assertTrue(seq.ready)
5077 self.assertFalse(seq.decoded)
5078 self._assert_expects(seq, expects)
5081 pprint(seq, big_blobs=True, with_decode_path=True)
5082 self.assertTrue(seq.ready)
5083 seq_encoded = seq.encode()
5084 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5085 self.assertFalse(seq_decoded.lenindef)
5086 self.assertFalse(seq_decoded.ber_encoded)
5087 self.assertFalse(seq_decoded.bered)
5089 t, _, lv = tag_strip(seq_encoded)
5090 _, _, v = len_decode(lv)
5091 seq_encoded_lenindef = t + LENINDEF + v + EOC
5092 ctx_copied = deepcopy(ctx_dummy)
5093 ctx_copied["bered"] = True
5094 seq_decoded_lenindef, tail_lenindef = seq.decode(
5095 seq_encoded_lenindef + tail_junk,
5098 del ctx_copied["bered"]
5099 self.assertDictEqual(ctx_copied, ctx_dummy)
5100 self.assertTrue(seq_decoded_lenindef.lenindef)
5101 self.assertTrue(seq_decoded_lenindef.bered)
5102 seq_decoded_lenindef = seq_decoded_lenindef.copy()
5103 self.assertTrue(seq_decoded_lenindef.lenindef)
5104 self.assertTrue(seq_decoded_lenindef.bered)
5105 with self.assertRaises(DecodeError):
5106 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5107 with self.assertRaises(DecodeError):
5108 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5109 repr(seq_decoded_lenindef)
5110 list(seq_decoded_lenindef.pps())
5111 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5112 self.assertTrue(seq_decoded_lenindef.ready)
5114 for decoded, decoded_tail, encoded in (
5115 (seq_decoded, tail, seq_encoded),
5116 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5118 self.assertEqual(decoded_tail, tail_junk)
5119 self._assert_expects(decoded, expects)
5120 self.assertEqual(seq, decoded)
5121 self.assertEqual(decoded.encode(), seq_encoded)
5122 self.assertEqual(decoded.tlvlen, len(encoded))
5123 for expect in expects:
5124 if not expect["presented"]:
5125 self.assertNotIn(expect["name"], decoded)
5127 self.assertIn(expect["name"], decoded)
5128 obj = decoded[expect["name"]]
5129 self.assertTrue(obj.decoded)
5130 offset = obj.expl_offset if obj.expled else obj.offset
5131 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5132 self.assertSequenceEqual(
5133 seq_encoded[offset:offset + tlvlen],
5137 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5138 @given(data_strategy())
5139 def test_symmetric_with_seq(self, d):
5140 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5141 self.assertTrue(seq.ready)
5142 seq_encoded = seq.encode()
5143 seq_decoded, tail = seq.decode(seq_encoded)
5144 self.assertEqual(tail, b"")
5145 self.assertTrue(seq.ready)
5146 self.assertEqual(seq, seq_decoded)
5147 self.assertEqual(seq_decoded.encode(), seq_encoded)
5148 for expect_outer in expect_outers:
5149 if not expect_outer["presented"]:
5150 self.assertNotIn(expect_outer["name"], seq_decoded)
5152 self.assertIn(expect_outer["name"], seq_decoded)
5153 obj = seq_decoded[expect_outer["name"]]
5154 self.assertTrue(obj.decoded)
5155 offset = obj.expl_offset if obj.expled else obj.offset
5156 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5157 self.assertSequenceEqual(
5158 seq_encoded[offset:offset + tlvlen],
5161 self._assert_expects(obj, expect_outer["expects"])
5163 @given(data_strategy())
5164 def test_default_disappears(self, d):
5165 _schema = list(d.draw(dictionaries(
5167 sets(integers(), min_size=2, max_size=2),
5171 class Seq(self.base_klass):
5173 (n, Integer(default=d))
5174 for n, (_, d) in _schema
5177 for name, (value, _) in _schema:
5178 seq[name] = Integer(value)
5179 self.assertEqual(len(seq._value), len(_schema))
5180 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5181 self.assertGreater(len(seq.encode()), len(empty_seq))
5182 for name, (_, default) in _schema:
5183 seq[name] = Integer(default)
5184 self.assertEqual(len(seq._value), 0)
5185 self.assertSequenceEqual(seq.encode(), empty_seq)
5187 @given(data_strategy())
5188 def test_encoded_default_not_accepted(self, d):
5189 _schema = list(d.draw(dictionaries(
5194 tags = [tag_encode(tag) for tag in d.draw(sets(
5195 integers(min_value=0),
5196 min_size=len(_schema),
5197 max_size=len(_schema),
5200 class SeqWithoutDefault(self.base_klass):
5202 (n, Integer(impl=t))
5203 for (n, _), t in zip(_schema, tags)
5205 seq_without_default = SeqWithoutDefault()
5206 for name, value in _schema:
5207 seq_without_default[name] = Integer(value)
5208 seq_encoded = seq_without_default.encode()
5210 class SeqWithDefault(self.base_klass):
5212 (n, Integer(default=v, impl=t))
5213 for (n, v), t in zip(_schema, tags)
5215 seq_with_default = SeqWithDefault()
5216 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5217 seq_with_default.decode(seq_encoded)
5218 for ctx in ({"bered": True}, {"allow_default_values": True}):
5219 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5220 self.assertTrue(seq_decoded.ber_encoded)
5221 self.assertTrue(seq_decoded.bered)
5222 seq_decoded = seq_decoded.copy()
5223 self.assertTrue(seq_decoded.ber_encoded)
5224 self.assertTrue(seq_decoded.bered)
5225 for name, value in _schema:
5226 self.assertEqual(seq_decoded[name], seq_with_default[name])
5227 self.assertEqual(seq_decoded[name], value)
5229 @given(data_strategy())
5230 def test_missing_from_spec(self, d):
5231 names = list(d.draw(sets(text_letters(), min_size=2)))
5232 tags = [tag_encode(tag) for tag in d.draw(sets(
5233 integers(min_value=0),
5234 min_size=len(names),
5235 max_size=len(names),
5237 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5239 class SeqFull(self.base_klass):
5240 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5241 seq_full = SeqFull()
5242 for i, name in enumerate(names):
5243 seq_full[name] = Integer(i)
5244 seq_encoded = seq_full.encode()
5245 altered = names_tags[:-2] + names_tags[-1:]
5247 class SeqMissing(self.base_klass):
5248 schema = [(n, Integer(impl=t)) for n, t in altered]
5249 seq_missing = SeqMissing()
5250 with self.assertRaises(TagMismatch):
5251 seq_missing.decode(seq_encoded)
5253 @given(data_strategy())
5254 def test_bered(self, d):
5255 class Seq(self.base_klass):
5256 schema = (("underlying", Boolean()),)
5257 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5258 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5259 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5260 self.assertFalse(decoded.ber_encoded)
5261 self.assertFalse(decoded.lenindef)
5262 self.assertTrue(decoded.bered)
5263 decoded = decoded.copy()
5264 self.assertFalse(decoded.ber_encoded)
5265 self.assertFalse(decoded.lenindef)
5266 self.assertTrue(decoded.bered)
5268 class Seq(self.base_klass):
5269 schema = (("underlying", OctetString()),)
5271 tag_encode(form=TagFormConstructed, num=4) +
5273 OctetString(b"whatever").encode() +
5276 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5277 with self.assertRaises(DecodeError):
5278 Seq().decode(encoded)
5279 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5280 self.assertFalse(decoded.ber_encoded)
5281 self.assertFalse(decoded.lenindef)
5282 self.assertTrue(decoded.bered)
5283 decoded = decoded.copy()
5284 self.assertFalse(decoded.ber_encoded)
5285 self.assertFalse(decoded.lenindef)
5286 self.assertTrue(decoded.bered)
5289 class TestSequence(SeqMixing, CommonMixin, TestCase):
5290 base_klass = Sequence
5296 def test_remaining(self, value, junk):
5297 class Seq(Sequence):
5299 ("whatever", Integer()),
5301 int_encoded = Integer(value).encode()
5303 Sequence.tag_default,
5304 len_encode(len(int_encoded + junk)),
5307 with assertRaisesRegex(self, DecodeError, "remaining"):
5308 Seq().decode(junked)
5310 @given(sets(text_letters(), min_size=2))
5311 def test_obj_unknown(self, names):
5312 missing = names.pop()
5314 class Seq(Sequence):
5315 schema = [(n, Boolean()) for n in names]
5317 with self.assertRaises(ObjUnknown) as err:
5320 with self.assertRaises(ObjUnknown) as err:
5321 seq[missing] = Boolean()
5324 def test_x690_vector(self):
5325 class Seq(Sequence):
5327 ("name", IA5String()),
5330 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5331 self.assertEqual(seq["name"], "Smith")
5332 self.assertEqual(seq["ok"], True)
5335 class TestSet(SeqMixing, CommonMixin, TestCase):
5338 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5339 @given(data_strategy())
5340 def test_sorted(self, d):
5342 tag_encode(tag) for tag in
5343 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5347 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5349 for name, _ in Seq.schema:
5350 seq[name] = OctetString(b"")
5351 seq_encoded = seq.encode()
5352 seq_decoded, _ = seq.decode(seq_encoded)
5353 self.assertSequenceEqual(
5354 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5355 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5358 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5359 @given(data_strategy())
5360 def test_unsorted(self, d):
5362 tag_encode(tag) for tag in
5363 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5365 tags = d.draw(permutations(tags))
5366 assume(tags != sorted(tags))
5367 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5368 seq_encoded = b"".join((
5370 len_encode(len(encoded)),
5375 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5377 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5378 seq.decode(seq_encoded)
5379 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5380 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5381 self.assertTrue(seq_decoded.ber_encoded)
5382 self.assertTrue(seq_decoded.bered)
5383 seq_decoded = seq_decoded.copy()
5384 self.assertTrue(seq_decoded.ber_encoded)
5385 self.assertTrue(seq_decoded.bered)
5386 self.assertSequenceEqual(
5387 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5393 def seqof_values_strategy(draw, schema=None, do_expl=False):
5395 schema = draw(sampled_from((Boolean(), Integer())))
5396 bound_min, bound_max = sorted(draw(sets(
5397 integers(min_value=0, max_value=10),
5401 if isinstance(schema, Boolean):
5402 values_generator = booleans().map(Boolean)
5403 elif isinstance(schema, Integer):
5404 values_generator = integers().map(Integer)
5405 values_generator = lists(
5410 values = draw(one_of(none(), values_generator))
5414 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5416 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5417 default = draw(one_of(none(), values_generator))
5418 optional = draw(one_of(none(), booleans()))
5420 draw(integers(min_value=0)),
5421 draw(integers(min_value=0)),
5422 draw(integers(min_value=0)),
5427 (bound_min, bound_max),
5436 class SeqOfMixing(object):
5437 def test_invalid_value_type(self):
5438 with self.assertRaises(InvalidValueType) as err:
5439 self.base_klass(123)
5442 def test_invalid_values_type(self):
5443 class SeqOf(self.base_klass):
5445 with self.assertRaises(InvalidValueType) as err:
5446 SeqOf([Integer(123), Boolean(False), Integer(234)])
5449 def test_schema_required(self):
5450 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5451 self.base_klass.__mro__[1]()
5453 @given(booleans(), booleans(), binary(), binary())
5454 def test_comparison(self, value1, value2, tag1, tag2):
5455 class SeqOf(self.base_klass):
5457 obj1 = SeqOf([Boolean(value1)])
5458 obj2 = SeqOf([Boolean(value2)])
5459 self.assertEqual(obj1 == obj2, value1 == value2)
5460 self.assertEqual(obj1 != obj2, value1 != value2)
5461 self.assertEqual(obj1 == list(obj2), value1 == value2)
5462 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5463 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5464 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5465 self.assertEqual(obj1 == obj2, tag1 == tag2)
5466 self.assertEqual(obj1 != obj2, tag1 != tag2)
5468 @given(lists(booleans()))
5469 def test_iter(self, values):
5470 class SeqOf(self.base_klass):
5472 obj = SeqOf([Boolean(value) for value in values])
5473 self.assertEqual(len(obj), len(values))
5474 for i, value in enumerate(obj):
5475 self.assertEqual(value, values[i])
5477 @given(data_strategy())
5478 def test_ready(self, d):
5479 ready = [Integer(v) for v in d.draw(lists(
5486 range(d.draw(integers(min_value=1, max_value=5)))
5489 class SeqOf(self.base_klass):
5491 values = d.draw(permutations(ready + non_ready))
5493 for value in values:
5495 self.assertFalse(seqof.ready)
5498 pprint(seqof, big_blobs=True, with_decode_path=True)
5499 with self.assertRaises(ObjNotReady) as err:
5502 for i, value in enumerate(values):
5503 self.assertEqual(seqof[i], value)
5504 if not seqof[i].ready:
5505 seqof[i] = Integer(i)
5506 self.assertTrue(seqof.ready)
5509 pprint(seqof, big_blobs=True, with_decode_path=True)
5511 def test_spec_mismatch(self):
5512 class SeqOf(self.base_klass):
5515 seqof.append(Integer(123))
5516 with self.assertRaises(ValueError):
5517 seqof.append(Boolean(False))
5518 with self.assertRaises(ValueError):
5519 seqof[0] = Boolean(False)
5521 @given(data_strategy())
5522 def test_bounds_satisfied(self, d):
5523 class SeqOf(self.base_klass):
5525 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5526 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5527 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5528 SeqOf(value=value, bounds=(bound_min, bound_max))
5530 @given(data_strategy())
5531 def test_bounds_unsatisfied(self, d):
5532 class SeqOf(self.base_klass):
5534 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5535 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5536 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5537 with self.assertRaises(BoundsError) as err:
5538 SeqOf(value=value, bounds=(bound_min, bound_max))
5540 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5541 SeqOf(bounds=(bound_min, bound_max)).decode(
5542 SeqOf(value).encode()
5545 value = [Boolean(True)] * d.draw(integers(
5546 min_value=bound_max + 1,
5547 max_value=bound_max + 10,
5549 with self.assertRaises(BoundsError) as err:
5550 SeqOf(value=value, bounds=(bound_min, bound_max))
5552 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5553 SeqOf(bounds=(bound_min, bound_max)).decode(
5554 SeqOf(value).encode()
5558 @given(integers(min_value=1, max_value=10))
5559 def test_out_of_bounds(self, bound_max):
5560 class SeqOf(self.base_klass):
5562 bounds = (0, bound_max)
5564 for _ in range(bound_max):
5565 seqof.append(Integer(123))
5566 with self.assertRaises(BoundsError):
5567 seqof.append(Integer(123))
5569 @given(data_strategy())
5570 def test_call(self, d):
5580 ) = d.draw(seqof_values_strategy())
5582 class SeqOf(self.base_klass):
5583 schema = schema_initial
5584 obj_initial = SeqOf(
5585 value=value_initial,
5586 bounds=bounds_initial,
5589 default=default_initial,
5590 optional=optional_initial or False,
5591 _decoded=_decoded_initial,
5602 ) = d.draw(seqof_values_strategy(
5603 schema=schema_initial,
5604 do_expl=impl_initial is None,
5606 if (default is None) and (obj_initial.default is not None):
5609 (bounds is None) and
5610 (value is not None) and
5611 (bounds_initial is not None) and
5612 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5616 (bounds is None) and
5617 (default is not None) and
5618 (bounds_initial is not None) and
5619 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5631 value_expected = default if value is None else value
5633 default_initial if value_expected is None
5636 value_expected = () if value_expected is None else value_expected
5637 self.assertEqual(obj, value_expected)
5638 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5639 self.assertEqual(obj.expl_tag, expl or expl_initial)
5642 default_initial if default is None else default,
5644 if obj.default is None:
5645 optional = optional_initial if optional is None else optional
5646 optional = False if optional is None else optional
5649 self.assertEqual(obj.optional, optional)
5651 (obj._bound_min, obj._bound_max),
5652 bounds or bounds_initial or (0, float("+inf")),
5655 @given(seqof_values_strategy())
5656 def test_copy(self, values):
5657 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5659 class SeqOf(self.base_klass):
5667 optional=optional or False,
5670 obj_copied = obj.copy()
5671 self.assert_copied_basic_fields(obj, obj_copied)
5672 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5673 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5674 self.assertEqual(obj._value, obj_copied._value)
5678 integers(min_value=1).map(tag_encode),
5680 def test_stripped(self, values, tag_impl):
5681 class SeqOf(self.base_klass):
5682 schema = OctetString()
5683 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5684 with self.assertRaises(NotEnoughData):
5685 obj.decode(obj.encode()[:-1])
5689 integers(min_value=1).map(tag_ctxc),
5691 def test_stripped_expl(self, values, tag_expl):
5692 class SeqOf(self.base_klass):
5693 schema = OctetString()
5694 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5695 with self.assertRaises(NotEnoughData):
5696 obj.decode(obj.encode()[:-1])
5699 integers(min_value=31),
5700 integers(min_value=0),
5703 def test_bad_tag(self, tag, offset, decode_path):
5704 with self.assertRaises(DecodeError) as err:
5705 self.base_klass().decode(
5706 tag_encode(tag)[:-1],
5708 decode_path=decode_path,
5711 self.assertEqual(err.exception.offset, offset)
5712 self.assertEqual(err.exception.decode_path, decode_path)
5715 integers(min_value=128),
5716 integers(min_value=0),
5719 def test_bad_len(self, l, offset, decode_path):
5720 with self.assertRaises(DecodeError) as err:
5721 self.base_klass().decode(
5722 self.base_klass.tag_default + len_encode(l)[:-1],
5724 decode_path=decode_path,
5727 self.assertEqual(err.exception.offset, offset)
5728 self.assertEqual(err.exception.decode_path, decode_path)
5730 @given(binary(min_size=1))
5731 def test_tag_mismatch(self, impl):
5732 assume(impl != self.base_klass.tag_default)
5733 with self.assertRaises(TagMismatch):
5734 self.base_klass(impl=impl).decode(self.base_klass().encode())
5736 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5738 seqof_values_strategy(schema=Integer()),
5739 lists(integers().map(Integer)),
5740 integers(min_value=1).map(tag_ctxc),
5741 integers(min_value=0),
5744 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5745 _, _, _, _, _, default, optional, _decoded = values
5747 class SeqOf(self.base_klass):
5757 pprint(obj, big_blobs=True, with_decode_path=True)
5758 self.assertFalse(obj.expled)
5759 obj_encoded = obj.encode()
5760 obj_expled = obj(value, expl=tag_expl)
5761 self.assertTrue(obj_expled.expled)
5763 list(obj_expled.pps())
5764 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5765 obj_expled_encoded = obj_expled.encode()
5766 ctx_copied = deepcopy(ctx_dummy)
5767 obj_decoded, tail = obj_expled.decode(
5768 obj_expled_encoded + tail_junk,
5772 self.assertDictEqual(ctx_copied, ctx_dummy)
5774 list(obj_decoded.pps())
5775 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5776 self.assertEqual(tail, tail_junk)
5777 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5778 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5779 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5780 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5782 obj_decoded.expl_llen,
5783 len(len_encode(len(obj_encoded))),
5785 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5786 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5789 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5791 self.assertEqual(obj_decoded.expl_offset, offset)
5792 for obj_inner in obj_decoded:
5793 self.assertIn(obj_inner, obj_decoded)
5794 self.assertSequenceEqual(
5797 obj_inner.offset - offset:
5798 obj_inner.offset + obj_inner.tlvlen - offset
5802 t, _, lv = tag_strip(obj_encoded)
5803 _, _, v = len_decode(lv)
5804 obj_encoded_lenindef = t + LENINDEF + v + EOC
5805 obj_decoded_lenindef, tail_lenindef = obj.decode(
5806 obj_encoded_lenindef + tail_junk,
5807 ctx={"bered": True},
5809 self.assertTrue(obj_decoded_lenindef.lenindef)
5810 self.assertTrue(obj_decoded_lenindef.bered)
5811 obj_decoded_lenindef = obj_decoded_lenindef.copy()
5812 self.assertTrue(obj_decoded_lenindef.lenindef)
5813 self.assertTrue(obj_decoded_lenindef.bered)
5814 repr(obj_decoded_lenindef)
5815 list(obj_decoded_lenindef.pps())
5816 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5817 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5818 with self.assertRaises(DecodeError):
5819 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5820 with self.assertRaises(DecodeError):
5821 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5823 @given(data_strategy())
5824 def test_bered(self, d):
5825 class SeqOf(self.base_klass):
5827 encoded = Boolean(False).encode()
5828 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5829 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5830 with self.assertRaises(DecodeError):
5831 SeqOf().decode(encoded)
5832 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5833 self.assertFalse(decoded.ber_encoded)
5834 self.assertFalse(decoded.lenindef)
5835 self.assertTrue(decoded.bered)
5836 decoded = decoded.copy()
5837 self.assertFalse(decoded.ber_encoded)
5838 self.assertFalse(decoded.lenindef)
5839 self.assertTrue(decoded.bered)
5841 class SeqOf(self.base_klass):
5842 schema = OctetString()
5843 encoded = OctetString(b"whatever").encode()
5845 tag_encode(form=TagFormConstructed, num=4) +
5847 OctetString(b"whatever").encode() +
5850 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5851 with self.assertRaises(DecodeError):
5852 SeqOf().decode(encoded)
5853 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5854 self.assertFalse(decoded.ber_encoded)
5855 self.assertFalse(decoded.lenindef)
5856 self.assertTrue(decoded.bered)
5857 decoded = decoded.copy()
5858 self.assertFalse(decoded.ber_encoded)
5859 self.assertFalse(decoded.lenindef)
5860 self.assertTrue(decoded.bered)
5863 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5864 class SeqOf(SequenceOf):
5868 def _test_symmetric_compare_objs(self, obj1, obj2):
5869 self.assertEqual(obj1, obj2)
5870 self.assertSequenceEqual(list(obj1), list(obj2))
5873 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5878 def _test_symmetric_compare_objs(self, obj1, obj2):
5879 self.assertSetEqual(
5880 set(int(v) for v in obj1),
5881 set(int(v) for v in obj2),
5884 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5885 @given(data_strategy())
5886 def test_sorted(self, d):
5887 values = [OctetString(v) for v in d.draw(lists(binary()))]
5890 schema = OctetString()
5892 seq_encoded = seq.encode()
5893 seq_decoded, _ = seq.decode(seq_encoded)
5894 self.assertSequenceEqual(
5895 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5896 b"".join(sorted([v.encode() for v in values])),
5899 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5900 @given(data_strategy())
5901 def test_unsorted(self, d):
5902 values = [OctetString(v).encode() for v in d.draw(sets(
5903 binary(min_size=1, max_size=5),
5907 values = d.draw(permutations(values))
5908 assume(values != sorted(values))
5909 encoded = b"".join(values)
5910 seq_encoded = b"".join((
5912 len_encode(len(encoded)),
5917 schema = OctetString()
5919 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5920 seq.decode(seq_encoded)
5922 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5923 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5924 self.assertTrue(seq_decoded.ber_encoded)
5925 self.assertTrue(seq_decoded.bered)
5926 seq_decoded = seq_decoded.copy()
5927 self.assertTrue(seq_decoded.ber_encoded)
5928 self.assertTrue(seq_decoded.bered)
5929 self.assertSequenceEqual(
5930 [obj.encode() for obj in seq_decoded],
5935 class TestGoMarshalVectors(TestCase):
5937 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5938 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5939 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5940 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5941 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5943 class Seq(Sequence):
5945 ("erste", Integer()),
5946 ("zweite", Integer(optional=True))
5949 seq["erste"] = Integer(64)
5950 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5951 seq["erste"] = Integer(0x123456)
5952 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5953 seq["erste"] = Integer(64)
5954 seq["zweite"] = Integer(65)
5955 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5957 class NestedSeq(Sequence):
5961 seq["erste"] = Integer(127)
5962 seq["zweite"] = None
5963 nested = NestedSeq()
5964 nested["nest"] = seq
5965 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5967 self.assertSequenceEqual(
5968 OctetString(b"\x01\x02\x03").encode(),
5969 hexdec("0403010203"),
5972 class Seq(Sequence):
5974 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5977 seq["erste"] = Integer(64)
5978 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5980 class Seq(Sequence):
5982 ("erste", Integer(expl=tag_ctxc(5))),
5985 seq["erste"] = Integer(64)
5986 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5988 class Seq(Sequence):
5991 impl=tag_encode(0, klass=TagClassContext),
5996 seq["erste"] = Null()
5997 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5999 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6001 self.assertSequenceEqual(
6002 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6003 hexdec("170d3730303130313030303030305a"),
6005 self.assertSequenceEqual(
6006 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6007 hexdec("170d3039313131353232353631365a"),
6009 self.assertSequenceEqual(
6010 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6011 hexdec("180f32313030303430353132303130315a"),
6014 class Seq(Sequence):
6016 ("erste", GeneralizedTime()),
6019 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6020 self.assertSequenceEqual(
6022 hexdec("3011180f32303039313131353232353631365a"),
6025 self.assertSequenceEqual(
6026 BitString((1, b"\x80")).encode(),
6029 self.assertSequenceEqual(
6030 BitString((12, b"\x81\xF0")).encode(),
6031 hexdec("03030481f0"),
6034 self.assertSequenceEqual(
6035 ObjectIdentifier("1.2.3.4").encode(),
6036 hexdec("06032a0304"),
6038 self.assertSequenceEqual(
6039 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6040 hexdec("06092a864888932d010105"),
6042 self.assertSequenceEqual(
6043 ObjectIdentifier("2.100.3").encode(),
6044 hexdec("0603813403"),
6047 self.assertSequenceEqual(
6048 PrintableString("test").encode(),
6049 hexdec("130474657374"),
6051 self.assertSequenceEqual(
6052 PrintableString("x" * 127).encode(),
6053 hexdec("137F" + "78" * 127),
6055 self.assertSequenceEqual(
6056 PrintableString("x" * 128).encode(),
6057 hexdec("138180" + "78" * 128),
6059 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6061 class Seq(Sequence):
6063 ("erste", IA5String()),
6066 seq["erste"] = IA5String("test")
6067 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6069 class Seq(Sequence):
6071 ("erste", PrintableString()),
6074 seq["erste"] = PrintableString("test")
6075 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6076 # Asterisk is actually not allowable
6077 PrintableString._allowable_chars |= set(b"*")
6078 seq["erste"] = PrintableString("test*")
6079 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6080 PrintableString._allowable_chars -= set(b"*")
6082 class Seq(Sequence):
6084 ("erste", Any(optional=True)),
6085 ("zweite", Integer()),
6088 seq["zweite"] = Integer(64)
6089 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6094 seq.append(Integer(10))
6095 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6097 class _SeqOf(SequenceOf):
6098 schema = PrintableString()
6100 class SeqOf(SequenceOf):
6103 _seqof.append(PrintableString("1"))
6105 seqof.append(_seqof)
6106 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6108 class Seq(Sequence):
6110 ("erste", Integer(default=1)),
6113 seq["erste"] = Integer(0)
6114 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6115 seq["erste"] = Integer(1)
6116 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6117 seq["erste"] = Integer(2)
6118 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6121 class TestPP(TestCase):
6122 @given(data_strategy())
6123 def test_oid_printing(self, d):
6125 str(ObjectIdentifier(k)): v * 2
6126 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6128 chosen = d.draw(sampled_from(sorted(oids)))
6129 chosen_id = oids[chosen]
6130 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6131 self.assertNotIn(chosen_id, pp_console_row(pp))
6134 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6138 class TestAutoAddSlots(TestCase):
6140 class Inher(Integer):
6143 with self.assertRaises(AttributeError):
6145 inher.unexistent = "whatever"
6148 class TestOIDDefines(TestCase):
6149 @given(data_strategy())
6150 def runTest(self, d):
6151 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6152 value_name_chosen = d.draw(sampled_from(value_names))
6154 ObjectIdentifier(oid)
6155 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6157 oid_chosen = d.draw(sampled_from(oids))
6158 values = d.draw(lists(
6160 min_size=len(value_names),
6161 max_size=len(value_names),
6164 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6165 oid: Integer() for oid in oids[:-1]
6168 for i, value_name in enumerate(value_names):
6169 _schema.append((value_name, Any(expl=tag_ctxp(i))))
6171 class Seq(Sequence):
6174 for value_name, value in zip(value_names, values):
6175 seq[value_name] = Any(Integer(value).encode())
6176 seq["type"] = oid_chosen
6177 seq, _ = Seq().decode(seq.encode())
6178 for value_name in value_names:
6179 if value_name == value_name_chosen:
6181 self.assertIsNone(seq[value_name].defined)
6182 if value_name_chosen in oids[:-1]:
6183 self.assertIsNotNone(seq[value_name_chosen].defined)
6184 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6185 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6188 pprint(seq, big_blobs=True, with_decode_path=True)
6191 class TestDefinesByPath(TestCase):
6192 def test_generated(self):
6193 class Seq(Sequence):
6195 ("type", ObjectIdentifier()),
6196 ("value", OctetString(expl=tag_ctxc(123))),
6199 class SeqInner(Sequence):
6201 ("typeInner", ObjectIdentifier()),
6202 ("valueInner", Any()),
6205 class PairValue(SetOf):
6208 class Pair(Sequence):
6210 ("type", ObjectIdentifier()),
6211 ("value", PairValue()),
6214 class Pairs(SequenceOf):
6221 type_octet_stringed,
6223 ObjectIdentifier(oid)
6224 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6226 seq_integered = Seq()
6227 seq_integered["type"] = type_integered
6228 seq_integered["value"] = OctetString(Integer(123).encode())
6229 seq_integered_raw = seq_integered.encode()
6233 (type_octet_stringed, OctetString(b"whatever")),
6234 (type_integered, Integer(123)),
6235 (type_octet_stringed, OctetString(b"whenever")),
6236 (type_integered, Integer(234)),
6238 for t, v in pairs_input:
6241 pair["value"] = PairValue((Any(v),))
6243 seq_inner = SeqInner()
6244 seq_inner["typeInner"] = type_innered
6245 seq_inner["valueInner"] = Any(pairs)
6246 seq_sequenced = Seq()
6247 seq_sequenced["type"] = type_sequenced
6248 seq_sequenced["value"] = OctetString(seq_inner.encode())
6249 seq_sequenced_raw = seq_sequenced.encode()
6251 list(seq_sequenced.pps())
6252 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6254 defines_by_path = []
6255 ctx_copied = deepcopy(ctx_dummy)
6256 seq_integered, _ = Seq().decode(
6260 self.assertDictEqual(ctx_copied, ctx_dummy)
6261 self.assertIsNone(seq_integered["value"].defined)
6262 defines_by_path.append(
6263 (("type",), ((("value",), {
6264 type_integered: Integer(),
6265 type_sequenced: SeqInner(),
6268 ctx_copied["defines_by_path"] = defines_by_path
6269 seq_integered, _ = Seq().decode(
6273 del ctx_copied["defines_by_path"]
6274 self.assertDictEqual(ctx_copied, ctx_dummy)
6275 self.assertIsNotNone(seq_integered["value"].defined)
6276 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6277 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6278 self.assertTrue(seq_integered_raw[
6279 seq_integered["value"].defined[1].offset:
6280 ].startswith(Integer(123).encode()))
6282 list(seq_integered.pps())
6283 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6285 ctx_copied["defines_by_path"] = defines_by_path
6286 seq_sequenced, _ = Seq().decode(
6290 del ctx_copied["defines_by_path"]
6291 self.assertDictEqual(ctx_copied, ctx_dummy)
6292 self.assertIsNotNone(seq_sequenced["value"].defined)
6293 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6294 seq_inner = seq_sequenced["value"].defined[1]
6295 self.assertIsNone(seq_inner["valueInner"].defined)
6297 list(seq_sequenced.pps())
6298 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6300 defines_by_path.append((
6301 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6302 ((("valueInner",), {type_innered: Pairs()}),),
6304 ctx_copied["defines_by_path"] = defines_by_path
6305 seq_sequenced, _ = Seq().decode(
6309 del ctx_copied["defines_by_path"]
6310 self.assertDictEqual(ctx_copied, ctx_dummy)
6311 self.assertIsNotNone(seq_sequenced["value"].defined)
6312 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6313 seq_inner = seq_sequenced["value"].defined[1]
6314 self.assertIsNotNone(seq_inner["valueInner"].defined)
6315 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6316 pairs = seq_inner["valueInner"].defined[1]
6318 self.assertIsNone(pair["value"][0].defined)
6320 list(seq_sequenced.pps())
6321 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6323 defines_by_path.append((
6326 DecodePathDefBy(type_sequenced),
6328 DecodePathDefBy(type_innered),
6333 type_integered: Integer(),
6334 type_octet_stringed: OctetString(),
6337 ctx_copied["defines_by_path"] = defines_by_path
6338 seq_sequenced, _ = Seq().decode(
6342 del ctx_copied["defines_by_path"]
6343 self.assertDictEqual(ctx_copied, ctx_dummy)
6344 self.assertIsNotNone(seq_sequenced["value"].defined)
6345 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6346 seq_inner = seq_sequenced["value"].defined[1]
6347 self.assertIsNotNone(seq_inner["valueInner"].defined)
6348 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6349 pairs_got = seq_inner["valueInner"].defined[1]
6350 for pair_input, pair_got in zip(pairs_input, pairs_got):
6351 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6352 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6354 list(seq_sequenced.pps())
6355 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6357 @given(oid_strategy(), integers())
6358 def test_simple(self, oid, tgt):
6359 class Inner(Sequence):
6361 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6362 ObjectIdentifier(oid): Integer(),
6366 class Outer(Sequence):
6369 ("tgt", OctetString()),
6373 inner["oid"] = ObjectIdentifier(oid)
6375 outer["inner"] = inner
6376 outer["tgt"] = OctetString(Integer(tgt).encode())
6377 decoded, _ = Outer().decode(outer.encode())
6378 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6381 class TestAbsDecodePath(TestCase):
6383 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6384 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6386 def test_concat(self, decode_path, rel_path):
6387 self.assertSequenceEqual(
6388 abs_decode_path(decode_path, rel_path),
6389 decode_path + rel_path,
6393 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6394 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6396 def test_abs(self, decode_path, rel_path):
6397 self.assertSequenceEqual(
6398 abs_decode_path(decode_path, ("/",) + rel_path),
6403 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6404 integers(min_value=1, max_value=3),
6405 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6407 def test_dots(self, decode_path, number_of_dots, rel_path):
6408 self.assertSequenceEqual(
6409 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6410 decode_path[:-number_of_dots] + rel_path,
6414 class TestStrictDefaultExistence(TestCase):
6415 @given(data_strategy())
6416 def runTest(self, d):
6417 count = d.draw(integers(min_value=1, max_value=10))
6418 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6420 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6421 for i in range(count)
6423 for klass in (Sequence, Set):
6427 for i in range(count):
6428 seq["int%d" % i] = Integer(123)
6430 chosen_choice = "int%d" % chosen
6431 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6432 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6434 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6435 self.assertTrue(decoded.ber_encoded)
6436 self.assertTrue(decoded.bered)
6437 decoded = decoded.copy()
6438 self.assertTrue(decoded.ber_encoded)
6439 self.assertTrue(decoded.bered)
6440 decoded, _ = seq.decode(raw, ctx={"bered": True})
6441 self.assertTrue(decoded.ber_encoded)
6442 self.assertTrue(decoded.bered)
6443 decoded = decoded.copy()
6444 self.assertTrue(decoded.ber_encoded)
6445 self.assertTrue(decoded.bered)
6448 class TestX690PrefixedType(TestCase):
6450 self.assertSequenceEqual(
6451 VisibleString("Jones").encode(),
6452 hexdec("1A054A6F6E6573"),
6454 self.assertSequenceEqual(
6457 impl=tag_encode(3, klass=TagClassApplication),
6459 hexdec("43054A6F6E6573"),
6461 self.assertSequenceEqual(
6465 impl=tag_encode(3, klass=TagClassApplication),
6469 hexdec("A20743054A6F6E6573"),
6471 self.assertSequenceEqual(
6475 impl=tag_encode(3, klass=TagClassApplication),
6477 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6479 hexdec("670743054A6F6E6573"),
6481 self.assertSequenceEqual(
6482 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6483 hexdec("82054A6F6E6573"),
6487 class TestExplOOB(TestCase):
6489 expl = tag_ctxc(123)
6490 raw = Integer(123).encode() + Integer(234).encode()
6491 raw = b"".join((expl, len_encode(len(raw)), raw))
6492 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6493 Integer(expl=expl).decode(raw)
6494 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})