2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from datetime import datetime
20 from string import ascii_letters
21 from string import digits
22 from string import printable
23 from string import whitespace
24 from unittest import TestCase
26 from hypothesis import assume
27 from hypothesis import given
28 from hypothesis import settings
29 from hypothesis.strategies import binary
30 from hypothesis.strategies import booleans
31 from hypothesis.strategies import composite
32 from hypothesis.strategies import data as data_strategy
33 from hypothesis.strategies import datetimes
34 from hypothesis.strategies import dictionaries
35 from hypothesis.strategies import integers
36 from hypothesis.strategies import just
37 from hypothesis.strategies import lists
38 from hypothesis.strategies import none
39 from hypothesis.strategies import one_of
40 from hypothesis.strategies import permutations
41 from hypothesis.strategies import sampled_from
42 from hypothesis.strategies import sets
43 from hypothesis.strategies import text
44 from hypothesis.strategies import tuples
45 from six import assertRaisesRegex
46 from six import binary_type
47 from six import byte2int
48 from six import indexbytes
49 from six import int2byte
50 from six import iterbytes
52 from six import text_type
53 from six import unichr as six_unichr
55 from pyderasn import _pp
56 from pyderasn import abs_decode_path
57 from pyderasn import Any
58 from pyderasn import BitString
59 from pyderasn import BMPString
60 from pyderasn import Boolean
61 from pyderasn import BoundsError
62 from pyderasn import Choice
63 from pyderasn import DecodeError
64 from pyderasn import DecodePathDefBy
65 from pyderasn import Enumerated
66 from pyderasn import EOC
67 from pyderasn import EOC_LEN
68 from pyderasn import GeneralizedTime
69 from pyderasn import GeneralString
70 from pyderasn import GraphicString
71 from pyderasn import hexdec
72 from pyderasn import hexenc
73 from pyderasn import IA5String
74 from pyderasn import Integer
75 from pyderasn import InvalidLength
76 from pyderasn import InvalidOID
77 from pyderasn import InvalidValueType
78 from pyderasn import len_decode
79 from pyderasn import len_encode
80 from pyderasn import LEN_YYMMDDHHMMSSZ
81 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
82 from pyderasn import LEN_YYYYMMDDHHMMSSZ
83 from pyderasn import LENINDEF
84 from pyderasn import LenIndefForm
85 from pyderasn import NotEnoughData
86 from pyderasn import Null
87 from pyderasn import NumericString
88 from pyderasn import ObjectIdentifier
89 from pyderasn import ObjNotReady
90 from pyderasn import ObjUnknown
91 from pyderasn import OctetString
92 from pyderasn import pp_console_row
93 from pyderasn import pprint
94 from pyderasn import PrintableString
95 from pyderasn import Sequence
96 from pyderasn import SequenceOf
97 from pyderasn import Set
98 from pyderasn import SetOf
99 from pyderasn import tag_ctxc
100 from pyderasn import tag_ctxp
101 from pyderasn import tag_decode
102 from pyderasn import tag_encode
103 from pyderasn import tag_strip
104 from pyderasn import TagClassApplication
105 from pyderasn import TagClassContext
106 from pyderasn import TagClassPrivate
107 from pyderasn import TagClassUniversal
108 from pyderasn import TagFormConstructed
109 from pyderasn import TagFormPrimitive
110 from pyderasn import TagMismatch
111 from pyderasn import TeletexString
112 from pyderasn import UniversalString
113 from pyderasn import UTCTime
114 from pyderasn import UTF8String
115 from pyderasn import VideotexString
116 from pyderasn import VisibleString
119 settings.register_profile("local", settings(
122 settings.load_profile("local")
123 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
125 tag_classes = sampled_from((
131 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
132 decode_path_strat = lists(integers(), max_size=3).map(
133 lambda decode_path: tuple(str(dp) for dp in decode_path)
137 class TestHex(TestCase):
139 def test_symmetric(self, data):
140 self.assertEqual(hexdec(hexenc(data)), data)
143 class TestTagCoder(TestCase):
144 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
148 integers(min_value=0, max_value=30),
151 def test_short(self, klass, form, num, junk):
152 raw = tag_encode(klass=klass, form=form, num=num)
153 self.assertEqual(tag_decode(raw), (klass, form, num))
154 self.assertEqual(len(raw), 1)
156 byte2int(tag_encode(klass=klass, form=form, num=0)),
157 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
159 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
160 self.assertSequenceEqual(stripped.tobytes(), raw)
161 self.assertEqual(tlen, len(raw))
162 self.assertSequenceEqual(tail, junk)
164 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
168 integers(min_value=31),
171 def test_long(self, klass, form, num, junk):
172 raw = tag_encode(klass=klass, form=form, num=num)
173 self.assertEqual(tag_decode(raw), (klass, form, num))
174 self.assertGreater(len(raw), 1)
176 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
179 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
180 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
181 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
182 self.assertSequenceEqual(stripped.tobytes(), raw)
183 self.assertEqual(tlen, len(raw))
184 self.assertSequenceEqual(tail, junk)
186 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
187 @given(integers(min_value=31))
188 def test_unfinished_tag(self, num):
189 raw = bytearray(tag_encode(num=num))
190 for i in range(1, len(raw)):
192 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
193 tag_strip(bytes(raw))
195 def test_go_vectors_valid(self):
196 for data, (eklass, etag, elen, eform) in (
197 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
198 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
199 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
200 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
201 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
202 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
203 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
204 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
205 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
206 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
208 tag, _, len_encoded = tag_strip(memoryview(data))
209 klass, form, num = tag_decode(tag)
210 _len, _, tail = len_decode(len_encoded)
211 self.assertSequenceEqual(tail, b"")
212 self.assertEqual(klass, eklass)
213 self.assertEqual(num, etag)
214 self.assertEqual(_len, elen)
215 self.assertEqual(form, eform)
217 def test_go_vectors_invalid(self):
225 with self.assertRaises(DecodeError):
226 _, _, len_encoded = tag_strip(memoryview(data))
227 len_decode(len_encoded)
230 integers(min_value=0, max_value=127),
231 integers(min_value=0, max_value=2),
233 def test_long_instead_of_short(self, l, dummy_num):
234 octets = (b"\x00" * dummy_num) + int2byte(l)
235 octets = int2byte((dummy_num + 1) | 0x80) + octets
236 with self.assertRaises(DecodeError):
240 class TestLenCoder(TestCase):
241 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
243 integers(min_value=0, max_value=127),
246 def test_short(self, l, junk):
247 raw = len_encode(l) + junk
248 decoded, llen, tail = len_decode(memoryview(raw))
249 self.assertEqual(decoded, l)
250 self.assertEqual(llen, 1)
251 self.assertEqual(len(raw), 1 + len(junk))
252 self.assertEqual(tail.tobytes(), junk)
254 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
256 integers(min_value=128),
259 def test_long(self, l, junk):
260 raw = len_encode(l) + junk
261 decoded, llen, tail = len_decode(memoryview(raw))
262 self.assertEqual(decoded, l)
263 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
264 self.assertEqual(llen, len(raw) - len(junk))
265 self.assertNotEqual(indexbytes(raw, 1), 0)
266 self.assertSequenceEqual(tail.tobytes(), junk)
268 def test_empty(self):
269 with self.assertRaises(NotEnoughData):
272 @given(integers(min_value=128))
273 def test_stripped(self, _len):
274 with self.assertRaises(NotEnoughData):
275 len_decode(len_encode(_len)[:-1])
278 text_printable = text(alphabet=printable, min_size=1)
282 def text_letters(draw):
283 result = draw(text(alphabet=ascii_letters, min_size=1))
285 result = result.encode("ascii")
289 class CommonMixin(object):
290 def test_tag_default(self):
291 obj = self.base_klass()
292 self.assertEqual(obj.tag, obj.tag_default)
294 def test_simultaneous_impl_expl(self):
295 with self.assertRaises(ValueError):
296 self.base_klass(impl=b"whatever", expl=b"whenever")
298 @given(binary(min_size=1), integers(), integers(), integers())
299 def test_decoded(self, impl, offset, llen, vlen):
300 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
301 self.assertEqual(obj.offset, offset)
302 self.assertEqual(obj.llen, llen)
303 self.assertEqual(obj.vlen, vlen)
304 self.assertEqual(obj.tlen, len(impl))
305 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
307 @given(binary(min_size=1))
308 def test_impl_inherited(self, impl_tag):
309 class Inherited(self.base_klass):
312 self.assertSequenceEqual(obj.impl, impl_tag)
313 self.assertFalse(obj.expled)
316 def test_expl_inherited(self, expl_tag):
317 class Inherited(self.base_klass):
320 self.assertSequenceEqual(obj.expl, expl_tag)
321 self.assertTrue(obj.expled)
323 def assert_copied_basic_fields(self, obj, obj_copied):
324 self.assertEqual(obj, obj_copied)
325 self.assertSequenceEqual(obj.tag, obj_copied.tag)
326 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
327 self.assertEqual(obj.default, obj_copied.default)
328 self.assertEqual(obj.optional, obj_copied.optional)
329 self.assertEqual(obj.offset, obj_copied.offset)
330 self.assertEqual(obj.llen, obj_copied.llen)
331 self.assertEqual(obj.vlen, obj_copied.vlen)
335 def boolean_values_strategy(draw, do_expl=False):
336 value = draw(one_of(none(), booleans()))
340 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
342 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
343 default = draw(one_of(none(), booleans()))
344 optional = draw(one_of(none(), booleans()))
346 draw(integers(min_value=0)),
347 draw(integers(min_value=0)),
348 draw(integers(min_value=0)),
350 return (value, impl, expl, default, optional, _decoded)
353 class BooleanInherited(Boolean):
357 class TestBoolean(CommonMixin, TestCase):
360 def test_invalid_value_type(self):
361 with self.assertRaises(InvalidValueType) as err:
366 def test_optional(self, optional):
367 obj = Boolean(default=Boolean(False), optional=optional)
368 self.assertTrue(obj.optional)
371 def test_ready(self, value):
373 self.assertFalse(obj.ready)
376 pprint(obj, big_blobs=True, with_decode_path=True)
377 with self.assertRaises(ObjNotReady) as err:
381 self.assertTrue(obj.ready)
384 pprint(obj, big_blobs=True, with_decode_path=True)
386 @given(booleans(), booleans(), binary(), binary())
387 def test_comparison(self, value1, value2, tag1, tag2):
388 for klass in (Boolean, BooleanInherited):
391 self.assertEqual(obj1 == obj2, value1 == value2)
392 self.assertEqual(obj1 != obj2, value1 != value2)
393 self.assertEqual(obj1 == bool(obj2), value1 == value2)
394 obj1 = klass(value1, impl=tag1)
395 obj2 = klass(value1, impl=tag2)
396 self.assertEqual(obj1 == obj2, tag1 == tag2)
397 self.assertEqual(obj1 != obj2, tag1 != tag2)
399 @given(data_strategy())
400 def test_call(self, d):
401 for klass in (Boolean, BooleanInherited):
409 ) = d.draw(boolean_values_strategy())
415 optional_initial or False,
425 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
426 obj = obj_initial(value, impl, expl, default, optional)
428 value_expected = default if value is None else value
430 default_initial if value_expected is None
433 self.assertEqual(obj, value_expected)
434 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
435 self.assertEqual(obj.expl_tag, expl or expl_initial)
438 default_initial if default is None else default,
440 if obj.default is None:
441 optional = optional_initial if optional is None else optional
442 optional = False if optional is None else optional
445 self.assertEqual(obj.optional, optional)
447 @given(boolean_values_strategy())
448 def test_copy(self, values):
449 for klass in (Boolean, BooleanInherited):
451 obj_copied = obj.copy()
452 self.assert_copied_basic_fields(obj, obj_copied)
456 integers(min_value=1).map(tag_encode),
458 def test_stripped(self, value, tag_impl):
459 obj = Boolean(value, impl=tag_impl)
460 with self.assertRaises(NotEnoughData):
461 obj.decode(obj.encode()[:-1])
465 integers(min_value=1).map(tag_ctxc),
467 def test_stripped_expl(self, value, tag_expl):
468 obj = Boolean(value, expl=tag_expl)
469 with self.assertRaises(NotEnoughData):
470 obj.decode(obj.encode()[:-1])
473 integers(min_value=31),
474 integers(min_value=0),
477 def test_bad_tag(self, tag, offset, decode_path):
478 with self.assertRaises(DecodeError) as err:
480 tag_encode(tag)[:-1],
482 decode_path=decode_path,
485 self.assertEqual(err.exception.offset, offset)
486 self.assertEqual(err.exception.decode_path, decode_path)
489 integers(min_value=31),
490 integers(min_value=0),
493 def test_bad_expl_tag(self, tag, offset, decode_path):
494 with self.assertRaises(DecodeError) as err:
495 Boolean(expl=Boolean.tag_default).decode(
496 tag_encode(tag)[:-1],
498 decode_path=decode_path,
501 self.assertEqual(err.exception.offset, offset)
502 self.assertEqual(err.exception.decode_path, decode_path)
505 integers(min_value=128),
506 integers(min_value=0),
509 def test_bad_len(self, l, offset, decode_path):
510 with self.assertRaises(DecodeError) as err:
512 Boolean.tag_default + len_encode(l)[:-1],
514 decode_path=decode_path,
517 self.assertEqual(err.exception.offset, offset)
518 self.assertEqual(err.exception.decode_path, decode_path)
521 integers(min_value=128),
522 integers(min_value=0),
525 def test_bad_expl_len(self, l, offset, decode_path):
526 with self.assertRaises(DecodeError) as err:
527 Boolean(expl=Boolean.tag_default).decode(
528 Boolean.tag_default + len_encode(l)[:-1],
530 decode_path=decode_path,
533 self.assertEqual(err.exception.offset, offset)
534 self.assertEqual(err.exception.decode_path, decode_path)
536 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
538 boolean_values_strategy(),
540 integers(min_value=1).map(tag_ctxc),
541 integers(min_value=0),
544 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
545 for klass in (Boolean, BooleanInherited):
546 _, _, _, default, optional, _decoded = values
555 pprint(obj, big_blobs=True, with_decode_path=True)
556 self.assertFalse(obj.expled)
557 obj_encoded = obj.encode()
558 obj_expled = obj(value, expl=tag_expl)
559 self.assertTrue(obj_expled.expled)
561 list(obj_expled.pps())
562 pprint(obj_expled, big_blobs=True, with_decode_path=True)
563 obj_expled_encoded = obj_expled.encode()
564 obj_decoded, tail = obj_expled.decode(
565 obj_expled_encoded + tail_junk,
569 list(obj_decoded.pps())
570 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
571 self.assertEqual(tail, tail_junk)
572 self.assertEqual(obj_decoded, obj_expled)
573 self.assertNotEqual(obj_decoded, obj)
574 self.assertEqual(bool(obj_decoded), bool(obj_expled))
575 self.assertEqual(bool(obj_decoded), bool(obj))
576 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
577 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
578 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
580 obj_decoded.expl_llen,
581 len(len_encode(len(obj_encoded))),
583 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
584 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
587 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
589 self.assertEqual(obj_decoded.expl_offset, offset)
591 @given(integers(min_value=2))
592 def test_invalid_len(self, l):
593 with self.assertRaises(InvalidLength):
594 Boolean().decode(b"".join((
600 @given(integers(min_value=0 + 1, max_value=255 - 1))
601 def test_ber_value(self, value):
602 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
603 Boolean().decode(b"".join((
608 obj, _ = Boolean().decode(
616 self.assertTrue(bool(obj))
617 self.assertTrue(obj.ber_encoded)
618 self.assertFalse(obj.lenindef)
619 self.assertTrue(obj.bered)
622 integers(min_value=1).map(tag_ctxc),
623 binary().filter(lambda x: not x.startswith(EOC)),
625 def test_ber_expl_no_eoc(self, expl, junk):
626 encoded = expl + LENINDEF + Boolean(False).encode()
627 with self.assertRaises(LenIndefForm):
628 Boolean(expl=expl).decode(encoded + junk)
629 with assertRaisesRegex(self, DecodeError, "no EOC"):
630 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
631 obj, tail = Boolean(expl=expl).decode(
632 encoded + EOC + junk,
635 self.assertTrue(obj.expl_lenindef)
636 self.assertFalse(obj.lenindef)
637 self.assertFalse(obj.ber_encoded)
638 self.assertTrue(obj.bered)
639 self.assertSequenceEqual(tail, junk)
642 pprint(obj, big_blobs=True, with_decode_path=True)
645 integers(min_value=1).map(tag_ctxc),
652 def test_ber_expl(self, expl, values):
658 Boolean(value).encode() +
661 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
663 class SeqOf(SequenceOf):
664 schema = Boolean(expl=expl)
665 with self.assertRaises(LenIndefForm):
666 SeqOf().decode(encoded)
667 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
668 self.assertSequenceEqual(tail, b"")
669 self.assertSequenceEqual([bool(v) for v in seqof], values)
685 len(expl) + 1 + 3 + EOC_LEN,
696 pprint(seqof, big_blobs=True, with_decode_path=True)
700 def integer_values_strategy(draw, do_expl=False):
701 bound_min, value, default, bound_max = sorted(draw(sets(
710 _specs = draw(sets(text_letters()))
713 min_size=len(_specs),
714 max_size=len(_specs),
716 _specs = list(zip(_specs, values))
719 bounds = (bound_min, bound_max)
723 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
725 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
728 optional = draw(one_of(none(), booleans()))
730 draw(integers(min_value=0)),
731 draw(integers(min_value=0)),
732 draw(integers(min_value=0)),
734 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
737 class IntegerInherited(Integer):
741 class TestInteger(CommonMixin, TestCase):
744 def test_invalid_value_type(self):
745 with self.assertRaises(InvalidValueType) as err:
749 @given(sets(text_letters(), min_size=2))
750 def test_unknown_name(self, names_input):
751 missing = names_input.pop()
754 schema = [(n, 123) for n in names_input]
755 with self.assertRaises(ObjUnknown) as err:
759 @given(sets(text_letters(), min_size=2))
760 def test_known_name(self, names_input):
762 schema = [(n, 123) for n in names_input]
763 Int(names_input.pop())
766 def test_optional(self, optional):
767 obj = Integer(default=Integer(0), optional=optional)
768 self.assertTrue(obj.optional)
771 def test_ready(self, value):
773 self.assertFalse(obj.ready)
776 pprint(obj, big_blobs=True, with_decode_path=True)
777 with self.assertRaises(ObjNotReady) as err:
781 self.assertTrue(obj.ready)
784 pprint(obj, big_blobs=True, with_decode_path=True)
787 @given(integers(), integers(), binary(), binary())
788 def test_comparison(self, value1, value2, tag1, tag2):
789 for klass in (Integer, IntegerInherited):
792 self.assertEqual(obj1 == obj2, value1 == value2)
793 self.assertEqual(obj1 != obj2, value1 != value2)
794 self.assertEqual(obj1 == int(obj2), value1 == value2)
795 obj1 = klass(value1, impl=tag1)
796 obj2 = klass(value1, impl=tag2)
797 self.assertEqual(obj1 == obj2, tag1 == tag2)
798 self.assertEqual(obj1 != obj2, tag1 != tag2)
800 @given(lists(integers()))
801 def test_sorted_works(self, values):
802 self.assertSequenceEqual(
803 [int(v) for v in sorted(Integer(v) for v in values)],
807 @given(data_strategy())
808 def test_named(self, d):
809 names_input = list(d.draw(sets(text_letters(), min_size=1)))
810 values_input = list(d.draw(sets(
812 min_size=len(names_input),
813 max_size=len(names_input),
815 chosen_name = d.draw(sampled_from(names_input))
816 names_input = dict(zip(names_input, values_input))
820 _int = Int(chosen_name)
821 self.assertEqual(_int.named, chosen_name)
822 self.assertEqual(int(_int), names_input[chosen_name])
824 @given(integers(), integers(min_value=0), integers(min_value=0))
825 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
826 value = bound_min + value_delta
827 bound_max = value + bound_delta
828 Integer(value=value, bounds=(bound_min, bound_max))
830 @given(sets(integers(), min_size=3, max_size=3))
831 def test_bounds_unsatisfied(self, values):
832 values = sorted(values)
833 with self.assertRaises(BoundsError) as err:
834 Integer(value=values[0], bounds=(values[1], values[2]))
836 with assertRaisesRegex(self, DecodeError, "bounds") as err:
837 Integer(bounds=(values[1], values[2])).decode(
838 Integer(values[0]).encode()
841 with self.assertRaises(BoundsError) as err:
842 Integer(value=values[2], bounds=(values[0], values[1]))
844 with assertRaisesRegex(self, DecodeError, "bounds") as err:
845 Integer(bounds=(values[0], values[1])).decode(
846 Integer(values[2]).encode()
850 @given(data_strategy())
851 def test_call(self, d):
852 for klass in (Integer, IntegerInherited):
862 ) = d.draw(integer_values_strategy())
869 optional_initial or False,
882 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
883 if (default is None) and (obj_initial.default is not None):
887 (value is not None) and
888 (bounds_initial is not None) and
889 not (bounds_initial[0] <= value <= bounds_initial[1])
894 (default is not None) and
895 (bounds_initial is not None) and
896 not (bounds_initial[0] <= default <= bounds_initial[1])
899 obj = obj_initial(value, bounds, impl, expl, default, optional)
901 value_expected = default if value is None else value
903 default_initial if value_expected is None
906 self.assertEqual(obj, value_expected)
907 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
908 self.assertEqual(obj.expl_tag, expl or expl_initial)
911 default_initial if default is None else default,
913 if obj.default is None:
914 optional = optional_initial if optional is None else optional
915 optional = False if optional is None else optional
918 self.assertEqual(obj.optional, optional)
920 (obj._bound_min, obj._bound_max),
921 bounds or bounds_initial or (float("-inf"), float("+inf")),
925 {} if _specs_initial is None else dict(_specs_initial),
928 @given(integer_values_strategy())
929 def test_copy(self, values):
930 for klass in (Integer, IntegerInherited):
932 obj_copied = obj.copy()
933 self.assert_copied_basic_fields(obj, obj_copied)
934 self.assertEqual(obj.specs, obj_copied.specs)
935 self.assertEqual(obj._bound_min, obj_copied._bound_min)
936 self.assertEqual(obj._bound_max, obj_copied._bound_max)
937 self.assertEqual(obj._value, obj_copied._value)
941 integers(min_value=1).map(tag_encode),
943 def test_stripped(self, value, tag_impl):
944 obj = Integer(value, impl=tag_impl)
945 with self.assertRaises(NotEnoughData):
946 obj.decode(obj.encode()[:-1])
950 integers(min_value=1).map(tag_ctxc),
952 def test_stripped_expl(self, value, tag_expl):
953 obj = Integer(value, expl=tag_expl)
954 with self.assertRaises(NotEnoughData):
955 obj.decode(obj.encode()[:-1])
957 def test_zero_len(self):
958 with self.assertRaises(NotEnoughData):
959 Integer().decode(b"".join((
965 integers(min_value=31),
966 integers(min_value=0),
969 def test_bad_tag(self, tag, offset, decode_path):
970 with self.assertRaises(DecodeError) as err:
972 tag_encode(tag)[:-1],
974 decode_path=decode_path,
977 self.assertEqual(err.exception.offset, offset)
978 self.assertEqual(err.exception.decode_path, decode_path)
981 integers(min_value=128),
982 integers(min_value=0),
985 def test_bad_len(self, l, offset, decode_path):
986 with self.assertRaises(DecodeError) as err:
988 Integer.tag_default + len_encode(l)[:-1],
990 decode_path=decode_path,
993 self.assertEqual(err.exception.offset, offset)
994 self.assertEqual(err.exception.decode_path, decode_path)
997 sets(integers(), min_size=2, max_size=2),
998 integers(min_value=0),
1001 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1002 value, bound_min = list(sorted(ints))
1005 bounds = (bound_min, bound_min)
1006 with self.assertRaises(DecodeError) as err:
1008 Integer(value).encode(),
1010 decode_path=decode_path,
1013 self.assertEqual(err.exception.offset, offset)
1014 self.assertEqual(err.exception.decode_path, decode_path)
1016 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1018 integer_values_strategy(),
1020 integers(min_value=1).map(tag_ctxc),
1021 integers(min_value=0),
1024 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1025 for klass in (Integer, IntegerInherited):
1026 _, _, _, _, default, optional, _, _decoded = values
1035 pprint(obj, big_blobs=True, with_decode_path=True)
1036 self.assertFalse(obj.expled)
1037 obj_encoded = obj.encode()
1038 obj_expled = obj(value, expl=tag_expl)
1039 self.assertTrue(obj_expled.expled)
1041 list(obj_expled.pps())
1042 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1043 obj_expled_encoded = obj_expled.encode()
1044 obj_decoded, tail = obj_expled.decode(
1045 obj_expled_encoded + tail_junk,
1049 list(obj_decoded.pps())
1050 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1051 self.assertEqual(tail, tail_junk)
1052 self.assertEqual(obj_decoded, obj_expled)
1053 self.assertNotEqual(obj_decoded, obj)
1054 self.assertEqual(int(obj_decoded), int(obj_expled))
1055 self.assertEqual(int(obj_decoded), int(obj))
1056 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1057 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1058 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1060 obj_decoded.expl_llen,
1061 len(len_encode(len(obj_encoded))),
1063 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1064 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1067 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1069 self.assertEqual(obj_decoded.expl_offset, offset)
1071 def test_go_vectors_valid(self):
1072 for data, expect in ((
1076 (b"\xff\x7f", -129),
1080 (b"\xff\x00", -256),
1084 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1085 (b"\x80\x00\x00\x00", -2147483648),
1088 Integer().decode(b"".join((
1089 Integer.tag_default,
1090 len_encode(len(data)),
1096 def test_go_vectors_invalid(self):
1101 with self.assertRaises(DecodeError):
1102 Integer().decode(b"".join((
1103 Integer.tag_default,
1104 len_encode(len(data)),
1110 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1113 if draw(booleans()):
1114 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1116 integers(min_value=0, max_value=255),
1117 min_size=len(schema),
1118 max_size=len(schema),
1120 schema = list(zip(schema, bits))
1122 def _value(value_required):
1123 if not value_required and draw(booleans()):
1125 generation_choice = 0
1127 generation_choice = draw(sampled_from((1, 2, 3)))
1128 if generation_choice == 1 or draw(booleans()):
1129 return "'%s'B" % "".join(draw(lists(
1130 sampled_from(("0", "1")),
1131 max_size=len(schema),
1133 elif generation_choice == 2 or draw(booleans()):
1134 return draw(binary(max_size=len(schema) // 8))
1135 elif generation_choice == 3 or draw(booleans()):
1136 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1138 value = _value(value_required)
1139 default = _value(value_required=False)
1143 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1145 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1146 optional = draw(one_of(none(), booleans()))
1148 draw(integers(min_value=0)),
1149 draw(integers(min_value=0)),
1150 draw(integers(min_value=0)),
1152 return (schema, value, impl, expl, default, optional, _decoded)
1155 class BitStringInherited(BitString):
1159 class TestBitString(CommonMixin, TestCase):
1160 base_klass = BitString
1162 @given(lists(booleans()))
1163 def test_b_encoding(self, bits):
1164 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1165 self.assertEqual(obj.bit_len, len(bits))
1166 self.assertSequenceEqual(list(obj), bits)
1167 for i, bit in enumerate(bits):
1168 self.assertEqual(obj[i], bit)
1170 @given(lists(booleans()))
1171 def test_out_of_bounds_bits(self, bits):
1172 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1173 for i in range(len(bits), len(bits) * 2):
1174 self.assertFalse(obj[i])
1176 def test_bad_b_encoding(self):
1177 with self.assertRaises(ValueError):
1178 BitString("'010120101'B")
1181 integers(min_value=1, max_value=255),
1182 integers(min_value=1, max_value=255),
1184 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1185 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1186 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1187 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1189 class BS(BitString):
1190 schema = (("whatever", 0),)
1191 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1192 self.assertEqual(obj.bit_len, leading_zeros + 1)
1193 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1195 def test_zero_len(self):
1196 with self.assertRaises(NotEnoughData):
1197 BitString().decode(b"".join((
1198 BitString.tag_default,
1202 def test_invalid_value_type(self):
1203 with self.assertRaises(InvalidValueType) as err:
1206 with self.assertRaises(InvalidValueType) as err:
1210 def test_obj_unknown(self):
1211 with self.assertRaises(ObjUnknown) as err:
1212 BitString(b"whatever")["whenever"]
1215 def test_get_invalid_type(self):
1216 with self.assertRaises(InvalidValueType) as err:
1217 BitString(b"whatever")[(1, 2, 3)]
1220 @given(data_strategy())
1221 def test_unknown_name(self, d):
1222 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1223 missing = _schema.pop()
1225 class BS(BitString):
1226 schema = [(n, i) for i, n in enumerate(_schema)]
1227 with self.assertRaises(ObjUnknown) as err:
1232 def test_optional(self, optional):
1233 obj = BitString(default=BitString(b""), optional=optional)
1234 self.assertTrue(obj.optional)
1237 def test_ready(self, value):
1239 self.assertFalse(obj.ready)
1242 pprint(obj, big_blobs=True, with_decode_path=True)
1243 with self.assertRaises(ObjNotReady) as err:
1246 obj = BitString(value)
1247 self.assertTrue(obj.ready)
1250 pprint(obj, big_blobs=True, with_decode_path=True)
1253 tuples(integers(min_value=0), binary()),
1254 tuples(integers(min_value=0), binary()),
1258 def test_comparison(self, value1, value2, tag1, tag2):
1259 for klass in (BitString, BitStringInherited):
1260 obj1 = klass(value1)
1261 obj2 = klass(value2)
1262 self.assertEqual(obj1 == obj2, value1 == value2)
1263 self.assertEqual(obj1 != obj2, value1 != value2)
1264 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1265 obj1 = klass(value1, impl=tag1)
1266 obj2 = klass(value1, impl=tag2)
1267 self.assertEqual(obj1 == obj2, tag1 == tag2)
1268 self.assertEqual(obj1 != obj2, tag1 != tag2)
1270 @given(data_strategy())
1271 def test_call(self, d):
1272 for klass in (BitString, BitStringInherited):
1281 ) = d.draw(bit_string_values_strategy())
1284 schema = schema_initial
1286 value=value_initial,
1289 default=default_initial,
1290 optional=optional_initial or False,
1291 _decoded=_decoded_initial,
1301 ) = d.draw(bit_string_values_strategy(
1302 schema=schema_initial,
1303 do_expl=impl_initial is None,
1312 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1313 self.assertEqual(obj.expl_tag, expl or expl_initial)
1314 if obj.default is None:
1315 optional = optional_initial if optional is None else optional
1316 optional = False if optional is None else optional
1319 self.assertEqual(obj.optional, optional)
1320 self.assertEqual(obj.specs, obj_initial.specs)
1322 @given(bit_string_values_strategy())
1323 def test_copy(self, values):
1324 for klass in (BitString, BitStringInherited):
1325 _schema, value, impl, expl, default, optional, _decoded = values
1334 optional=optional or False,
1337 obj_copied = obj.copy()
1338 self.assert_copied_basic_fields(obj, obj_copied)
1339 self.assertEqual(obj.specs, obj_copied.specs)
1340 self.assertEqual(obj._value, obj_copied._value)
1344 integers(min_value=1).map(tag_encode),
1346 def test_stripped(self, value, tag_impl):
1347 obj = BitString(value, impl=tag_impl)
1348 with self.assertRaises(NotEnoughData):
1349 obj.decode(obj.encode()[:-1])
1353 integers(min_value=1).map(tag_ctxc),
1355 def test_stripped_expl(self, value, tag_expl):
1356 obj = BitString(value, expl=tag_expl)
1357 with self.assertRaises(NotEnoughData):
1358 obj.decode(obj.encode()[:-1])
1361 integers(min_value=31),
1362 integers(min_value=0),
1365 def test_bad_tag(self, tag, offset, decode_path):
1366 with self.assertRaises(DecodeError) as err:
1368 tag_encode(tag)[:-1],
1370 decode_path=decode_path,
1373 self.assertEqual(err.exception.offset, offset)
1374 self.assertEqual(err.exception.decode_path, decode_path)
1377 integers(min_value=128),
1378 integers(min_value=0),
1381 def test_bad_len(self, l, offset, decode_path):
1382 with self.assertRaises(DecodeError) as err:
1384 BitString.tag_default + len_encode(l)[:-1],
1386 decode_path=decode_path,
1389 self.assertEqual(err.exception.offset, offset)
1390 self.assertEqual(err.exception.decode_path, decode_path)
1392 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1393 @given(data_strategy())
1394 def test_symmetric(self, d):
1403 ) = d.draw(bit_string_values_strategy(value_required=True))
1404 tail_junk = d.draw(binary(max_size=5))
1405 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1406 offset = d.draw(integers(min_value=0))
1407 for klass in (BitString, BitStringInherited):
1418 pprint(obj, big_blobs=True, with_decode_path=True)
1419 self.assertFalse(obj.expled)
1420 obj_encoded = obj.encode()
1421 obj_expled = obj(value, expl=tag_expl)
1422 self.assertTrue(obj_expled.expled)
1424 list(obj_expled.pps())
1425 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1426 obj_expled_encoded = obj_expled.encode()
1427 obj_decoded, tail = obj_expled.decode(
1428 obj_expled_encoded + tail_junk,
1432 list(obj_decoded.pps())
1433 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1434 self.assertEqual(tail, tail_junk)
1435 self.assertEqual(obj_decoded, obj_expled)
1436 self.assertNotEqual(obj_decoded, obj)
1437 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1438 self.assertEqual(bytes(obj_decoded), bytes(obj))
1439 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1440 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1441 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1443 obj_decoded.expl_llen,
1444 len(len_encode(len(obj_encoded))),
1446 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1447 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1450 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1452 self.assertEqual(obj_decoded.expl_offset, offset)
1453 if isinstance(value, tuple):
1454 self.assertSetEqual(set(value), set(obj_decoded.named))
1458 @given(integers(min_value=1, max_value=255))
1459 def test_bad_zero_value(self, pad_size):
1460 with self.assertRaises(DecodeError):
1461 BitString().decode(b"".join((
1462 BitString.tag_default,
1467 def test_go_vectors_invalid(self):
1473 with self.assertRaises(DecodeError):
1474 BitString().decode(b"".join((
1475 BitString.tag_default,
1480 def test_go_vectors_valid(self):
1481 obj, _ = BitString().decode(b"".join((
1482 BitString.tag_default,
1486 self.assertEqual(bytes(obj), b"")
1487 self.assertEqual(obj.bit_len, 0)
1489 obj, _ = BitString().decode(b"".join((
1490 BitString.tag_default,
1494 self.assertEqual(bytes(obj), b"\x00")
1495 self.assertEqual(obj.bit_len, 1)
1497 obj = BitString((16, b"\x82\x40"))
1498 self.assertTrue(obj[0])
1499 self.assertFalse(obj[1])
1500 self.assertTrue(obj[6])
1501 self.assertTrue(obj[9])
1502 self.assertFalse(obj[17])
1505 integers(min_value=1, max_value=30),
1508 binary(min_size=1, max_size=5),
1510 binary(min_size=1, max_size=5),
1518 lists(booleans(), min_size=1),
1521 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1522 def chunk_constructed(contents):
1524 tag_encode(form=TagFormConstructed, num=3) +
1526 b"".join(BitString(content).encode() for content in contents) +
1530 payload_expected = b""
1531 bit_len_expected = 0
1532 for chunk_input in chunk_inputs:
1533 if isinstance(chunk_input, binary_type):
1534 chunks.append(BitString(chunk_input).encode())
1535 payload_expected += chunk_input
1536 bit_len_expected += len(chunk_input) * 8
1538 chunks.append(chunk_constructed(chunk_input))
1539 payload = b"".join(chunk_input)
1540 payload_expected += payload
1541 bit_len_expected += len(payload) * 8
1542 chunk_last = BitString("'%s'B" % "".join(
1543 "1" if bit else "0" for bit in chunk_last_bits
1545 payload_expected += bytes(chunk_last)
1546 bit_len_expected += chunk_last.bit_len
1547 encoded_indefinite = (
1548 tag_encode(form=TagFormConstructed, num=impl) +
1551 chunk_last.encode() +
1554 encoded_definite = (
1555 tag_encode(form=TagFormConstructed, num=impl) +
1556 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1560 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1561 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1562 for lenindef_expected, encoded in (
1563 (True, encoded_indefinite),
1564 (False, encoded_definite),
1566 obj, tail = BitString(impl=tag_encode(impl)).decode(
1568 ctx={"bered": True},
1570 self.assertSequenceEqual(tail, junk)
1571 self.assertEqual(obj.bit_len, bit_len_expected)
1572 self.assertSequenceEqual(bytes(obj), payload_expected)
1573 self.assertTrue(obj.ber_encoded)
1574 self.assertEqual(obj.lenindef, lenindef_expected)
1575 self.assertTrue(obj.bered)
1576 self.assertEqual(len(encoded), obj.tlvlen)
1579 integers(min_value=0),
1582 def test_ber_definite_too_short(self, offset, decode_path):
1583 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1585 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1587 decode_path=decode_path,
1588 ctx={"bered": True},
1590 self.assertEqual(err.exception.decode_path, decode_path)
1591 self.assertEqual(err.exception.offset, offset)
1594 integers(min_value=0),
1597 def test_ber_definite_no_data(self, offset, decode_path):
1598 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1600 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1602 decode_path=decode_path,
1603 ctx={"bered": True},
1605 self.assertEqual(err.exception.decode_path, decode_path)
1606 self.assertEqual(err.exception.offset, offset)
1609 integers(min_value=0),
1611 integers(min_value=1, max_value=3),
1613 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1614 bs = BitString(b"data").encode()
1615 with self.assertRaises(NotEnoughData) as err:
1617 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1619 decode_path=decode_path,
1620 ctx={"bered": True},
1622 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1623 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1626 integers(min_value=0),
1628 integers(min_value=1, max_value=3),
1630 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1631 bs = BitString(b"data").encode()
1632 bs_longer = BitString(b"data-longer").encode()
1633 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1636 tag_encode(3, form=TagFormConstructed) +
1637 len_encode((chunks + 1) * len(bs)) +
1642 decode_path=decode_path,
1643 ctx={"bered": True},
1645 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1646 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1649 integers(min_value=0),
1652 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1653 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1655 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1657 decode_path=decode_path,
1658 ctx={"bered": True},
1660 self.assertEqual(err.exception.decode_path, decode_path)
1661 self.assertEqual(err.exception.offset, offset)
1663 @given(data_strategy())
1664 def test_ber_indefinite_not_multiple(self, d):
1665 bs_short = BitString("'A'H").encode()
1666 bs_full = BitString("'AA'H").encode()
1667 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1668 chunks.append(bs_short)
1669 d.draw(permutations(chunks))
1670 chunks.append(bs_short)
1671 offset = d.draw(integers(min_value=0))
1672 decode_path = d.draw(decode_path_strat)
1673 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1676 tag_encode(3, form=TagFormConstructed) +
1682 decode_path=decode_path,
1683 ctx={"bered": True},
1686 err.exception.decode_path,
1687 decode_path + (str(chunks.index(bs_short)),),
1690 err.exception.offset,
1691 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1694 def test_x690_vector(self):
1695 vector = BitString("'0A3B5F291CD'H")
1696 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1697 self.assertSequenceEqual(tail, b"")
1698 self.assertEqual(obj, vector)
1699 obj, tail = BitString().decode(
1700 hexdec("23800303000A3B0305045F291CD00000"),
1701 ctx={"bered": True},
1703 self.assertSequenceEqual(tail, b"")
1704 self.assertEqual(obj, vector)
1705 self.assertTrue(obj.ber_encoded)
1706 self.assertTrue(obj.lenindef)
1707 self.assertTrue(obj.bered)
1711 def octet_string_values_strategy(draw, do_expl=False):
1712 bound_min, bound_max = sorted(draw(sets(
1713 integers(min_value=0, max_value=1 << 7),
1717 value = draw(one_of(
1719 binary(min_size=bound_min, max_size=bound_max),
1721 default = draw(one_of(
1723 binary(min_size=bound_min, max_size=bound_max),
1726 if draw(booleans()):
1727 bounds = (bound_min, bound_max)
1731 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1733 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1734 optional = draw(one_of(none(), booleans()))
1736 draw(integers(min_value=0)),
1737 draw(integers(min_value=0)),
1738 draw(integers(min_value=0)),
1740 return (value, bounds, impl, expl, default, optional, _decoded)
1743 class OctetStringInherited(OctetString):
1747 class TestOctetString(CommonMixin, TestCase):
1748 base_klass = OctetString
1750 def test_invalid_value_type(self):
1751 with self.assertRaises(InvalidValueType) as err:
1752 OctetString(text_type(123))
1756 def test_optional(self, optional):
1757 obj = OctetString(default=OctetString(b""), optional=optional)
1758 self.assertTrue(obj.optional)
1761 def test_ready(self, value):
1763 self.assertFalse(obj.ready)
1766 pprint(obj, big_blobs=True, with_decode_path=True)
1767 with self.assertRaises(ObjNotReady) as err:
1770 obj = OctetString(value)
1771 self.assertTrue(obj.ready)
1774 pprint(obj, big_blobs=True, with_decode_path=True)
1776 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1777 def test_comparison(self, value1, value2, tag1, tag2):
1778 for klass in (OctetString, OctetStringInherited):
1779 obj1 = klass(value1)
1780 obj2 = klass(value2)
1781 self.assertEqual(obj1 == obj2, value1 == value2)
1782 self.assertEqual(obj1 != obj2, value1 != value2)
1783 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1784 obj1 = klass(value1, impl=tag1)
1785 obj2 = klass(value1, impl=tag2)
1786 self.assertEqual(obj1 == obj2, tag1 == tag2)
1787 self.assertEqual(obj1 != obj2, tag1 != tag2)
1789 @given(lists(binary()))
1790 def test_sorted_works(self, values):
1791 self.assertSequenceEqual(
1792 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1796 @given(data_strategy())
1797 def test_bounds_satisfied(self, d):
1798 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1799 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1800 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1801 OctetString(value=value, bounds=(bound_min, bound_max))
1803 @given(data_strategy())
1804 def test_bounds_unsatisfied(self, d):
1805 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1806 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1807 value = d.draw(binary(max_size=bound_min - 1))
1808 with self.assertRaises(BoundsError) as err:
1809 OctetString(value=value, bounds=(bound_min, bound_max))
1811 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1812 OctetString(bounds=(bound_min, bound_max)).decode(
1813 OctetString(value).encode()
1816 value = d.draw(binary(min_size=bound_max + 1))
1817 with self.assertRaises(BoundsError) as err:
1818 OctetString(value=value, bounds=(bound_min, bound_max))
1820 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1821 OctetString(bounds=(bound_min, bound_max)).decode(
1822 OctetString(value).encode()
1826 @given(data_strategy())
1827 def test_call(self, d):
1828 for klass in (OctetString, OctetStringInherited):
1837 ) = d.draw(octet_string_values_strategy())
1838 obj_initial = klass(
1844 optional_initial or False,
1855 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1856 if (default is None) and (obj_initial.default is not None):
1859 (bounds is None) and
1860 (value is not None) and
1861 (bounds_initial is not None) and
1862 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1866 (bounds is None) and
1867 (default is not None) and
1868 (bounds_initial is not None) and
1869 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1872 obj = obj_initial(value, bounds, impl, expl, default, optional)
1874 value_expected = default if value is None else value
1876 default_initial if value_expected is None
1879 self.assertEqual(obj, value_expected)
1880 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1881 self.assertEqual(obj.expl_tag, expl or expl_initial)
1884 default_initial if default is None else default,
1886 if obj.default is None:
1887 optional = optional_initial if optional is None else optional
1888 optional = False if optional is None else optional
1891 self.assertEqual(obj.optional, optional)
1893 (obj._bound_min, obj._bound_max),
1894 bounds or bounds_initial or (0, float("+inf")),
1897 @given(octet_string_values_strategy())
1898 def test_copy(self, values):
1899 for klass in (OctetString, OctetStringInherited):
1900 obj = klass(*values)
1901 obj_copied = obj.copy()
1902 self.assert_copied_basic_fields(obj, obj_copied)
1903 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1904 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1905 self.assertEqual(obj._value, obj_copied._value)
1909 integers(min_value=1).map(tag_encode),
1911 def test_stripped(self, value, tag_impl):
1912 obj = OctetString(value, impl=tag_impl)
1913 with self.assertRaises(NotEnoughData):
1914 obj.decode(obj.encode()[:-1])
1918 integers(min_value=1).map(tag_ctxc),
1920 def test_stripped_expl(self, value, tag_expl):
1921 obj = OctetString(value, expl=tag_expl)
1922 with self.assertRaises(NotEnoughData):
1923 obj.decode(obj.encode()[:-1])
1926 integers(min_value=31),
1927 integers(min_value=0),
1930 def test_bad_tag(self, tag, offset, decode_path):
1931 with self.assertRaises(DecodeError) as err:
1932 OctetString().decode(
1933 tag_encode(tag)[:-1],
1935 decode_path=decode_path,
1938 self.assertEqual(err.exception.offset, offset)
1939 self.assertEqual(err.exception.decode_path, decode_path)
1942 integers(min_value=128),
1943 integers(min_value=0),
1946 def test_bad_len(self, l, offset, decode_path):
1947 with self.assertRaises(DecodeError) as err:
1948 OctetString().decode(
1949 OctetString.tag_default + len_encode(l)[:-1],
1951 decode_path=decode_path,
1954 self.assertEqual(err.exception.offset, offset)
1955 self.assertEqual(err.exception.decode_path, decode_path)
1958 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1959 integers(min_value=0),
1962 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1963 value, bound_min = list(sorted(ints))
1965 class String(OctetString):
1966 bounds = (bound_min, bound_min)
1967 with self.assertRaises(DecodeError) as err:
1969 OctetString(b"\x00" * value).encode(),
1971 decode_path=decode_path,
1974 self.assertEqual(err.exception.offset, offset)
1975 self.assertEqual(err.exception.decode_path, decode_path)
1977 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1979 octet_string_values_strategy(),
1981 integers(min_value=1).map(tag_ctxc),
1982 integers(min_value=0),
1985 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1986 for klass in (OctetString, OctetStringInherited):
1987 _, _, _, _, default, optional, _decoded = values
1996 pprint(obj, big_blobs=True, with_decode_path=True)
1997 self.assertFalse(obj.expled)
1998 obj_encoded = obj.encode()
1999 obj_expled = obj(value, expl=tag_expl)
2000 self.assertTrue(obj_expled.expled)
2002 list(obj_expled.pps())
2003 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2004 obj_expled_encoded = obj_expled.encode()
2005 obj_decoded, tail = obj_expled.decode(
2006 obj_expled_encoded + tail_junk,
2010 list(obj_decoded.pps())
2011 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2012 self.assertEqual(tail, tail_junk)
2013 self.assertEqual(obj_decoded, obj_expled)
2014 self.assertNotEqual(obj_decoded, obj)
2015 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2016 self.assertEqual(bytes(obj_decoded), bytes(obj))
2017 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2018 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2019 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2021 obj_decoded.expl_llen,
2022 len(len_encode(len(obj_encoded))),
2024 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2025 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2028 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2030 self.assertEqual(obj_decoded.expl_offset, offset)
2033 integers(min_value=1, max_value=30),
2036 binary(min_size=1, max_size=5),
2038 binary(min_size=1, max_size=5),
2048 def test_constructed(self, impl, chunk_inputs, junk):
2049 def chunk_constructed(contents):
2051 tag_encode(form=TagFormConstructed, num=4) +
2053 b"".join(OctetString(content).encode() for content in contents) +
2057 payload_expected = b""
2058 for chunk_input in chunk_inputs:
2059 if isinstance(chunk_input, binary_type):
2060 chunks.append(OctetString(chunk_input).encode())
2061 payload_expected += chunk_input
2063 chunks.append(chunk_constructed(chunk_input))
2064 payload = b"".join(chunk_input)
2065 payload_expected += payload
2066 encoded_indefinite = (
2067 tag_encode(form=TagFormConstructed, num=impl) +
2072 encoded_definite = (
2073 tag_encode(form=TagFormConstructed, num=impl) +
2074 len_encode(len(b"".join(chunks))) +
2077 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2078 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2079 for lenindef_expected, encoded in (
2080 (True, encoded_indefinite),
2081 (False, encoded_definite),
2083 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2085 ctx={"bered": True},
2087 self.assertSequenceEqual(tail, junk)
2088 self.assertSequenceEqual(bytes(obj), payload_expected)
2089 self.assertTrue(obj.ber_encoded)
2090 self.assertEqual(obj.lenindef, lenindef_expected)
2091 self.assertTrue(obj.bered)
2092 self.assertEqual(len(encoded), obj.tlvlen)
2095 integers(min_value=0),
2098 def test_ber_definite_too_short(self, offset, decode_path):
2099 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2100 OctetString().decode(
2101 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2103 decode_path=decode_path,
2104 ctx={"bered": True},
2106 self.assertEqual(err.exception.decode_path, decode_path)
2107 self.assertEqual(err.exception.offset, offset)
2110 integers(min_value=0),
2112 integers(min_value=1, max_value=3),
2114 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2115 bs = OctetString(b"data").encode()
2116 with self.assertRaises(NotEnoughData) as err:
2117 OctetString().decode(
2118 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2120 decode_path=decode_path,
2121 ctx={"bered": True},
2123 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2124 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2127 integers(min_value=0),
2129 integers(min_value=1, max_value=3),
2131 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2132 bs = OctetString(b"data").encode()
2133 bs_longer = OctetString(b"data-longer").encode()
2134 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2135 OctetString().decode(
2137 tag_encode(4, form=TagFormConstructed) +
2138 len_encode((chunks + 1) * len(bs)) +
2143 decode_path=decode_path,
2144 ctx={"bered": True},
2146 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2147 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2151 def null_values_strategy(draw, do_expl=False):
2155 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2157 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2158 optional = draw(one_of(none(), booleans()))
2160 draw(integers(min_value=0)),
2161 draw(integers(min_value=0)),
2162 draw(integers(min_value=0)),
2164 return (impl, expl, optional, _decoded)
2167 class NullInherited(Null):
2171 class TestNull(CommonMixin, TestCase):
2174 def test_ready(self):
2176 self.assertTrue(obj.ready)
2179 pprint(obj, big_blobs=True, with_decode_path=True)
2181 @given(binary(), binary())
2182 def test_comparison(self, tag1, tag2):
2183 for klass in (Null, NullInherited):
2184 obj1 = klass(impl=tag1)
2185 obj2 = klass(impl=tag2)
2186 self.assertEqual(obj1 == obj2, tag1 == tag2)
2187 self.assertEqual(obj1 != obj2, tag1 != tag2)
2188 self.assertNotEqual(obj1, tag2)
2190 @given(data_strategy())
2191 def test_call(self, d):
2192 for klass in (Null, NullInherited):
2198 ) = d.draw(null_values_strategy())
2199 obj_initial = klass(
2202 optional=optional_initial or False,
2203 _decoded=_decoded_initial,
2210 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2211 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2212 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2213 self.assertEqual(obj.expl_tag, expl or expl_initial)
2214 optional = optional_initial if optional is None else optional
2215 optional = False if optional is None else optional
2216 self.assertEqual(obj.optional, optional)
2218 @given(null_values_strategy())
2219 def test_copy(self, values):
2220 for klass in (Null, NullInherited):
2221 impl, expl, optional, _decoded = values
2225 optional=optional or False,
2228 obj_copied = obj.copy()
2229 self.assert_copied_basic_fields(obj, obj_copied)
2231 @given(integers(min_value=1).map(tag_encode))
2232 def test_stripped(self, tag_impl):
2233 obj = Null(impl=tag_impl)
2234 with self.assertRaises(NotEnoughData):
2235 obj.decode(obj.encode()[:-1])
2237 @given(integers(min_value=1).map(tag_ctxc))
2238 def test_stripped_expl(self, tag_expl):
2239 obj = Null(expl=tag_expl)
2240 with self.assertRaises(NotEnoughData):
2241 obj.decode(obj.encode()[:-1])
2244 integers(min_value=31),
2245 integers(min_value=0),
2248 def test_bad_tag(self, tag, offset, decode_path):
2249 with self.assertRaises(DecodeError) as err:
2251 tag_encode(tag)[:-1],
2253 decode_path=decode_path,
2256 self.assertEqual(err.exception.offset, offset)
2257 self.assertEqual(err.exception.decode_path, decode_path)
2260 integers(min_value=128),
2261 integers(min_value=0),
2264 def test_bad_len(self, l, offset, decode_path):
2265 with self.assertRaises(DecodeError) as err:
2267 Null.tag_default + len_encode(l)[:-1],
2269 decode_path=decode_path,
2272 self.assertEqual(err.exception.offset, offset)
2273 self.assertEqual(err.exception.decode_path, decode_path)
2275 @given(binary(min_size=1))
2276 def test_tag_mismatch(self, impl):
2277 assume(impl != Null.tag_default)
2278 with self.assertRaises(TagMismatch):
2279 Null(impl=impl).decode(Null().encode())
2282 null_values_strategy(),
2283 integers(min_value=1).map(tag_ctxc),
2284 integers(min_value=0),
2287 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2288 for klass in (Null, NullInherited):
2289 _, _, optional, _decoded = values
2290 obj = klass(optional=optional, _decoded=_decoded)
2293 pprint(obj, big_blobs=True, with_decode_path=True)
2294 self.assertFalse(obj.expled)
2295 obj_encoded = obj.encode()
2296 obj_expled = obj(expl=tag_expl)
2297 self.assertTrue(obj_expled.expled)
2299 list(obj_expled.pps())
2300 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2301 obj_expled_encoded = obj_expled.encode()
2302 obj_decoded, tail = obj_expled.decode(
2303 obj_expled_encoded + tail_junk,
2307 list(obj_decoded.pps())
2308 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2309 self.assertEqual(tail, tail_junk)
2310 self.assertEqual(obj_decoded, obj_expled)
2311 self.assertNotEqual(obj_decoded, obj)
2312 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2313 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2314 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2316 obj_decoded.expl_llen,
2317 len(len_encode(len(obj_encoded))),
2319 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2320 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2323 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2325 self.assertEqual(obj_decoded.expl_offset, offset)
2327 @given(integers(min_value=1))
2328 def test_invalid_len(self, l):
2329 with self.assertRaises(InvalidLength):
2330 Null().decode(b"".join((
2337 def oid_strategy(draw):
2338 first_arc = draw(integers(min_value=0, max_value=2))
2340 if first_arc in (0, 1):
2341 second_arc = draw(integers(min_value=0, max_value=39))
2343 second_arc = draw(integers(min_value=0))
2344 other_arcs = draw(lists(integers(min_value=0)))
2345 return tuple([first_arc, second_arc] + other_arcs)
2349 def oid_values_strategy(draw, do_expl=False):
2350 value = draw(one_of(none(), oid_strategy()))
2354 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2356 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2357 default = draw(one_of(none(), oid_strategy()))
2358 optional = draw(one_of(none(), booleans()))
2360 draw(integers(min_value=0)),
2361 draw(integers(min_value=0)),
2362 draw(integers(min_value=0)),
2364 return (value, impl, expl, default, optional, _decoded)
2367 class ObjectIdentifierInherited(ObjectIdentifier):
2371 class TestObjectIdentifier(CommonMixin, TestCase):
2372 base_klass = ObjectIdentifier
2374 def test_invalid_value_type(self):
2375 with self.assertRaises(InvalidValueType) as err:
2376 ObjectIdentifier(123)
2380 def test_optional(self, optional):
2381 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2382 self.assertTrue(obj.optional)
2384 @given(oid_strategy())
2385 def test_ready(self, value):
2386 obj = ObjectIdentifier()
2387 self.assertFalse(obj.ready)
2390 pprint(obj, big_blobs=True, with_decode_path=True)
2391 with self.assertRaises(ObjNotReady) as err:
2394 obj = ObjectIdentifier(value)
2395 self.assertTrue(obj.ready)
2398 pprint(obj, big_blobs=True, with_decode_path=True)
2401 @given(oid_strategy(), oid_strategy(), binary(), binary())
2402 def test_comparison(self, value1, value2, tag1, tag2):
2403 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2404 obj1 = klass(value1)
2405 obj2 = klass(value2)
2406 self.assertEqual(obj1 == obj2, value1 == value2)
2407 self.assertEqual(obj1 != obj2, value1 != value2)
2408 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2409 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2410 obj1 = klass(value1, impl=tag1)
2411 obj2 = klass(value1, impl=tag2)
2412 self.assertEqual(obj1 == obj2, tag1 == tag2)
2413 self.assertEqual(obj1 != obj2, tag1 != tag2)
2415 @given(lists(oid_strategy()))
2416 def test_sorted_works(self, values):
2417 self.assertSequenceEqual(
2418 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2422 @given(data_strategy())
2423 def test_call(self, d):
2424 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2432 ) = d.draw(oid_values_strategy())
2433 obj_initial = klass(
2434 value=value_initial,
2437 default=default_initial,
2438 optional=optional_initial or False,
2439 _decoded=_decoded_initial,
2448 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2457 value_expected = default if value is None else value
2459 default_initial if value_expected is None
2462 self.assertEqual(obj, value_expected)
2463 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2464 self.assertEqual(obj.expl_tag, expl or expl_initial)
2467 default_initial if default is None else default,
2469 if obj.default is None:
2470 optional = optional_initial if optional is None else optional
2471 optional = False if optional is None else optional
2474 self.assertEqual(obj.optional, optional)
2476 @given(oid_values_strategy())
2477 def test_copy(self, values):
2478 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2495 obj_copied = obj.copy()
2496 self.assert_copied_basic_fields(obj, obj_copied)
2497 self.assertEqual(obj._value, obj_copied._value)
2499 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2502 integers(min_value=1).map(tag_encode),
2504 def test_stripped(self, value, tag_impl):
2505 obj = ObjectIdentifier(value, impl=tag_impl)
2506 with self.assertRaises(NotEnoughData):
2507 obj.decode(obj.encode()[:-1])
2511 integers(min_value=1).map(tag_ctxc),
2513 def test_stripped_expl(self, value, tag_expl):
2514 obj = ObjectIdentifier(value, expl=tag_expl)
2515 with self.assertRaises(NotEnoughData):
2516 obj.decode(obj.encode()[:-1])
2519 integers(min_value=31),
2520 integers(min_value=0),
2523 def test_bad_tag(self, tag, offset, decode_path):
2524 with self.assertRaises(DecodeError) as err:
2525 ObjectIdentifier().decode(
2526 tag_encode(tag)[:-1],
2528 decode_path=decode_path,
2531 self.assertEqual(err.exception.offset, offset)
2532 self.assertEqual(err.exception.decode_path, decode_path)
2535 integers(min_value=128),
2536 integers(min_value=0),
2539 def test_bad_len(self, l, offset, decode_path):
2540 with self.assertRaises(DecodeError) as err:
2541 ObjectIdentifier().decode(
2542 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2544 decode_path=decode_path,
2547 self.assertEqual(err.exception.offset, offset)
2548 self.assertEqual(err.exception.decode_path, decode_path)
2550 def test_zero_oid(self):
2551 with self.assertRaises(NotEnoughData):
2552 ObjectIdentifier().decode(
2553 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2556 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2557 @given(oid_strategy())
2558 def test_unfinished_oid(self, value):
2559 assume(list(value)[-1] > 255)
2560 obj_encoded = ObjectIdentifier(value).encode()
2561 obj, _ = ObjectIdentifier().decode(obj_encoded)
2562 data = obj_encoded[obj.tlen + obj.llen:-1]
2564 ObjectIdentifier.tag_default,
2565 len_encode(len(data)),
2568 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2571 @given(integers(min_value=0))
2572 def test_invalid_short(self, value):
2573 with self.assertRaises(InvalidOID):
2574 ObjectIdentifier((value,))
2575 with self.assertRaises(InvalidOID):
2576 ObjectIdentifier("%d" % value)
2578 @given(integers(min_value=3), integers(min_value=0))
2579 def test_invalid_first_arc(self, first_arc, second_arc):
2580 with self.assertRaises(InvalidOID):
2581 ObjectIdentifier((first_arc, second_arc))
2582 with self.assertRaises(InvalidOID):
2583 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2585 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2586 def test_invalid_second_arc(self, first_arc, second_arc):
2587 with self.assertRaises(InvalidOID):
2588 ObjectIdentifier((first_arc, second_arc))
2589 with self.assertRaises(InvalidOID):
2590 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2592 @given(text(alphabet=ascii_letters + ".", min_size=1))
2593 def test_junk(self, oid):
2594 with self.assertRaises(InvalidOID):
2595 ObjectIdentifier(oid)
2597 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2598 @given(oid_strategy())
2599 def test_validness(self, oid):
2600 obj = ObjectIdentifier(oid)
2601 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2604 pprint(obj, big_blobs=True, with_decode_path=True)
2606 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2608 oid_values_strategy(),
2610 integers(min_value=1).map(tag_ctxc),
2611 integers(min_value=0),
2614 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2615 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2616 _, _, _, default, optional, _decoded = values
2625 pprint(obj, big_blobs=True, with_decode_path=True)
2626 self.assertFalse(obj.expled)
2627 obj_encoded = obj.encode()
2628 obj_expled = obj(value, expl=tag_expl)
2629 self.assertTrue(obj_expled.expled)
2631 list(obj_expled.pps())
2632 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2633 obj_expled_encoded = obj_expled.encode()
2634 obj_decoded, tail = obj_expled.decode(
2635 obj_expled_encoded + tail_junk,
2639 list(obj_decoded.pps())
2640 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2641 self.assertEqual(tail, tail_junk)
2642 self.assertEqual(obj_decoded, obj_expled)
2643 self.assertNotEqual(obj_decoded, obj)
2644 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2645 self.assertEqual(tuple(obj_decoded), tuple(obj))
2646 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2647 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2648 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2650 obj_decoded.expl_llen,
2651 len(len_encode(len(obj_encoded))),
2653 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2654 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2657 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2659 self.assertEqual(obj_decoded.expl_offset, offset)
2662 oid_strategy().map(ObjectIdentifier),
2663 oid_strategy().map(ObjectIdentifier),
2665 def test_add(self, oid1, oid2):
2666 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2667 for oid_to_add in (oid2, tuple(oid2)):
2668 self.assertEqual(oid1 + oid_to_add, oid_expect)
2669 with self.assertRaises(InvalidValueType):
2672 def test_go_vectors_valid(self):
2673 for data, expect in (
2675 (b"\x55\x02", (2, 5, 2)),
2676 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2677 (b"\x81\x34\x03", (2, 100, 3)),
2680 ObjectIdentifier().decode(b"".join((
2681 ObjectIdentifier.tag_default,
2682 len_encode(len(data)),
2688 def test_go_vectors_invalid(self):
2689 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2690 with self.assertRaises(DecodeError):
2691 ObjectIdentifier().decode(b"".join((
2692 Integer.tag_default,
2693 len_encode(len(data)),
2697 def test_x690_vector(self):
2699 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2700 ObjectIdentifier((2, 999, 3)),
2705 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2707 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2708 values = list(draw(sets(
2710 min_size=len(schema),
2711 max_size=len(schema),
2713 schema = list(zip(schema, values))
2714 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2718 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2720 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2721 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2722 optional = draw(one_of(none(), booleans()))
2724 draw(integers(min_value=0)),
2725 draw(integers(min_value=0)),
2726 draw(integers(min_value=0)),
2728 return (schema, value, impl, expl, default, optional, _decoded)
2731 class TestEnumerated(CommonMixin, TestCase):
2732 class EWhatever(Enumerated):
2733 schema = (("whatever", 0),)
2735 base_klass = EWhatever
2737 def test_schema_required(self):
2738 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2741 def test_invalid_value_type(self):
2742 with self.assertRaises(InvalidValueType) as err:
2743 self.base_klass((1, 2))
2746 @given(sets(text_letters(), min_size=2))
2747 def test_unknown_name(self, schema_input):
2748 missing = schema_input.pop()
2750 class E(Enumerated):
2751 schema = [(n, 123) for n in schema_input]
2752 with self.assertRaises(ObjUnknown) as err:
2757 sets(text_letters(), min_size=2),
2758 sets(integers(), min_size=2),
2760 def test_unknown_value(self, schema_input, values_input):
2762 missing_value = values_input.pop()
2763 _input = list(zip(schema_input, values_input))
2765 class E(Enumerated):
2767 with self.assertRaises(DecodeError) as err:
2772 def test_optional(self, optional):
2773 obj = self.base_klass(default="whatever", optional=optional)
2774 self.assertTrue(obj.optional)
2776 def test_ready(self):
2777 obj = self.base_klass()
2778 self.assertFalse(obj.ready)
2781 pprint(obj, big_blobs=True, with_decode_path=True)
2782 with self.assertRaises(ObjNotReady) as err:
2785 obj = self.base_klass("whatever")
2786 self.assertTrue(obj.ready)
2789 pprint(obj, big_blobs=True, with_decode_path=True)
2791 @given(integers(), integers(), binary(), binary())
2792 def test_comparison(self, value1, value2, tag1, tag2):
2793 class E(Enumerated):
2795 ("whatever0", value1),
2796 ("whatever1", value2),
2799 class EInherited(E):
2801 for klass in (E, EInherited):
2802 obj1 = klass(value1)
2803 obj2 = klass(value2)
2804 self.assertEqual(obj1 == obj2, value1 == value2)
2805 self.assertEqual(obj1 != obj2, value1 != value2)
2806 self.assertEqual(obj1 == int(obj2), value1 == value2)
2807 obj1 = klass(value1, impl=tag1)
2808 obj2 = klass(value1, impl=tag2)
2809 self.assertEqual(obj1 == obj2, tag1 == tag2)
2810 self.assertEqual(obj1 != obj2, tag1 != tag2)
2812 @given(data_strategy())
2813 def test_call(self, d):
2822 ) = d.draw(enumerated_values_strategy())
2824 class E(Enumerated):
2825 schema = schema_initial
2827 value=value_initial,
2830 default=default_initial,
2831 optional=optional_initial or False,
2832 _decoded=_decoded_initial,
2842 ) = d.draw(enumerated_values_strategy(
2843 schema=schema_initial,
2844 do_expl=impl_initial is None,
2854 value_expected = default if value is None else value
2856 default_initial if value_expected is None
2861 dict(schema_initial).get(value_expected, value_expected),
2863 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2864 self.assertEqual(obj.expl_tag, expl or expl_initial)
2867 default_initial if default is None else default,
2869 if obj.default is None:
2870 optional = optional_initial if optional is None else optional
2871 optional = False if optional is None else optional
2874 self.assertEqual(obj.optional, optional)
2875 self.assertEqual(obj.specs, dict(schema_initial))
2877 @given(enumerated_values_strategy())
2878 def test_copy(self, values):
2879 schema_input, value, impl, expl, default, optional, _decoded = values
2881 class E(Enumerated):
2882 schema = schema_input
2891 obj_copied = obj.copy()
2892 self.assert_copied_basic_fields(obj, obj_copied)
2893 self.assertEqual(obj.specs, obj_copied.specs)
2895 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2896 @given(data_strategy())
2897 def test_symmetric(self, d):
2898 schema_input, _, _, _, default, optional, _decoded = d.draw(
2899 enumerated_values_strategy(),
2901 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2902 offset = d.draw(integers(min_value=0))
2903 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2904 tail_junk = d.draw(binary(max_size=5))
2906 class E(Enumerated):
2907 schema = schema_input
2916 pprint(obj, big_blobs=True, with_decode_path=True)
2917 self.assertFalse(obj.expled)
2918 obj_encoded = obj.encode()
2919 obj_expled = obj(value, expl=tag_expl)
2920 self.assertTrue(obj_expled.expled)
2922 list(obj_expled.pps())
2923 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2924 obj_expled_encoded = obj_expled.encode()
2925 obj_decoded, tail = obj_expled.decode(
2926 obj_expled_encoded + tail_junk,
2930 list(obj_decoded.pps())
2931 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2932 self.assertEqual(tail, tail_junk)
2933 self.assertEqual(obj_decoded, obj_expled)
2934 self.assertNotEqual(obj_decoded, obj)
2935 self.assertEqual(int(obj_decoded), int(obj_expled))
2936 self.assertEqual(int(obj_decoded), int(obj))
2937 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2938 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2939 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2941 obj_decoded.expl_llen,
2942 len(len_encode(len(obj_encoded))),
2944 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2945 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2948 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2950 self.assertEqual(obj_decoded.expl_offset, offset)
2954 def string_values_strategy(draw, alphabet, do_expl=False):
2955 bound_min, bound_max = sorted(draw(sets(
2956 integers(min_value=0, max_value=1 << 7),
2960 value = draw(one_of(
2962 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2964 default = draw(one_of(
2966 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2969 if draw(booleans()):
2970 bounds = (bound_min, bound_max)
2974 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2976 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2977 optional = draw(one_of(none(), booleans()))
2979 draw(integers(min_value=0)),
2980 draw(integers(min_value=0)),
2981 draw(integers(min_value=0)),
2983 return (value, bounds, impl, expl, default, optional, _decoded)
2986 class StringMixin(object):
2987 def test_invalid_value_type(self):
2988 with self.assertRaises(InvalidValueType) as err:
2989 self.base_klass((1, 2))
2992 def text_alphabet(self):
2993 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2994 return printable + whitespace
2998 def test_optional(self, optional):
2999 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3000 self.assertTrue(obj.optional)
3002 @given(data_strategy())
3003 def test_ready(self, d):
3004 obj = self.base_klass()
3005 self.assertFalse(obj.ready)
3008 pprint(obj, big_blobs=True, with_decode_path=True)
3010 with self.assertRaises(ObjNotReady) as err:
3013 value = d.draw(text(alphabet=self.text_alphabet()))
3014 obj = self.base_klass(value)
3015 self.assertTrue(obj.ready)
3018 pprint(obj, big_blobs=True, with_decode_path=True)
3021 @given(data_strategy())
3022 def test_comparison(self, d):
3023 value1 = d.draw(text(alphabet=self.text_alphabet()))
3024 value2 = d.draw(text(alphabet=self.text_alphabet()))
3025 tag1 = d.draw(binary(min_size=1))
3026 tag2 = d.draw(binary(min_size=1))
3027 obj1 = self.base_klass(value1)
3028 obj2 = self.base_klass(value2)
3029 self.assertEqual(obj1 == obj2, value1 == value2)
3030 self.assertEqual(obj1 != obj2, value1 != value2)
3031 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3032 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3033 obj1 = self.base_klass(value1, impl=tag1)
3034 obj2 = self.base_klass(value1, impl=tag2)
3035 self.assertEqual(obj1 == obj2, tag1 == tag2)
3036 self.assertEqual(obj1 != obj2, tag1 != tag2)
3038 @given(data_strategy())
3039 def test_bounds_satisfied(self, d):
3040 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3041 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3042 value = d.draw(text(
3043 alphabet=self.text_alphabet(),
3047 self.base_klass(value=value, bounds=(bound_min, bound_max))
3049 @given(data_strategy())
3050 def test_bounds_unsatisfied(self, d):
3051 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3052 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3053 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3054 with self.assertRaises(BoundsError) as err:
3055 self.base_klass(value=value, bounds=(bound_min, bound_max))
3057 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3058 self.base_klass(bounds=(bound_min, bound_max)).decode(
3059 self.base_klass(value).encode()
3062 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3063 with self.assertRaises(BoundsError) as err:
3064 self.base_klass(value=value, bounds=(bound_min, bound_max))
3066 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3067 self.base_klass(bounds=(bound_min, bound_max)).decode(
3068 self.base_klass(value).encode()
3072 @given(data_strategy())
3073 def test_call(self, d):
3082 ) = d.draw(string_values_strategy(self.text_alphabet()))
3083 obj_initial = self.base_klass(
3089 optional_initial or False,
3100 ) = d.draw(string_values_strategy(
3101 self.text_alphabet(),
3102 do_expl=impl_initial is None,
3104 if (default is None) and (obj_initial.default is not None):
3107 (bounds is None) and
3108 (value is not None) and
3109 (bounds_initial is not None) and
3110 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3114 (bounds is None) and
3115 (default is not None) and
3116 (bounds_initial is not None) and
3117 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3120 obj = obj_initial(value, bounds, impl, expl, default, optional)
3122 value_expected = default if value is None else value
3124 default_initial if value_expected is None
3127 self.assertEqual(obj, value_expected)
3128 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3129 self.assertEqual(obj.expl_tag, expl or expl_initial)
3132 default_initial if default is None else default,
3134 if obj.default is None:
3135 optional = optional_initial if optional is None else optional
3136 optional = False if optional is None else optional
3139 self.assertEqual(obj.optional, optional)
3141 (obj._bound_min, obj._bound_max),
3142 bounds or bounds_initial or (0, float("+inf")),
3145 @given(data_strategy())
3146 def test_copy(self, d):
3147 values = d.draw(string_values_strategy(self.text_alphabet()))
3148 obj = self.base_klass(*values)
3149 obj_copied = obj.copy()
3150 self.assert_copied_basic_fields(obj, obj_copied)
3151 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3152 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3153 self.assertEqual(obj._value, obj_copied._value)
3155 @given(data_strategy())
3156 def test_stripped(self, d):
3157 value = d.draw(text(alphabet=self.text_alphabet()))
3158 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3159 obj = self.base_klass(value, impl=tag_impl)
3160 with self.assertRaises(NotEnoughData):
3161 obj.decode(obj.encode()[:-1])
3163 @given(data_strategy())
3164 def test_stripped_expl(self, d):
3165 value = d.draw(text(alphabet=self.text_alphabet()))
3166 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3167 obj = self.base_klass(value, expl=tag_expl)
3168 with self.assertRaises(NotEnoughData):
3169 obj.decode(obj.encode()[:-1])
3172 integers(min_value=31),
3173 integers(min_value=0),
3176 def test_bad_tag(self, tag, offset, decode_path):
3177 with self.assertRaises(DecodeError) as err:
3178 self.base_klass().decode(
3179 tag_encode(tag)[:-1],
3181 decode_path=decode_path,
3184 self.assertEqual(err.exception.offset, offset)
3185 self.assertEqual(err.exception.decode_path, decode_path)
3188 integers(min_value=128),
3189 integers(min_value=0),
3192 def test_bad_len(self, l, offset, decode_path):
3193 with self.assertRaises(DecodeError) as err:
3194 self.base_klass().decode(
3195 self.base_klass.tag_default + len_encode(l)[:-1],
3197 decode_path=decode_path,
3200 self.assertEqual(err.exception.offset, offset)
3201 self.assertEqual(err.exception.decode_path, decode_path)
3204 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3205 integers(min_value=0),
3208 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3209 value, bound_min = list(sorted(ints))
3211 class String(self.base_klass):
3212 # Multiply this value by four, to satisfy UTF-32 bounds
3213 # (4 bytes per character) validation
3214 bounds = (bound_min * 4, bound_min * 4)
3215 with self.assertRaises(DecodeError) as err:
3217 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3219 decode_path=decode_path,
3222 self.assertEqual(err.exception.offset, offset)
3223 self.assertEqual(err.exception.decode_path, decode_path)
3225 @given(data_strategy())
3226 def test_symmetric(self, d):
3227 values = d.draw(string_values_strategy(self.text_alphabet()))
3228 value = d.draw(text(alphabet=self.text_alphabet()))
3229 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3230 offset = d.draw(integers(min_value=0))
3231 tail_junk = d.draw(binary(max_size=5))
3232 _, _, _, _, default, optional, _decoded = values
3233 obj = self.base_klass(
3241 pprint(obj, big_blobs=True, with_decode_path=True)
3242 self.assertFalse(obj.expled)
3243 obj_encoded = obj.encode()
3244 obj_expled = obj(value, expl=tag_expl)
3245 self.assertTrue(obj_expled.expled)
3247 list(obj_expled.pps())
3248 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3249 obj_expled_encoded = obj_expled.encode()
3250 obj_decoded, tail = obj_expled.decode(
3251 obj_expled_encoded + tail_junk,
3255 list(obj_decoded.pps())
3256 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3257 self.assertEqual(tail, tail_junk)
3258 self.assertEqual(obj_decoded, obj_expled)
3259 self.assertNotEqual(obj_decoded, obj)
3260 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3261 self.assertEqual(bytes(obj_decoded), bytes(obj))
3262 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3263 self.assertEqual(text_type(obj_decoded), text_type(obj))
3264 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3265 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3266 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3268 obj_decoded.expl_llen,
3269 len(len_encode(len(obj_encoded))),
3271 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3272 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3275 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3277 self.assertEqual(obj_decoded.expl_offset, offset)
3280 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3281 base_klass = UTF8String
3284 class UnicodeDecodeErrorMixin(object):
3286 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3290 def test_unicode_decode_error(self, cyrillic_text):
3291 with self.assertRaises(DecodeError):
3292 self.base_klass(cyrillic_text)
3295 class TestNumericString(StringMixin, CommonMixin, TestCase):
3296 base_klass = NumericString
3298 def text_alphabet(self):
3301 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3302 def test_non_numeric(self, non_numeric_text):
3303 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3304 self.base_klass(non_numeric_text)
3307 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3308 integers(min_value=0),
3311 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3312 value, bound_min = list(sorted(ints))
3314 class String(self.base_klass):
3315 bounds = (bound_min, bound_min)
3316 with self.assertRaises(DecodeError) as err:
3318 self.base_klass(b"1" * value).encode(),
3320 decode_path=decode_path,
3323 self.assertEqual(err.exception.offset, offset)
3324 self.assertEqual(err.exception.decode_path, decode_path)
3327 class TestPrintableString(
3328 UnicodeDecodeErrorMixin,
3333 base_klass = PrintableString
3336 class TestTeletexString(
3337 UnicodeDecodeErrorMixin,
3342 base_klass = TeletexString
3345 class TestVideotexString(
3346 UnicodeDecodeErrorMixin,
3351 base_klass = VideotexString
3354 class TestIA5String(
3355 UnicodeDecodeErrorMixin,
3360 base_klass = IA5String
3363 class TestGraphicString(
3364 UnicodeDecodeErrorMixin,
3369 base_klass = GraphicString
3372 class TestVisibleString(
3373 UnicodeDecodeErrorMixin,
3378 base_klass = VisibleString
3380 def test_x690_vector(self):
3381 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3382 self.assertSequenceEqual(tail, b"")
3383 self.assertEqual(str(obj), "Jones")
3384 self.assertFalse(obj.ber_encoded)
3385 self.assertFalse(obj.lenindef)
3386 self.assertFalse(obj.bered)
3388 obj, tail = VisibleString().decode(
3389 hexdec("3A0904034A6F6E04026573"),
3390 ctx={"bered": True},
3392 self.assertSequenceEqual(tail, b"")
3393 self.assertEqual(str(obj), "Jones")
3394 self.assertTrue(obj.ber_encoded)
3395 self.assertFalse(obj.lenindef)
3396 self.assertTrue(obj.bered)
3398 obj, tail = VisibleString().decode(
3399 hexdec("3A8004034A6F6E040265730000"),
3400 ctx={"bered": True},
3402 self.assertSequenceEqual(tail, b"")
3403 self.assertEqual(str(obj), "Jones")
3404 self.assertTrue(obj.ber_encoded)
3405 self.assertTrue(obj.lenindef)
3406 self.assertTrue(obj.bered)
3409 class TestGeneralString(
3410 UnicodeDecodeErrorMixin,
3415 base_klass = GeneralString
3418 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3419 base_klass = UniversalString
3422 class TestBMPString(StringMixin, CommonMixin, TestCase):
3423 base_klass = BMPString
3427 def generalized_time_values_strategy(
3435 if draw(booleans()):
3436 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3438 value = value.replace(microsecond=0)
3440 if draw(booleans()):
3441 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3443 default = default.replace(microsecond=0)
3447 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3449 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3450 optional = draw(one_of(none(), booleans()))
3452 draw(integers(min_value=0)),
3453 draw(integers(min_value=0)),
3454 draw(integers(min_value=0)),
3456 return (value, impl, expl, default, optional, _decoded)
3459 class TimeMixin(object):
3460 def test_invalid_value_type(self):
3461 with self.assertRaises(InvalidValueType) as err:
3462 self.base_klass(datetime.now().timetuple())
3465 @given(data_strategy())
3466 def test_optional(self, d):
3467 default = d.draw(datetimes(
3468 min_value=self.min_datetime,
3469 max_value=self.max_datetime,
3471 optional = d.draw(booleans())
3472 obj = self.base_klass(default=default, optional=optional)
3473 self.assertTrue(obj.optional)
3475 @given(data_strategy())
3476 def test_ready(self, d):
3477 obj = self.base_klass()
3478 self.assertFalse(obj.ready)
3481 pprint(obj, big_blobs=True, with_decode_path=True)
3482 with self.assertRaises(ObjNotReady) as err:
3485 value = d.draw(datetimes(min_value=self.min_datetime))
3486 obj = self.base_klass(value)
3487 self.assertTrue(obj.ready)
3490 pprint(obj, big_blobs=True, with_decode_path=True)
3492 @given(data_strategy())
3493 def test_comparison(self, d):
3494 value1 = d.draw(datetimes(
3495 min_value=self.min_datetime,
3496 max_value=self.max_datetime,
3498 value2 = d.draw(datetimes(
3499 min_value=self.min_datetime,
3500 max_value=self.max_datetime,
3502 tag1 = d.draw(binary(min_size=1))
3503 tag2 = d.draw(binary(min_size=1))
3505 value1 = value1.replace(microsecond=0)
3506 value2 = value2.replace(microsecond=0)
3507 obj1 = self.base_klass(value1)
3508 obj2 = self.base_klass(value2)
3509 self.assertEqual(obj1 == obj2, value1 == value2)
3510 self.assertEqual(obj1 != obj2, value1 != value2)
3511 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3512 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3513 obj1 = self.base_klass(value1, impl=tag1)
3514 obj2 = self.base_klass(value1, impl=tag2)
3515 self.assertEqual(obj1 == obj2, tag1 == tag2)
3516 self.assertEqual(obj1 != obj2, tag1 != tag2)
3518 @given(data_strategy())
3519 def test_call(self, d):
3527 ) = d.draw(generalized_time_values_strategy(
3528 min_datetime=self.min_datetime,
3529 max_datetime=self.max_datetime,
3530 omit_ms=self.omit_ms,
3532 obj_initial = self.base_klass(
3533 value=value_initial,
3536 default=default_initial,
3537 optional=optional_initial or False,
3538 _decoded=_decoded_initial,
3547 ) = d.draw(generalized_time_values_strategy(
3548 min_datetime=self.min_datetime,
3549 max_datetime=self.max_datetime,
3550 omit_ms=self.omit_ms,
3551 do_expl=impl_initial is None,
3561 value_expected = default if value is None else value
3563 default_initial if value_expected is None
3566 self.assertEqual(obj, value_expected)
3567 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3568 self.assertEqual(obj.expl_tag, expl or expl_initial)
3571 default_initial if default is None else default,
3573 if obj.default is None:
3574 optional = optional_initial if optional is None else optional
3575 optional = False if optional is None else optional
3578 self.assertEqual(obj.optional, optional)
3580 @given(data_strategy())
3581 def test_copy(self, d):
3582 values = d.draw(generalized_time_values_strategy(
3583 min_datetime=self.min_datetime,
3584 max_datetime=self.max_datetime,
3586 obj = self.base_klass(*values)
3587 obj_copied = obj.copy()
3588 self.assert_copied_basic_fields(obj, obj_copied)
3589 self.assertEqual(obj._value, obj_copied._value)
3591 @given(data_strategy())
3592 def test_stripped(self, d):
3593 value = d.draw(datetimes(
3594 min_value=self.min_datetime,
3595 max_value=self.max_datetime,
3597 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3598 obj = self.base_klass(value, impl=tag_impl)
3599 with self.assertRaises(NotEnoughData):
3600 obj.decode(obj.encode()[:-1])
3602 @given(data_strategy())
3603 def test_stripped_expl(self, d):
3604 value = d.draw(datetimes(
3605 min_value=self.min_datetime,
3606 max_value=self.max_datetime,
3608 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3609 obj = self.base_klass(value, expl=tag_expl)
3610 with self.assertRaises(NotEnoughData):
3611 obj.decode(obj.encode()[:-1])
3613 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3614 @given(data_strategy())
3615 def test_symmetric(self, d):
3616 values = d.draw(generalized_time_values_strategy(
3617 min_datetime=self.min_datetime,
3618 max_datetime=self.max_datetime,
3620 value = d.draw(datetimes(
3621 min_value=self.min_datetime,
3622 max_value=self.max_datetime,
3624 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3625 offset = d.draw(integers(min_value=0))
3626 tail_junk = d.draw(binary(max_size=5))
3627 _, _, _, default, optional, _decoded = values
3628 obj = self.base_klass(
3636 pprint(obj, big_blobs=True, with_decode_path=True)
3637 self.assertFalse(obj.expled)
3638 obj_encoded = obj.encode()
3639 obj_expled = obj(value, expl=tag_expl)
3640 self.assertTrue(obj_expled.expled)
3642 list(obj_expled.pps())
3643 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3644 obj_expled_encoded = obj_expled.encode()
3645 obj_decoded, tail = obj_expled.decode(
3646 obj_expled_encoded + tail_junk,
3650 list(obj_decoded.pps())
3651 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3652 self.assertEqual(tail, tail_junk)
3653 self.assertEqual(obj_decoded, obj_expled)
3654 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3655 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3656 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3657 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3658 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3660 obj_decoded.expl_llen,
3661 len(len_encode(len(obj_encoded))),
3663 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3664 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3667 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3669 self.assertEqual(obj_decoded.expl_offset, offset)
3672 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3673 base_klass = GeneralizedTime
3675 min_datetime = datetime(1900, 1, 1)
3676 max_datetime = datetime(9999, 12, 31)
3678 def test_go_vectors_invalid(self):
3690 b"-20100102030410Z",
3691 b"2010-0102030410Z",
3692 b"2010-0002030410Z",
3693 b"201001-02030410Z",
3694 b"20100102-030410Z",
3695 b"2010010203-0410Z",
3696 b"201001020304-10Z",
3697 # These ones are INVALID in *DER*, but accepted
3698 # by Go's encoding/asn1
3699 b"20100102030405+0607",
3700 b"20100102030405-0607",
3702 with self.assertRaises(DecodeError) as err:
3703 GeneralizedTime(data)
3706 def test_go_vectors_valid(self):
3708 GeneralizedTime(b"20100102030405Z").todatetime(),
3709 datetime(2010, 1, 2, 3, 4, 5, 0),
3714 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3715 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3717 binary(min_size=1, max_size=1),
3719 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3720 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3723 def test_junk(self, part0, part1, part2):
3724 junk = part0 + part1 + part2
3725 assume(not (set(junk) <= set(digits.encode("ascii"))))
3726 with self.assertRaises(DecodeError):
3727 GeneralizedTime().decode(
3728 GeneralizedTime.tag_default +
3729 len_encode(len(junk)) +
3735 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3736 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3738 binary(min_size=1, max_size=1),
3740 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3741 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3744 def test_junk_dm(self, part0, part1, part2):
3745 junk = part0 + part1 + part2
3746 assume(not (set(junk) <= set(digits.encode("ascii"))))
3747 with self.assertRaises(DecodeError):
3748 GeneralizedTime().decode(
3749 GeneralizedTime.tag_default +
3750 len_encode(len(junk)) +
3755 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3756 base_klass = UTCTime
3758 min_datetime = datetime(2000, 1, 1)
3759 max_datetime = datetime(2049, 12, 31)
3761 def test_go_vectors_invalid(self):
3787 # These ones are INVALID in *DER*, but accepted
3788 # by Go's encoding/asn1
3789 b"910506164540-0700",
3790 b"910506164540+0730",
3794 with self.assertRaises(DecodeError) as err:
3798 def test_go_vectors_valid(self):
3800 UTCTime(b"910506234540Z").todatetime(),
3801 datetime(1991, 5, 6, 23, 45, 40, 0),
3804 @given(integers(min_value=0, max_value=49))
3805 def test_pre50(self, year):
3807 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3811 @given(integers(min_value=50, max_value=99))
3812 def test_post50(self, year):
3814 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3820 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3821 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3823 binary(min_size=1, max_size=1),
3825 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3826 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3829 def test_junk(self, part0, part1, part2):
3830 junk = part0 + part1 + part2
3831 assume(not (set(junk) <= set(digits.encode("ascii"))))
3832 with self.assertRaises(DecodeError):
3834 UTCTime.tag_default +
3835 len_encode(len(junk)) +
3841 def any_values_strategy(draw, do_expl=False):
3842 value = draw(one_of(none(), binary()))
3845 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3846 optional = draw(one_of(none(), booleans()))
3848 draw(integers(min_value=0)),
3849 draw(integers(min_value=0)),
3850 draw(integers(min_value=0)),
3852 return (value, expl, optional, _decoded)
3855 class AnyInherited(Any):
3859 class TestAny(CommonMixin, TestCase):
3862 def test_invalid_value_type(self):
3863 with self.assertRaises(InvalidValueType) as err:
3868 def test_optional(self, optional):
3869 obj = Any(optional=optional)
3870 self.assertEqual(obj.optional, optional)
3873 def test_ready(self, value):
3875 self.assertFalse(obj.ready)
3878 pprint(obj, big_blobs=True, with_decode_path=True)
3879 with self.assertRaises(ObjNotReady) as err:
3883 self.assertTrue(obj.ready)
3886 pprint(obj, big_blobs=True, with_decode_path=True)
3889 def test_basic(self, value):
3890 integer_encoded = Integer(value).encode()
3892 Any(integer_encoded),
3893 Any(Integer(value)),
3894 Any(Any(Integer(value))),
3896 self.assertSequenceEqual(bytes(obj), integer_encoded)
3898 obj.decode(obj.encode())[0].vlen,
3899 len(integer_encoded),
3903 pprint(obj, big_blobs=True, with_decode_path=True)
3904 self.assertSequenceEqual(obj.encode(), integer_encoded)
3906 @given(binary(), binary())
3907 def test_comparison(self, value1, value2):
3908 for klass in (Any, AnyInherited):
3909 obj1 = klass(value1)
3910 obj2 = klass(value2)
3911 self.assertEqual(obj1 == obj2, value1 == value2)
3912 self.assertEqual(obj1 != obj2, value1 != value2)
3913 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3915 @given(data_strategy())
3916 def test_call(self, d):
3917 for klass in (Any, AnyInherited):
3923 ) = d.draw(any_values_strategy())
3924 obj_initial = klass(
3927 optional_initial or False,
3935 ) = d.draw(any_values_strategy(do_expl=True))
3936 obj = obj_initial(value, expl, optional)
3938 value_expected = None if value is None else value
3939 self.assertEqual(obj, value_expected)
3940 self.assertEqual(obj.expl_tag, expl or expl_initial)
3941 if obj.default is None:
3942 optional = optional_initial if optional is None else optional
3943 optional = False if optional is None else optional
3944 self.assertEqual(obj.optional, optional)
3946 def test_simultaneous_impl_expl(self):
3947 # override it, as Any does not have implicit tag
3950 def test_decoded(self):
3951 # override it, as Any does not have implicit tag
3954 @given(any_values_strategy())
3955 def test_copy(self, values):
3956 for klass in (Any, AnyInherited):
3957 obj = klass(*values)
3958 obj_copied = obj.copy()
3959 self.assert_copied_basic_fields(obj, obj_copied)
3960 self.assertEqual(obj._value, obj_copied._value)
3962 @given(binary().map(OctetString))
3963 def test_stripped(self, value):
3965 with self.assertRaises(NotEnoughData):
3966 obj.decode(obj.encode()[:-1])
3970 integers(min_value=1).map(tag_ctxc),
3972 def test_stripped_expl(self, value, tag_expl):
3973 obj = Any(value, expl=tag_expl)
3974 with self.assertRaises(NotEnoughData):
3975 obj.decode(obj.encode()[:-1])
3978 integers(min_value=31),
3979 integers(min_value=0),
3982 def test_bad_tag(self, tag, offset, decode_path):
3983 with self.assertRaises(DecodeError) as err:
3985 tag_encode(tag)[:-1],
3987 decode_path=decode_path,
3990 self.assertEqual(err.exception.offset, offset)
3991 self.assertEqual(err.exception.decode_path, decode_path)
3994 integers(min_value=128),
3995 integers(min_value=0),
3998 def test_bad_len(self, l, offset, decode_path):
3999 with self.assertRaises(DecodeError) as err:
4001 Any.tag_default + len_encode(l)[:-1],
4003 decode_path=decode_path,
4006 self.assertEqual(err.exception.offset, offset)
4007 self.assertEqual(err.exception.decode_path, decode_path)
4009 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4011 any_values_strategy(),
4012 integers().map(lambda x: Integer(x).encode()),
4013 integers(min_value=1).map(tag_ctxc),
4014 integers(min_value=0),
4017 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4018 for klass in (Any, AnyInherited):
4019 _, _, optional, _decoded = values
4020 obj = klass(value=value, optional=optional, _decoded=_decoded)
4023 pprint(obj, big_blobs=True, with_decode_path=True)
4024 self.assertFalse(obj.expled)
4025 obj_encoded = obj.encode()
4026 obj_expled = obj(value, expl=tag_expl)
4027 self.assertTrue(obj_expled.expled)
4029 list(obj_expled.pps())
4030 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4031 obj_expled_encoded = obj_expled.encode()
4032 obj_decoded, tail = obj_expled.decode(
4033 obj_expled_encoded + tail_junk,
4037 list(obj_decoded.pps())
4038 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4039 self.assertEqual(tail, tail_junk)
4040 self.assertEqual(obj_decoded, obj_expled)
4041 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4042 self.assertEqual(bytes(obj_decoded), bytes(obj))
4043 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4044 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4045 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4047 obj_decoded.expl_llen,
4048 len(len_encode(len(obj_encoded))),
4050 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4051 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4054 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4056 self.assertEqual(obj_decoded.expl_offset, offset)
4057 self.assertEqual(obj_decoded.tlen, 0)
4058 self.assertEqual(obj_decoded.llen, 0)
4059 self.assertEqual(obj_decoded.vlen, len(value))
4062 integers(min_value=1).map(tag_ctxc),
4063 integers(min_value=0, max_value=3),
4064 integers(min_value=0),
4068 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4069 chunk = Boolean(False, expl=expl).encode()
4071 OctetString.tag_default +
4073 b"".join([chunk] * chunks) +
4076 with self.assertRaises(LenIndefForm):
4080 decode_path=decode_path,
4082 obj, tail = Any().decode(
4085 decode_path=decode_path,
4086 ctx={"bered": True},
4088 self.assertSequenceEqual(tail, junk)
4089 self.assertEqual(obj.offset, offset)
4090 self.assertEqual(obj.tlvlen, len(encoded))
4091 self.assertTrue(obj.lenindef)
4092 self.assertFalse(obj.ber_encoded)
4093 self.assertTrue(obj.bered)
4096 pprint(obj, big_blobs=True, with_decode_path=True)
4097 with self.assertRaises(NotEnoughData) as err:
4101 decode_path=decode_path,
4102 ctx={"bered": True},
4104 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4105 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4107 class SeqOf(SequenceOf):
4108 schema = Boolean(expl=expl)
4110 class Seq(Sequence):
4112 ("type", ObjectIdentifier(defines=((("value",), {
4113 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4118 ("type", ObjectIdentifier("1.2.3")),
4119 ("value", Any(encoded)),
4121 seq_encoded = seq.encode()
4122 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4123 self.assertIsNotNone(seq_decoded["value"].defined)
4125 list(seq_decoded.pps())
4126 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4127 self.assertTrue(seq_decoded.bered)
4128 self.assertFalse(seq_decoded["type"].bered)
4129 self.assertTrue(seq_decoded["value"].bered)
4131 chunk = chunk[:-1] + b"\x01"
4132 chunks = b"".join([chunk] * (chunks + 1))
4133 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4135 ("type", ObjectIdentifier("1.2.3")),
4136 ("value", Any(encoded)),
4138 seq_encoded = seq.encode()
4139 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4140 self.assertIsNotNone(seq_decoded["value"].defined)
4142 list(seq_decoded.pps())
4143 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4144 self.assertTrue(seq_decoded.bered)
4145 self.assertFalse(seq_decoded["type"].bered)
4146 self.assertTrue(seq_decoded["value"].bered)
4150 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4152 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4153 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4155 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4156 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4158 min_size=len(names),
4159 max_size=len(names),
4162 (name, Integer(**tag_kwargs))
4163 for name, tag_kwargs in zip(names, tags)
4166 if value_required or draw(booleans()):
4167 value = draw(tuples(
4168 sampled_from([name for name, _ in schema]),
4169 integers().map(Integer),
4173 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4174 default = draw(one_of(
4176 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4178 optional = draw(one_of(none(), booleans()))
4180 draw(integers(min_value=0)),
4181 draw(integers(min_value=0)),
4182 draw(integers(min_value=0)),
4184 return (schema, value, expl, default, optional, _decoded)
4187 class ChoiceInherited(Choice):
4191 class TestChoice(CommonMixin, TestCase):
4193 schema = (("whatever", Boolean()),)
4196 def test_schema_required(self):
4197 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4200 def test_impl_forbidden(self):
4201 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4202 Choice(impl=b"whatever")
4204 def test_invalid_value_type(self):
4205 with self.assertRaises(InvalidValueType) as err:
4206 self.base_klass(123)
4208 with self.assertRaises(ObjUnknown) as err:
4209 self.base_klass(("whenever", Boolean(False)))
4211 with self.assertRaises(InvalidValueType) as err:
4212 self.base_klass(("whatever", Integer(123)))
4216 def test_optional(self, optional):
4217 obj = self.base_klass(
4218 default=self.base_klass(("whatever", Boolean(False))),
4221 self.assertTrue(obj.optional)
4224 def test_ready(self, value):
4225 obj = self.base_klass()
4226 self.assertFalse(obj.ready)
4229 pprint(obj, big_blobs=True, with_decode_path=True)
4230 self.assertIsNone(obj["whatever"])
4231 with self.assertRaises(ObjNotReady) as err:
4234 obj["whatever"] = Boolean()
4235 self.assertFalse(obj.ready)
4238 pprint(obj, big_blobs=True, with_decode_path=True)
4239 obj["whatever"] = Boolean(value)
4240 self.assertTrue(obj.ready)
4243 pprint(obj, big_blobs=True, with_decode_path=True)
4245 @given(booleans(), booleans())
4246 def test_comparison(self, value1, value2):
4247 class WahlInherited(self.base_klass):
4249 for klass in (self.base_klass, WahlInherited):
4250 obj1 = klass(("whatever", Boolean(value1)))
4251 obj2 = klass(("whatever", Boolean(value2)))
4252 self.assertEqual(obj1 == obj2, value1 == value2)
4253 self.assertEqual(obj1 != obj2, value1 != value2)
4254 self.assertEqual(obj1 == obj2._value, value1 == value2)
4255 self.assertFalse(obj1 == obj2._value[1])
4257 @given(data_strategy())
4258 def test_call(self, d):
4259 for klass in (Choice, ChoiceInherited):
4267 ) = d.draw(choice_values_strategy())
4270 schema = schema_initial
4272 value=value_initial,
4274 default=default_initial,
4275 optional=optional_initial or False,
4276 _decoded=_decoded_initial,
4285 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4286 obj = obj_initial(value, expl, default, optional)
4288 value_expected = default if value is None else value
4290 default_initial if value_expected is None
4293 self.assertEqual(obj.choice, value_expected[0])
4294 self.assertEqual(obj.value, int(value_expected[1]))
4295 self.assertEqual(obj.expl_tag, expl or expl_initial)
4296 default_expect = default_initial if default is None else default
4297 if default_expect is not None:
4298 self.assertEqual(obj.default.choice, default_expect[0])
4299 self.assertEqual(obj.default.value, int(default_expect[1]))
4300 if obj.default is None:
4301 optional = optional_initial if optional is None else optional
4302 optional = False if optional is None else optional
4305 self.assertEqual(obj.optional, optional)
4306 self.assertEqual(obj.specs, obj_initial.specs)
4308 def test_simultaneous_impl_expl(self):
4309 # override it, as Any does not have implicit tag
4312 def test_decoded(self):
4313 # override it, as Any does not have implicit tag
4316 @given(choice_values_strategy())
4317 def test_copy(self, values):
4318 _schema, value, expl, default, optional, _decoded = values
4320 class Wahl(self.base_klass):
4326 optional=optional or False,
4329 obj_copied = obj.copy()
4330 self.assertIsNone(obj.tag)
4331 self.assertIsNone(obj_copied.tag)
4332 # hack for assert_copied_basic_fields
4333 obj.tag = "whatever"
4334 obj_copied.tag = "whatever"
4335 self.assert_copied_basic_fields(obj, obj_copied)
4336 self.assertEqual(obj._value, obj_copied._value)
4337 self.assertEqual(obj.specs, obj_copied.specs)
4340 def test_stripped(self, value):
4341 obj = self.base_klass(("whatever", Boolean(value)))
4342 with self.assertRaises(NotEnoughData):
4343 obj.decode(obj.encode()[:-1])
4347 integers(min_value=1).map(tag_ctxc),
4349 def test_stripped_expl(self, value, tag_expl):
4350 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4351 with self.assertRaises(NotEnoughData):
4352 obj.decode(obj.encode()[:-1])
4354 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4355 @given(data_strategy())
4356 def test_symmetric(self, d):
4357 _schema, value, _, default, optional, _decoded = d.draw(
4358 choice_values_strategy(value_required=True)
4360 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4361 offset = d.draw(integers(min_value=0))
4362 tail_junk = d.draw(binary(max_size=5))
4364 class Wahl(self.base_klass):
4374 pprint(obj, big_blobs=True, with_decode_path=True)
4375 self.assertFalse(obj.expled)
4376 obj_encoded = obj.encode()
4377 obj_expled = obj(value, expl=tag_expl)
4378 self.assertTrue(obj_expled.expled)
4380 list(obj_expled.pps())
4381 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4382 obj_expled_encoded = obj_expled.encode()
4383 obj_decoded, tail = obj_expled.decode(
4384 obj_expled_encoded + tail_junk,
4388 list(obj_decoded.pps())
4389 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4390 self.assertEqual(tail, tail_junk)
4391 self.assertEqual(obj_decoded, obj_expled)
4392 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4393 self.assertEqual(obj_decoded.value, obj_expled.value)
4394 self.assertEqual(obj_decoded.choice, obj.choice)
4395 self.assertEqual(obj_decoded.value, obj.value)
4396 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4397 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4398 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4400 obj_decoded.expl_llen,
4401 len(len_encode(len(obj_encoded))),
4403 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4404 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4407 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4409 self.assertEqual(obj_decoded.expl_offset, offset)
4410 self.assertSequenceEqual(
4412 obj_decoded.value.fulloffset - offset:
4413 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4419 def test_set_get(self, value):
4422 ("erste", Boolean()),
4423 ("zweite", Integer()),
4426 with self.assertRaises(ObjUnknown) as err:
4427 obj["whatever"] = "whenever"
4428 with self.assertRaises(InvalidValueType) as err:
4429 obj["zweite"] = Boolean(False)
4430 obj["zweite"] = Integer(value)
4432 with self.assertRaises(ObjUnknown) as err:
4435 self.assertIsNone(obj["erste"])
4436 self.assertEqual(obj["zweite"], Integer(value))
4438 def test_tag_mismatch(self):
4441 ("erste", Boolean()),
4443 int_encoded = Integer(123).encode()
4444 bool_encoded = Boolean(False).encode()
4446 obj.decode(bool_encoded)
4447 with self.assertRaises(TagMismatch):
4448 obj.decode(int_encoded)
4450 def test_tag_mismatch_underlying(self):
4451 class SeqOfBoolean(SequenceOf):
4454 class SeqOfInteger(SequenceOf):
4459 ("erste", SeqOfBoolean()),
4462 int_encoded = SeqOfInteger((Integer(123),)).encode()
4463 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4465 obj.decode(bool_encoded)
4466 with self.assertRaises(TagMismatch) as err:
4467 obj.decode(int_encoded)
4468 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4472 def seq_values_strategy(draw, seq_klass, do_expl=False):
4474 if draw(booleans()):
4477 k: v for k, v in draw(dictionaries(
4480 booleans().map(Boolean),
4481 integers().map(Integer),
4486 if draw(booleans()):
4487 schema = list(draw(dictionaries(
4490 booleans().map(Boolean),
4491 integers().map(Integer),
4497 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4499 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4501 if draw(booleans()):
4502 default = seq_klass()
4504 k: v for k, v in draw(dictionaries(
4507 booleans().map(Boolean),
4508 integers().map(Integer),
4512 optional = draw(one_of(none(), booleans()))
4514 draw(integers(min_value=0)),
4515 draw(integers(min_value=0)),
4516 draw(integers(min_value=0)),
4518 return (value, schema, impl, expl, default, optional, _decoded)
4522 def sequence_strategy(draw, seq_klass):
4523 inputs = draw(lists(
4525 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4526 tuples(just(Integer), integers(), one_of(none(), integers())),
4531 integers(min_value=1),
4532 min_size=len(inputs),
4533 max_size=len(inputs),
4536 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4537 for tag, expled in zip(tags, draw(lists(
4539 min_size=len(inputs),
4540 max_size=len(inputs),
4544 for i, optional in enumerate(draw(lists(
4545 sampled_from(("required", "optional", "empty")),
4546 min_size=len(inputs),
4547 max_size=len(inputs),
4549 if optional in ("optional", "empty"):
4550 inits[i]["optional"] = True
4551 if optional == "empty":
4553 empties = set(empties)
4554 names = list(draw(sets(
4556 min_size=len(inputs),
4557 max_size=len(inputs),
4560 for i, (klass, value, default) in enumerate(inputs):
4561 schema.append((names[i], klass(default=default, **inits[i])))
4562 seq_name = draw(text_letters())
4563 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4566 for i, (klass, value, default) in enumerate(inputs):
4573 "default_value": None if spec.default is None else default,
4577 expect["optional"] = True
4579 expect["presented"] = True
4580 expect["value"] = value
4582 expect["optional"] = True
4583 if default is not None and default == value:
4584 expect["presented"] = False
4585 seq[name] = klass(value)
4586 expects.append(expect)
4591 def sequences_strategy(draw, seq_klass):
4592 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4594 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4595 for tag, expled in zip(tags, draw(lists(
4602 i for i, is_default in enumerate(draw(lists(
4608 names = list(draw(sets(
4613 seq_expectses = draw(lists(
4614 sequence_strategy(seq_klass=seq_klass),
4618 seqs = [seq for seq, _ in seq_expectses]
4620 for i, (name, seq) in enumerate(zip(names, seqs)):
4623 seq(default=(seq if i in defaulted else None), **inits[i]),
4625 seq_name = draw(text_letters())
4626 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4629 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4632 "expects": expects_inner,
4635 seq_outer[name] = seq_inner
4636 if seq_outer.specs[name].default is None:
4637 expect["presented"] = True
4638 expect_outers.append(expect)
4639 return seq_outer, expect_outers
4642 class SeqMixing(object):
4643 def test_invalid_value_type(self):
4644 with self.assertRaises(InvalidValueType) as err:
4645 self.base_klass(123)
4648 def test_invalid_value_type_set(self):
4649 class Seq(self.base_klass):
4650 schema = (("whatever", Boolean()),)
4652 with self.assertRaises(InvalidValueType) as err:
4653 seq["whatever"] = Integer(123)
4657 def test_optional(self, optional):
4658 obj = self.base_klass(default=self.base_klass(), optional=optional)
4659 self.assertTrue(obj.optional)
4661 @given(data_strategy())
4662 def test_ready(self, d):
4664 str(i): v for i, v in enumerate(d.draw(lists(
4671 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4678 for name in d.draw(permutations(
4679 list(ready.keys()) + list(non_ready.keys()),
4681 schema_input.append((name, Boolean()))
4683 class Seq(self.base_klass):
4684 schema = tuple(schema_input)
4686 for name in ready.keys():
4688 seq[name] = Boolean()
4689 self.assertFalse(seq.ready)
4692 pprint(seq, big_blobs=True, with_decode_path=True)
4693 for name, value in ready.items():
4694 seq[name] = Boolean(value)
4695 self.assertFalse(seq.ready)
4698 pprint(seq, big_blobs=True, with_decode_path=True)
4699 with self.assertRaises(ObjNotReady) as err:
4702 for name, value in non_ready.items():
4703 seq[name] = Boolean(value)
4704 self.assertTrue(seq.ready)
4707 pprint(seq, big_blobs=True, with_decode_path=True)
4709 @given(data_strategy())
4710 def test_call(self, d):
4711 class SeqInherited(self.base_klass):
4713 for klass in (self.base_klass, SeqInherited):
4722 ) = d.draw(seq_values_strategy(seq_klass=klass))
4723 obj_initial = klass(
4729 optional_initial or False,
4740 ) = d.draw(seq_values_strategy(
4742 do_expl=impl_initial is None,
4744 obj = obj_initial(value, impl, expl, default, optional)
4745 value_expected = default if value is None else value
4747 default_initial if value_expected is None
4750 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4751 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4752 self.assertEqual(obj.expl_tag, expl or expl_initial)
4754 {} if obj.default is None else obj.default._value,
4755 getattr(default_initial if default is None else default, "_value", {}),
4757 if obj.default is None:
4758 optional = optional_initial if optional is None else optional
4759 optional = False if optional is None else optional
4762 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4763 self.assertEqual(obj.optional, optional)
4765 @given(data_strategy())
4766 def test_copy(self, d):
4767 class SeqInherited(self.base_klass):
4769 for klass in (self.base_klass, SeqInherited):
4770 values = d.draw(seq_values_strategy(seq_klass=klass))
4771 obj = klass(*values)
4772 obj_copied = obj.copy()
4773 self.assert_copied_basic_fields(obj, obj_copied)
4774 self.assertEqual(obj.specs, obj_copied.specs)
4775 self.assertEqual(obj._value, obj_copied._value)
4777 @given(data_strategy())
4778 def test_stripped(self, d):
4779 value = d.draw(integers())
4780 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4782 class Seq(self.base_klass):
4784 schema = (("whatever", Integer()),)
4786 seq["whatever"] = Integer(value)
4787 with self.assertRaises(NotEnoughData):
4788 seq.decode(seq.encode()[:-1])
4790 @given(data_strategy())
4791 def test_stripped_expl(self, d):
4792 value = d.draw(integers())
4793 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4795 class Seq(self.base_klass):
4797 schema = (("whatever", Integer()),)
4799 seq["whatever"] = Integer(value)
4800 with self.assertRaises(NotEnoughData):
4801 seq.decode(seq.encode()[:-1])
4803 @given(binary(min_size=2))
4804 def test_non_tag_mismatch_raised(self, junk):
4806 _, _, len_encoded = tag_strip(memoryview(junk))
4807 len_decode(len_encoded)
4813 class Seq(self.base_klass):
4815 ("whatever", Integer()),
4817 ("whenever", Integer()),
4820 seq["whatever"] = Integer(123)
4821 seq["junk"] = Any(junk)
4822 seq["whenever"] = Integer(123)
4823 with self.assertRaises(DecodeError):
4824 seq.decode(seq.encode())
4827 integers(min_value=31),
4828 integers(min_value=0),
4831 def test_bad_tag(self, tag, offset, decode_path):
4832 with self.assertRaises(DecodeError) as err:
4833 self.base_klass().decode(
4834 tag_encode(tag)[:-1],
4836 decode_path=decode_path,
4839 self.assertEqual(err.exception.offset, offset)
4840 self.assertEqual(err.exception.decode_path, decode_path)
4843 integers(min_value=128),
4844 integers(min_value=0),
4847 def test_bad_len(self, l, offset, decode_path):
4848 with self.assertRaises(DecodeError) as err:
4849 self.base_klass().decode(
4850 self.base_klass.tag_default + len_encode(l)[:-1],
4852 decode_path=decode_path,
4855 self.assertEqual(err.exception.offset, offset)
4856 self.assertEqual(err.exception.decode_path, decode_path)
4858 def _assert_expects(self, seq, expects):
4859 for expect in expects:
4861 seq.specs[expect["name"]].optional,
4864 if expect["default_value"] is not None:
4866 seq.specs[expect["name"]].default,
4867 expect["default_value"],
4869 if expect["presented"]:
4870 self.assertIn(expect["name"], seq)
4871 self.assertEqual(seq[expect["name"]], expect["value"])
4873 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4874 @given(data_strategy())
4875 def test_symmetric(self, d):
4876 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4877 tail_junk = d.draw(binary(max_size=5))
4878 self.assertTrue(seq.ready)
4879 self.assertFalse(seq.decoded)
4880 self._assert_expects(seq, expects)
4883 pprint(seq, big_blobs=True, with_decode_path=True)
4884 self.assertTrue(seq.ready)
4885 seq_encoded = seq.encode()
4886 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4887 self.assertFalse(seq_decoded.lenindef)
4888 self.assertFalse(seq_decoded.ber_encoded)
4889 self.assertFalse(seq_decoded.bered)
4891 t, _, lv = tag_strip(seq_encoded)
4892 _, _, v = len_decode(lv)
4893 seq_encoded_lenindef = t + LENINDEF + v + EOC
4894 seq_decoded_lenindef, tail_lenindef = seq.decode(
4895 seq_encoded_lenindef + tail_junk,
4896 ctx={"bered": True},
4898 self.assertTrue(seq_decoded_lenindef.lenindef)
4899 self.assertTrue(seq_decoded_lenindef.bered)
4900 with self.assertRaises(DecodeError):
4901 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4902 with self.assertRaises(DecodeError):
4903 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4904 repr(seq_decoded_lenindef)
4905 list(seq_decoded_lenindef.pps())
4906 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
4907 self.assertTrue(seq_decoded_lenindef.ready)
4909 for decoded, decoded_tail, encoded in (
4910 (seq_decoded, tail, seq_encoded),
4911 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4913 self.assertEqual(decoded_tail, tail_junk)
4914 self._assert_expects(decoded, expects)
4915 self.assertEqual(seq, decoded)
4916 self.assertEqual(decoded.encode(), seq_encoded)
4917 self.assertEqual(decoded.tlvlen, len(encoded))
4918 for expect in expects:
4919 if not expect["presented"]:
4920 self.assertNotIn(expect["name"], decoded)
4922 self.assertIn(expect["name"], decoded)
4923 obj = decoded[expect["name"]]
4924 self.assertTrue(obj.decoded)
4925 offset = obj.expl_offset if obj.expled else obj.offset
4926 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4927 self.assertSequenceEqual(
4928 seq_encoded[offset:offset + tlvlen],
4932 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4933 @given(data_strategy())
4934 def test_symmetric_with_seq(self, d):
4935 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4936 self.assertTrue(seq.ready)
4937 seq_encoded = seq.encode()
4938 seq_decoded, tail = seq.decode(seq_encoded)
4939 self.assertEqual(tail, b"")
4940 self.assertTrue(seq.ready)
4941 self.assertEqual(seq, seq_decoded)
4942 self.assertEqual(seq_decoded.encode(), seq_encoded)
4943 for expect_outer in expect_outers:
4944 if not expect_outer["presented"]:
4945 self.assertNotIn(expect_outer["name"], seq_decoded)
4947 self.assertIn(expect_outer["name"], seq_decoded)
4948 obj = seq_decoded[expect_outer["name"]]
4949 self.assertTrue(obj.decoded)
4950 offset = obj.expl_offset if obj.expled else obj.offset
4951 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4952 self.assertSequenceEqual(
4953 seq_encoded[offset:offset + tlvlen],
4956 self._assert_expects(obj, expect_outer["expects"])
4958 @given(data_strategy())
4959 def test_default_disappears(self, d):
4960 _schema = list(d.draw(dictionaries(
4962 sets(integers(), min_size=2, max_size=2),
4966 class Seq(self.base_klass):
4968 (n, Integer(default=d))
4969 for n, (_, d) in _schema
4972 for name, (value, _) in _schema:
4973 seq[name] = Integer(value)
4974 self.assertEqual(len(seq._value), len(_schema))
4975 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4976 self.assertGreater(len(seq.encode()), len(empty_seq))
4977 for name, (_, default) in _schema:
4978 seq[name] = Integer(default)
4979 self.assertEqual(len(seq._value), 0)
4980 self.assertSequenceEqual(seq.encode(), empty_seq)
4982 @given(data_strategy())
4983 def test_encoded_default_not_accepted(self, d):
4984 _schema = list(d.draw(dictionaries(
4989 tags = [tag_encode(tag) for tag in d.draw(sets(
4990 integers(min_value=0),
4991 min_size=len(_schema),
4992 max_size=len(_schema),
4995 class SeqWithoutDefault(self.base_klass):
4997 (n, Integer(impl=t))
4998 for (n, _), t in zip(_schema, tags)
5000 seq_without_default = SeqWithoutDefault()
5001 for name, value in _schema:
5002 seq_without_default[name] = Integer(value)
5003 seq_encoded = seq_without_default.encode()
5005 class SeqWithDefault(self.base_klass):
5007 (n, Integer(default=v, impl=t))
5008 for (n, v), t in zip(_schema, tags)
5010 seq_with_default = SeqWithDefault()
5011 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5012 seq_with_default.decode(seq_encoded)
5013 for ctx in ({"bered": True}, {"allow_default_values": True}):
5014 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5015 self.assertTrue(seq_decoded.ber_encoded)
5016 self.assertTrue(seq_decoded.bered)
5017 for name, value in _schema:
5018 self.assertEqual(seq_decoded[name], seq_with_default[name])
5019 self.assertEqual(seq_decoded[name], value)
5021 @given(data_strategy())
5022 def test_missing_from_spec(self, d):
5023 names = list(d.draw(sets(text_letters(), min_size=2)))
5024 tags = [tag_encode(tag) for tag in d.draw(sets(
5025 integers(min_value=0),
5026 min_size=len(names),
5027 max_size=len(names),
5029 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5031 class SeqFull(self.base_klass):
5032 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5033 seq_full = SeqFull()
5034 for i, name in enumerate(names):
5035 seq_full[name] = Integer(i)
5036 seq_encoded = seq_full.encode()
5037 altered = names_tags[:-2] + names_tags[-1:]
5039 class SeqMissing(self.base_klass):
5040 schema = [(n, Integer(impl=t)) for n, t in altered]
5041 seq_missing = SeqMissing()
5042 with self.assertRaises(TagMismatch):
5043 seq_missing.decode(seq_encoded)
5045 @given(data_strategy())
5046 def test_bered(self, d):
5047 class Seq(self.base_klass):
5048 schema = (("underlying", Boolean()),)
5049 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5050 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5051 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5052 self.assertFalse(decoded.ber_encoded)
5053 self.assertFalse(decoded.lenindef)
5054 self.assertTrue(decoded.bered)
5056 class Seq(self.base_klass):
5057 schema = (("underlying", OctetString()),)
5059 tag_encode(form=TagFormConstructed, num=4) +
5061 OctetString(b"whatever").encode() +
5064 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5065 with self.assertRaises(DecodeError):
5066 Seq().decode(encoded)
5067 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5068 self.assertFalse(decoded.ber_encoded)
5069 self.assertFalse(decoded.lenindef)
5070 self.assertTrue(decoded.bered)
5073 class TestSequence(SeqMixing, CommonMixin, TestCase):
5074 base_klass = Sequence
5080 def test_remaining(self, value, junk):
5081 class Seq(Sequence):
5083 ("whatever", Integer()),
5085 int_encoded = Integer(value).encode()
5087 Sequence.tag_default,
5088 len_encode(len(int_encoded + junk)),
5091 with assertRaisesRegex(self, DecodeError, "remaining"):
5092 Seq().decode(junked)
5094 @given(sets(text_letters(), min_size=2))
5095 def test_obj_unknown(self, names):
5096 missing = names.pop()
5098 class Seq(Sequence):
5099 schema = [(n, Boolean()) for n in names]
5101 with self.assertRaises(ObjUnknown) as err:
5104 with self.assertRaises(ObjUnknown) as err:
5105 seq[missing] = Boolean()
5108 def test_x690_vector(self):
5109 class Seq(Sequence):
5111 ("name", IA5String()),
5114 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5115 self.assertEqual(seq["name"], "Smith")
5116 self.assertEqual(seq["ok"], True)
5119 class TestSet(SeqMixing, CommonMixin, TestCase):
5122 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5123 @given(data_strategy())
5124 def test_sorted(self, d):
5126 tag_encode(tag) for tag in
5127 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5131 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5133 for name, _ in Seq.schema:
5134 seq[name] = OctetString(b"")
5135 seq_encoded = seq.encode()
5136 seq_decoded, _ = seq.decode(seq_encoded)
5137 self.assertSequenceEqual(
5138 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5139 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5142 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5143 @given(data_strategy())
5144 def test_unsorted(self, d):
5146 tag_encode(tag) for tag in
5147 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5149 tags = d.draw(permutations(tags))
5150 assume(tags != sorted(tags))
5151 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5152 seq_encoded = b"".join((
5154 len_encode(len(encoded)),
5159 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5161 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5162 seq.decode(seq_encoded)
5163 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5164 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5165 self.assertTrue(seq_decoded.ber_encoded)
5166 self.assertTrue(seq_decoded.bered)
5167 self.assertSequenceEqual(
5168 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5174 def seqof_values_strategy(draw, schema=None, do_expl=False):
5176 schema = draw(sampled_from((Boolean(), Integer())))
5177 bound_min, bound_max = sorted(draw(sets(
5178 integers(min_value=0, max_value=10),
5182 if isinstance(schema, Boolean):
5183 values_generator = booleans().map(Boolean)
5184 elif isinstance(schema, Integer):
5185 values_generator = integers().map(Integer)
5186 values_generator = lists(
5191 values = draw(one_of(none(), values_generator))
5195 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5197 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5198 default = draw(one_of(none(), values_generator))
5199 optional = draw(one_of(none(), booleans()))
5201 draw(integers(min_value=0)),
5202 draw(integers(min_value=0)),
5203 draw(integers(min_value=0)),
5208 (bound_min, bound_max),
5217 class SeqOfMixing(object):
5218 def test_invalid_value_type(self):
5219 with self.assertRaises(InvalidValueType) as err:
5220 self.base_klass(123)
5223 def test_invalid_values_type(self):
5224 class SeqOf(self.base_klass):
5226 with self.assertRaises(InvalidValueType) as err:
5227 SeqOf([Integer(123), Boolean(False), Integer(234)])
5230 def test_schema_required(self):
5231 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5232 self.base_klass.__mro__[1]()
5234 @given(booleans(), booleans(), binary(), binary())
5235 def test_comparison(self, value1, value2, tag1, tag2):
5236 class SeqOf(self.base_klass):
5238 obj1 = SeqOf([Boolean(value1)])
5239 obj2 = SeqOf([Boolean(value2)])
5240 self.assertEqual(obj1 == obj2, value1 == value2)
5241 self.assertEqual(obj1 != obj2, value1 != value2)
5242 self.assertEqual(obj1 == list(obj2), value1 == value2)
5243 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5244 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5245 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5246 self.assertEqual(obj1 == obj2, tag1 == tag2)
5247 self.assertEqual(obj1 != obj2, tag1 != tag2)
5249 @given(lists(booleans()))
5250 def test_iter(self, values):
5251 class SeqOf(self.base_klass):
5253 obj = SeqOf([Boolean(value) for value in values])
5254 self.assertEqual(len(obj), len(values))
5255 for i, value in enumerate(obj):
5256 self.assertEqual(value, values[i])
5258 @given(data_strategy())
5259 def test_ready(self, d):
5260 ready = [Integer(v) for v in d.draw(lists(
5267 range(d.draw(integers(min_value=1, max_value=5)))
5270 class SeqOf(self.base_klass):
5272 values = d.draw(permutations(ready + non_ready))
5274 for value in values:
5276 self.assertFalse(seqof.ready)
5279 pprint(seqof, big_blobs=True, with_decode_path=True)
5280 with self.assertRaises(ObjNotReady) as err:
5283 for i, value in enumerate(values):
5284 self.assertEqual(seqof[i], value)
5285 if not seqof[i].ready:
5286 seqof[i] = Integer(i)
5287 self.assertTrue(seqof.ready)
5290 pprint(seqof, big_blobs=True, with_decode_path=True)
5292 def test_spec_mismatch(self):
5293 class SeqOf(self.base_klass):
5296 seqof.append(Integer(123))
5297 with self.assertRaises(ValueError):
5298 seqof.append(Boolean(False))
5299 with self.assertRaises(ValueError):
5300 seqof[0] = Boolean(False)
5302 @given(data_strategy())
5303 def test_bounds_satisfied(self, d):
5304 class SeqOf(self.base_klass):
5306 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5307 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5308 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5309 SeqOf(value=value, bounds=(bound_min, bound_max))
5311 @given(data_strategy())
5312 def test_bounds_unsatisfied(self, d):
5313 class SeqOf(self.base_klass):
5315 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5316 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5317 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5318 with self.assertRaises(BoundsError) as err:
5319 SeqOf(value=value, bounds=(bound_min, bound_max))
5321 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5322 SeqOf(bounds=(bound_min, bound_max)).decode(
5323 SeqOf(value).encode()
5326 value = [Boolean(True)] * d.draw(integers(
5327 min_value=bound_max + 1,
5328 max_value=bound_max + 10,
5330 with self.assertRaises(BoundsError) as err:
5331 SeqOf(value=value, bounds=(bound_min, bound_max))
5333 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5334 SeqOf(bounds=(bound_min, bound_max)).decode(
5335 SeqOf(value).encode()
5339 @given(integers(min_value=1, max_value=10))
5340 def test_out_of_bounds(self, bound_max):
5341 class SeqOf(self.base_klass):
5343 bounds = (0, bound_max)
5345 for _ in range(bound_max):
5346 seqof.append(Integer(123))
5347 with self.assertRaises(BoundsError):
5348 seqof.append(Integer(123))
5350 @given(data_strategy())
5351 def test_call(self, d):
5361 ) = d.draw(seqof_values_strategy())
5363 class SeqOf(self.base_klass):
5364 schema = schema_initial
5365 obj_initial = SeqOf(
5366 value=value_initial,
5367 bounds=bounds_initial,
5370 default=default_initial,
5371 optional=optional_initial or False,
5372 _decoded=_decoded_initial,
5383 ) = d.draw(seqof_values_strategy(
5384 schema=schema_initial,
5385 do_expl=impl_initial is None,
5387 if (default is None) and (obj_initial.default is not None):
5390 (bounds is None) and
5391 (value is not None) and
5392 (bounds_initial is not None) and
5393 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5397 (bounds is None) and
5398 (default is not None) and
5399 (bounds_initial is not None) and
5400 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5412 value_expected = default if value is None else value
5414 default_initial if value_expected is None
5417 value_expected = () if value_expected is None else value_expected
5418 self.assertEqual(obj, value_expected)
5419 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5420 self.assertEqual(obj.expl_tag, expl or expl_initial)
5423 default_initial if default is None else default,
5425 if obj.default is None:
5426 optional = optional_initial if optional is None else optional
5427 optional = False if optional is None else optional
5430 self.assertEqual(obj.optional, optional)
5432 (obj._bound_min, obj._bound_max),
5433 bounds or bounds_initial or (0, float("+inf")),
5436 @given(seqof_values_strategy())
5437 def test_copy(self, values):
5438 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5440 class SeqOf(self.base_klass):
5448 optional=optional or False,
5451 obj_copied = obj.copy()
5452 self.assert_copied_basic_fields(obj, obj_copied)
5453 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5454 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5455 self.assertEqual(obj._value, obj_copied._value)
5459 integers(min_value=1).map(tag_encode),
5461 def test_stripped(self, values, tag_impl):
5462 class SeqOf(self.base_klass):
5463 schema = OctetString()
5464 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5465 with self.assertRaises(NotEnoughData):
5466 obj.decode(obj.encode()[:-1])
5470 integers(min_value=1).map(tag_ctxc),
5472 def test_stripped_expl(self, values, tag_expl):
5473 class SeqOf(self.base_klass):
5474 schema = OctetString()
5475 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5476 with self.assertRaises(NotEnoughData):
5477 obj.decode(obj.encode()[:-1])
5480 integers(min_value=31),
5481 integers(min_value=0),
5484 def test_bad_tag(self, tag, offset, decode_path):
5485 with self.assertRaises(DecodeError) as err:
5486 self.base_klass().decode(
5487 tag_encode(tag)[:-1],
5489 decode_path=decode_path,
5492 self.assertEqual(err.exception.offset, offset)
5493 self.assertEqual(err.exception.decode_path, decode_path)
5496 integers(min_value=128),
5497 integers(min_value=0),
5500 def test_bad_len(self, l, offset, decode_path):
5501 with self.assertRaises(DecodeError) as err:
5502 self.base_klass().decode(
5503 self.base_klass.tag_default + len_encode(l)[:-1],
5505 decode_path=decode_path,
5508 self.assertEqual(err.exception.offset, offset)
5509 self.assertEqual(err.exception.decode_path, decode_path)
5511 @given(binary(min_size=1))
5512 def test_tag_mismatch(self, impl):
5513 assume(impl != self.base_klass.tag_default)
5514 with self.assertRaises(TagMismatch):
5515 self.base_klass(impl=impl).decode(self.base_klass().encode())
5517 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5519 seqof_values_strategy(schema=Integer()),
5520 lists(integers().map(Integer)),
5521 integers(min_value=1).map(tag_ctxc),
5522 integers(min_value=0),
5525 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5526 _, _, _, _, _, default, optional, _decoded = values
5528 class SeqOf(self.base_klass):
5538 pprint(obj, big_blobs=True, with_decode_path=True)
5539 self.assertFalse(obj.expled)
5540 obj_encoded = obj.encode()
5541 obj_expled = obj(value, expl=tag_expl)
5542 self.assertTrue(obj_expled.expled)
5544 list(obj_expled.pps())
5545 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5546 obj_expled_encoded = obj_expled.encode()
5547 obj_decoded, tail = obj_expled.decode(
5548 obj_expled_encoded + tail_junk,
5552 list(obj_decoded.pps())
5553 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5554 self.assertEqual(tail, tail_junk)
5555 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5556 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5557 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5558 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5560 obj_decoded.expl_llen,
5561 len(len_encode(len(obj_encoded))),
5563 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5564 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5567 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5569 self.assertEqual(obj_decoded.expl_offset, offset)
5570 for obj_inner in obj_decoded:
5571 self.assertIn(obj_inner, obj_decoded)
5572 self.assertSequenceEqual(
5575 obj_inner.offset - offset:
5576 obj_inner.offset + obj_inner.tlvlen - offset
5580 t, _, lv = tag_strip(obj_encoded)
5581 _, _, v = len_decode(lv)
5582 obj_encoded_lenindef = t + LENINDEF + v + EOC
5583 obj_decoded_lenindef, tail_lenindef = obj.decode(
5584 obj_encoded_lenindef + tail_junk,
5585 ctx={"bered": True},
5587 self.assertTrue(obj_decoded_lenindef.lenindef)
5588 self.assertTrue(obj_decoded_lenindef.bered)
5589 repr(obj_decoded_lenindef)
5590 list(obj_decoded_lenindef.pps())
5591 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5592 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5593 with self.assertRaises(DecodeError):
5594 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5595 with self.assertRaises(DecodeError):
5596 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5598 @given(data_strategy())
5599 def test_bered(self, d):
5600 class SeqOf(self.base_klass):
5602 encoded = Boolean(False).encode()
5603 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5604 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5605 with self.assertRaises(DecodeError):
5606 SeqOf().decode(encoded)
5607 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5608 self.assertFalse(decoded.ber_encoded)
5609 self.assertFalse(decoded.lenindef)
5610 self.assertTrue(decoded.bered)
5612 class SeqOf(self.base_klass):
5613 schema = OctetString()
5614 encoded = OctetString(b"whatever").encode()
5616 tag_encode(form=TagFormConstructed, num=4) +
5618 OctetString(b"whatever").encode() +
5621 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5622 with self.assertRaises(DecodeError):
5623 SeqOf().decode(encoded)
5624 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5625 self.assertFalse(decoded.ber_encoded)
5626 self.assertFalse(decoded.lenindef)
5627 self.assertTrue(decoded.bered)
5630 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5631 class SeqOf(SequenceOf):
5635 def _test_symmetric_compare_objs(self, obj1, obj2):
5636 self.assertEqual(obj1, obj2)
5637 self.assertSequenceEqual(list(obj1), list(obj2))
5640 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5645 def _test_symmetric_compare_objs(self, obj1, obj2):
5646 self.assertSetEqual(
5647 set(int(v) for v in obj1),
5648 set(int(v) for v in obj2),
5651 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5652 @given(data_strategy())
5653 def test_sorted(self, d):
5654 values = [OctetString(v) for v in d.draw(lists(binary()))]
5657 schema = OctetString()
5659 seq_encoded = seq.encode()
5660 seq_decoded, _ = seq.decode(seq_encoded)
5661 self.assertSequenceEqual(
5662 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5663 b"".join(sorted([v.encode() for v in values])),
5666 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5667 @given(data_strategy())
5668 def test_unsorted(self, d):
5669 values = [OctetString(v).encode() for v in d.draw(sets(
5670 binary(min_size=1, max_size=5),
5674 values = d.draw(permutations(values))
5675 assume(values != sorted(values))
5676 encoded = b"".join(values)
5677 seq_encoded = b"".join((
5679 len_encode(len(encoded)),
5684 schema = OctetString()
5686 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5687 seq.decode(seq_encoded)
5689 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5690 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5691 self.assertTrue(seq_decoded.ber_encoded)
5692 self.assertTrue(seq_decoded.bered)
5693 self.assertSequenceEqual(
5694 [obj.encode() for obj in seq_decoded],
5699 class TestGoMarshalVectors(TestCase):
5701 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5702 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5703 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5704 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5705 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5707 class Seq(Sequence):
5709 ("erste", Integer()),
5710 ("zweite", Integer(optional=True))
5713 seq["erste"] = Integer(64)
5714 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5715 seq["erste"] = Integer(0x123456)
5716 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5717 seq["erste"] = Integer(64)
5718 seq["zweite"] = Integer(65)
5719 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5721 class NestedSeq(Sequence):
5725 seq["erste"] = Integer(127)
5726 seq["zweite"] = None
5727 nested = NestedSeq()
5728 nested["nest"] = seq
5729 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5731 self.assertSequenceEqual(
5732 OctetString(b"\x01\x02\x03").encode(),
5733 hexdec("0403010203"),
5736 class Seq(Sequence):
5738 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5741 seq["erste"] = Integer(64)
5742 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5744 class Seq(Sequence):
5746 ("erste", Integer(expl=tag_ctxc(5))),
5749 seq["erste"] = Integer(64)
5750 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5752 class Seq(Sequence):
5755 impl=tag_encode(0, klass=TagClassContext),
5760 seq["erste"] = Null()
5761 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5763 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5765 self.assertSequenceEqual(
5766 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5767 hexdec("170d3730303130313030303030305a"),
5769 self.assertSequenceEqual(
5770 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5771 hexdec("170d3039313131353232353631365a"),
5773 self.assertSequenceEqual(
5774 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5775 hexdec("180f32313030303430353132303130315a"),
5778 class Seq(Sequence):
5780 ("erste", GeneralizedTime()),
5783 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5784 self.assertSequenceEqual(
5786 hexdec("3011180f32303039313131353232353631365a"),
5789 self.assertSequenceEqual(
5790 BitString((1, b"\x80")).encode(),
5793 self.assertSequenceEqual(
5794 BitString((12, b"\x81\xF0")).encode(),
5795 hexdec("03030481f0"),
5798 self.assertSequenceEqual(
5799 ObjectIdentifier("1.2.3.4").encode(),
5800 hexdec("06032a0304"),
5802 self.assertSequenceEqual(
5803 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5804 hexdec("06092a864888932d010105"),
5806 self.assertSequenceEqual(
5807 ObjectIdentifier("2.100.3").encode(),
5808 hexdec("0603813403"),
5811 self.assertSequenceEqual(
5812 PrintableString("test").encode(),
5813 hexdec("130474657374"),
5815 self.assertSequenceEqual(
5816 PrintableString("x" * 127).encode(),
5817 hexdec("137F" + "78" * 127),
5819 self.assertSequenceEqual(
5820 PrintableString("x" * 128).encode(),
5821 hexdec("138180" + "78" * 128),
5823 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5825 class Seq(Sequence):
5827 ("erste", IA5String()),
5830 seq["erste"] = IA5String("test")
5831 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5833 class Seq(Sequence):
5835 ("erste", PrintableString()),
5838 seq["erste"] = PrintableString("test")
5839 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5840 seq["erste"] = PrintableString("test*")
5841 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5843 class Seq(Sequence):
5845 ("erste", Any(optional=True)),
5846 ("zweite", Integer()),
5849 seq["zweite"] = Integer(64)
5850 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5855 seq.append(Integer(10))
5856 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5858 class _SeqOf(SequenceOf):
5859 schema = PrintableString()
5861 class SeqOf(SequenceOf):
5864 _seqof.append(PrintableString("1"))
5866 seqof.append(_seqof)
5867 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5869 class Seq(Sequence):
5871 ("erste", Integer(default=1)),
5874 seq["erste"] = Integer(0)
5875 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5876 seq["erste"] = Integer(1)
5877 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5878 seq["erste"] = Integer(2)
5879 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5882 class TestPP(TestCase):
5883 @given(data_strategy())
5884 def test_oid_printing(self, d):
5886 str(ObjectIdentifier(k)): v * 2
5887 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5889 chosen = d.draw(sampled_from(sorted(oids)))
5890 chosen_id = oids[chosen]
5891 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5892 self.assertNotIn(chosen_id, pp_console_row(pp))
5893 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5896 class TestAutoAddSlots(TestCase):
5898 class Inher(Integer):
5901 with self.assertRaises(AttributeError):
5903 inher.unexistent = "whatever"
5906 class TestOIDDefines(TestCase):
5907 @given(data_strategy())
5908 def runTest(self, d):
5909 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5910 value_name_chosen = d.draw(sampled_from(value_names))
5912 ObjectIdentifier(oid)
5913 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5915 oid_chosen = d.draw(sampled_from(oids))
5916 values = d.draw(lists(
5918 min_size=len(value_names),
5919 max_size=len(value_names),
5922 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5923 oid: Integer() for oid in oids[:-1]
5926 for i, value_name in enumerate(value_names):
5927 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5929 class Seq(Sequence):
5932 for value_name, value in zip(value_names, values):
5933 seq[value_name] = Any(Integer(value).encode())
5934 seq["type"] = oid_chosen
5935 seq, _ = Seq().decode(seq.encode())
5936 for value_name in value_names:
5937 if value_name == value_name_chosen:
5939 self.assertIsNone(seq[value_name].defined)
5940 if value_name_chosen in oids[:-1]:
5941 self.assertIsNotNone(seq[value_name_chosen].defined)
5942 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5943 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5946 pprint(seq, big_blobs=True, with_decode_path=True)
5949 class TestDefinesByPath(TestCase):
5950 def test_generated(self):
5951 class Seq(Sequence):
5953 ("type", ObjectIdentifier()),
5954 ("value", OctetString(expl=tag_ctxc(123))),
5957 class SeqInner(Sequence):
5959 ("typeInner", ObjectIdentifier()),
5960 ("valueInner", Any()),
5963 class PairValue(SetOf):
5966 class Pair(Sequence):
5968 ("type", ObjectIdentifier()),
5969 ("value", PairValue()),
5972 class Pairs(SequenceOf):
5979 type_octet_stringed,
5981 ObjectIdentifier(oid)
5982 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5984 seq_integered = Seq()
5985 seq_integered["type"] = type_integered
5986 seq_integered["value"] = OctetString(Integer(123).encode())
5987 seq_integered_raw = seq_integered.encode()
5991 (type_octet_stringed, OctetString(b"whatever")),
5992 (type_integered, Integer(123)),
5993 (type_octet_stringed, OctetString(b"whenever")),
5994 (type_integered, Integer(234)),
5996 for t, v in pairs_input:
5999 pair["value"] = PairValue((Any(v),))
6001 seq_inner = SeqInner()
6002 seq_inner["typeInner"] = type_innered
6003 seq_inner["valueInner"] = Any(pairs)
6004 seq_sequenced = Seq()
6005 seq_sequenced["type"] = type_sequenced
6006 seq_sequenced["value"] = OctetString(seq_inner.encode())
6007 seq_sequenced_raw = seq_sequenced.encode()
6009 list(seq_sequenced.pps())
6010 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6012 defines_by_path = []
6013 seq_integered, _ = Seq().decode(seq_integered_raw)
6014 self.assertIsNone(seq_integered["value"].defined)
6015 defines_by_path.append(
6016 (("type",), ((("value",), {
6017 type_integered: Integer(),
6018 type_sequenced: SeqInner(),
6021 seq_integered, _ = Seq().decode(
6023 ctx={"defines_by_path": defines_by_path},
6025 self.assertIsNotNone(seq_integered["value"].defined)
6026 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6027 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6028 self.assertTrue(seq_integered_raw[
6029 seq_integered["value"].defined[1].offset:
6030 ].startswith(Integer(123).encode()))
6032 list(seq_integered.pps())
6033 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6035 seq_sequenced, _ = Seq().decode(
6037 ctx={"defines_by_path": defines_by_path},
6039 self.assertIsNotNone(seq_sequenced["value"].defined)
6040 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6041 seq_inner = seq_sequenced["value"].defined[1]
6042 self.assertIsNone(seq_inner["valueInner"].defined)
6044 list(seq_sequenced.pps())
6045 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6047 defines_by_path.append((
6048 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6049 ((("valueInner",), {type_innered: Pairs()}),),
6051 seq_sequenced, _ = Seq().decode(
6053 ctx={"defines_by_path": defines_by_path},
6055 self.assertIsNotNone(seq_sequenced["value"].defined)
6056 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6057 seq_inner = seq_sequenced["value"].defined[1]
6058 self.assertIsNotNone(seq_inner["valueInner"].defined)
6059 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6060 pairs = seq_inner["valueInner"].defined[1]
6062 self.assertIsNone(pair["value"][0].defined)
6064 list(seq_sequenced.pps())
6065 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6067 defines_by_path.append((
6070 DecodePathDefBy(type_sequenced),
6072 DecodePathDefBy(type_innered),
6077 type_integered: Integer(),
6078 type_octet_stringed: OctetString(),
6081 seq_sequenced, _ = Seq().decode(
6083 ctx={"defines_by_path": defines_by_path},
6085 self.assertIsNotNone(seq_sequenced["value"].defined)
6086 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6087 seq_inner = seq_sequenced["value"].defined[1]
6088 self.assertIsNotNone(seq_inner["valueInner"].defined)
6089 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6090 pairs_got = seq_inner["valueInner"].defined[1]
6091 for pair_input, pair_got in zip(pairs_input, pairs_got):
6092 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6093 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6095 list(seq_sequenced.pps())
6096 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6098 @given(oid_strategy(), integers())
6099 def test_simple(self, oid, tgt):
6100 class Inner(Sequence):
6102 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6103 ObjectIdentifier(oid): Integer(),
6107 class Outer(Sequence):
6110 ("tgt", OctetString()),
6114 inner["oid"] = ObjectIdentifier(oid)
6116 outer["inner"] = inner
6117 outer["tgt"] = OctetString(Integer(tgt).encode())
6118 decoded, _ = Outer().decode(outer.encode())
6119 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6122 class TestAbsDecodePath(TestCase):
6124 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6125 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6127 def test_concat(self, decode_path, rel_path):
6128 self.assertSequenceEqual(
6129 abs_decode_path(decode_path, rel_path),
6130 decode_path + rel_path,
6134 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6135 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6137 def test_abs(self, decode_path, rel_path):
6138 self.assertSequenceEqual(
6139 abs_decode_path(decode_path, ("/",) + rel_path),
6144 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6145 integers(min_value=1, max_value=3),
6146 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6148 def test_dots(self, decode_path, number_of_dots, rel_path):
6149 self.assertSequenceEqual(
6150 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6151 decode_path[:-number_of_dots] + rel_path,
6155 class TestStrictDefaultExistence(TestCase):
6156 @given(data_strategy())
6157 def runTest(self, d):
6158 count = d.draw(integers(min_value=1, max_value=10))
6159 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6161 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6162 for i in range(count)
6164 for klass in (Sequence, Set):
6168 for i in range(count):
6169 seq["int%d" % i] = Integer(123)
6171 chosen_choice = "int%d" % chosen
6172 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6173 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6175 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6176 self.assertTrue(decoded.ber_encoded)
6177 self.assertTrue(decoded.bered)
6178 decoded, _ = seq.decode(raw, ctx={"bered": True})
6179 self.assertTrue(decoded.ber_encoded)
6180 self.assertTrue(decoded.bered)
6183 class TestX690PrefixedType(TestCase):
6185 self.assertSequenceEqual(
6186 VisibleString("Jones").encode(),
6187 hexdec("1A054A6F6E6573"),
6189 self.assertSequenceEqual(
6192 impl=tag_encode(3, klass=TagClassApplication),
6194 hexdec("43054A6F6E6573"),
6196 self.assertSequenceEqual(
6200 impl=tag_encode(3, klass=TagClassApplication),
6204 hexdec("A20743054A6F6E6573"),
6206 self.assertSequenceEqual(
6210 impl=tag_encode(3, klass=TagClassApplication),
6212 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6214 hexdec("670743054A6F6E6573"),
6216 self.assertSequenceEqual(
6217 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6218 hexdec("82054A6F6E6573"),
6222 class TestExplOOB(TestCase):
6224 expl = tag_ctxc(123)
6225 raw = Integer(123).encode() + Integer(234).encode()
6226 raw = b"".join((expl, len_encode(len(raw)), raw))
6227 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6228 Integer(expl=expl).decode(raw)
6229 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})