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 cyrillic_letters = text(
3285 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3291 class UnicodeDecodeErrorMixin(object):
3292 @given(cyrillic_letters)
3293 def test_unicode_decode_error(self, cyrillic_text):
3294 with self.assertRaises(DecodeError):
3295 self.base_klass(cyrillic_text)
3298 class TestNumericString(StringMixin, CommonMixin, TestCase):
3299 base_klass = NumericString
3301 def text_alphabet(self):
3304 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3305 def test_non_numeric(self, non_numeric_text):
3306 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3307 self.base_klass(non_numeric_text)
3310 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3311 integers(min_value=0),
3314 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3315 value, bound_min = list(sorted(ints))
3317 class String(self.base_klass):
3318 bounds = (bound_min, bound_min)
3319 with self.assertRaises(DecodeError) as err:
3321 self.base_klass(b"1" * value).encode(),
3323 decode_path=decode_path,
3326 self.assertEqual(err.exception.offset, offset)
3327 self.assertEqual(err.exception.decode_path, decode_path)
3330 class TestPrintableString(
3331 UnicodeDecodeErrorMixin,
3336 base_klass = PrintableString
3338 def text_alphabet(self):
3339 return ascii_letters + digits + " '()+,-./:=?"
3341 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3342 def test_non_printable(self, non_printable_text):
3343 with assertRaisesRegex(self, DecodeError, "non-printable"):
3344 self.base_klass(non_printable_text)
3347 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3348 integers(min_value=0),
3351 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3352 value, bound_min = list(sorted(ints))
3354 class String(self.base_klass):
3355 bounds = (bound_min, bound_min)
3356 with self.assertRaises(DecodeError) as err:
3358 self.base_klass(b"1" * value).encode(),
3360 decode_path=decode_path,
3363 self.assertEqual(err.exception.offset, offset)
3364 self.assertEqual(err.exception.decode_path, decode_path)
3367 class TestTeletexString(
3368 UnicodeDecodeErrorMixin,
3373 base_klass = TeletexString
3376 class TestVideotexString(
3377 UnicodeDecodeErrorMixin,
3382 base_klass = VideotexString
3385 class TestIA5String(
3386 UnicodeDecodeErrorMixin,
3391 base_klass = IA5String
3394 class TestGraphicString(
3395 UnicodeDecodeErrorMixin,
3400 base_klass = GraphicString
3403 class TestVisibleString(
3404 UnicodeDecodeErrorMixin,
3409 base_klass = VisibleString
3411 def test_x690_vector(self):
3412 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3413 self.assertSequenceEqual(tail, b"")
3414 self.assertEqual(str(obj), "Jones")
3415 self.assertFalse(obj.ber_encoded)
3416 self.assertFalse(obj.lenindef)
3417 self.assertFalse(obj.bered)
3419 obj, tail = VisibleString().decode(
3420 hexdec("3A0904034A6F6E04026573"),
3421 ctx={"bered": True},
3423 self.assertSequenceEqual(tail, b"")
3424 self.assertEqual(str(obj), "Jones")
3425 self.assertTrue(obj.ber_encoded)
3426 self.assertFalse(obj.lenindef)
3427 self.assertTrue(obj.bered)
3429 obj, tail = VisibleString().decode(
3430 hexdec("3A8004034A6F6E040265730000"),
3431 ctx={"bered": True},
3433 self.assertSequenceEqual(tail, b"")
3434 self.assertEqual(str(obj), "Jones")
3435 self.assertTrue(obj.ber_encoded)
3436 self.assertTrue(obj.lenindef)
3437 self.assertTrue(obj.bered)
3440 class TestGeneralString(
3441 UnicodeDecodeErrorMixin,
3446 base_klass = GeneralString
3449 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3450 base_klass = UniversalString
3453 class TestBMPString(StringMixin, CommonMixin, TestCase):
3454 base_klass = BMPString
3458 def generalized_time_values_strategy(
3466 if draw(booleans()):
3467 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3469 value = value.replace(microsecond=0)
3471 if draw(booleans()):
3472 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3474 default = default.replace(microsecond=0)
3478 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3480 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3481 optional = draw(one_of(none(), booleans()))
3483 draw(integers(min_value=0)),
3484 draw(integers(min_value=0)),
3485 draw(integers(min_value=0)),
3487 return (value, impl, expl, default, optional, _decoded)
3490 class TimeMixin(object):
3491 def test_invalid_value_type(self):
3492 with self.assertRaises(InvalidValueType) as err:
3493 self.base_klass(datetime.now().timetuple())
3496 @given(data_strategy())
3497 def test_optional(self, d):
3498 default = d.draw(datetimes(
3499 min_value=self.min_datetime,
3500 max_value=self.max_datetime,
3502 optional = d.draw(booleans())
3503 obj = self.base_klass(default=default, optional=optional)
3504 self.assertTrue(obj.optional)
3506 @given(data_strategy())
3507 def test_ready(self, d):
3508 obj = self.base_klass()
3509 self.assertFalse(obj.ready)
3512 pprint(obj, big_blobs=True, with_decode_path=True)
3513 with self.assertRaises(ObjNotReady) as err:
3516 value = d.draw(datetimes(min_value=self.min_datetime))
3517 obj = self.base_klass(value)
3518 self.assertTrue(obj.ready)
3521 pprint(obj, big_blobs=True, with_decode_path=True)
3523 @given(data_strategy())
3524 def test_comparison(self, d):
3525 value1 = d.draw(datetimes(
3526 min_value=self.min_datetime,
3527 max_value=self.max_datetime,
3529 value2 = d.draw(datetimes(
3530 min_value=self.min_datetime,
3531 max_value=self.max_datetime,
3533 tag1 = d.draw(binary(min_size=1))
3534 tag2 = d.draw(binary(min_size=1))
3536 value1 = value1.replace(microsecond=0)
3537 value2 = value2.replace(microsecond=0)
3538 obj1 = self.base_klass(value1)
3539 obj2 = self.base_klass(value2)
3540 self.assertEqual(obj1 == obj2, value1 == value2)
3541 self.assertEqual(obj1 != obj2, value1 != value2)
3542 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3543 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3544 obj1 = self.base_klass(value1, impl=tag1)
3545 obj2 = self.base_klass(value1, impl=tag2)
3546 self.assertEqual(obj1 == obj2, tag1 == tag2)
3547 self.assertEqual(obj1 != obj2, tag1 != tag2)
3549 @given(data_strategy())
3550 def test_call(self, d):
3558 ) = d.draw(generalized_time_values_strategy(
3559 min_datetime=self.min_datetime,
3560 max_datetime=self.max_datetime,
3561 omit_ms=self.omit_ms,
3563 obj_initial = self.base_klass(
3564 value=value_initial,
3567 default=default_initial,
3568 optional=optional_initial or False,
3569 _decoded=_decoded_initial,
3578 ) = d.draw(generalized_time_values_strategy(
3579 min_datetime=self.min_datetime,
3580 max_datetime=self.max_datetime,
3581 omit_ms=self.omit_ms,
3582 do_expl=impl_initial is None,
3592 value_expected = default if value is None else value
3594 default_initial if value_expected is None
3597 self.assertEqual(obj, value_expected)
3598 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3599 self.assertEqual(obj.expl_tag, expl or expl_initial)
3602 default_initial if default is None else default,
3604 if obj.default is None:
3605 optional = optional_initial if optional is None else optional
3606 optional = False if optional is None else optional
3609 self.assertEqual(obj.optional, optional)
3611 @given(data_strategy())
3612 def test_copy(self, d):
3613 values = d.draw(generalized_time_values_strategy(
3614 min_datetime=self.min_datetime,
3615 max_datetime=self.max_datetime,
3617 obj = self.base_klass(*values)
3618 obj_copied = obj.copy()
3619 self.assert_copied_basic_fields(obj, obj_copied)
3620 self.assertEqual(obj._value, obj_copied._value)
3622 @given(data_strategy())
3623 def test_stripped(self, d):
3624 value = d.draw(datetimes(
3625 min_value=self.min_datetime,
3626 max_value=self.max_datetime,
3628 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3629 obj = self.base_klass(value, impl=tag_impl)
3630 with self.assertRaises(NotEnoughData):
3631 obj.decode(obj.encode()[:-1])
3633 @given(data_strategy())
3634 def test_stripped_expl(self, d):
3635 value = d.draw(datetimes(
3636 min_value=self.min_datetime,
3637 max_value=self.max_datetime,
3639 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3640 obj = self.base_klass(value, expl=tag_expl)
3641 with self.assertRaises(NotEnoughData):
3642 obj.decode(obj.encode()[:-1])
3644 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3645 @given(data_strategy())
3646 def test_symmetric(self, d):
3647 values = d.draw(generalized_time_values_strategy(
3648 min_datetime=self.min_datetime,
3649 max_datetime=self.max_datetime,
3651 value = d.draw(datetimes(
3652 min_value=self.min_datetime,
3653 max_value=self.max_datetime,
3655 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3656 offset = d.draw(integers(min_value=0))
3657 tail_junk = d.draw(binary(max_size=5))
3658 _, _, _, default, optional, _decoded = values
3659 obj = self.base_klass(
3667 pprint(obj, big_blobs=True, with_decode_path=True)
3668 self.assertFalse(obj.expled)
3669 obj_encoded = obj.encode()
3670 obj_expled = obj(value, expl=tag_expl)
3671 self.assertTrue(obj_expled.expled)
3673 list(obj_expled.pps())
3674 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3675 obj_expled_encoded = obj_expled.encode()
3676 obj_decoded, tail = obj_expled.decode(
3677 obj_expled_encoded + tail_junk,
3681 list(obj_decoded.pps())
3682 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3683 self.assertEqual(tail, tail_junk)
3684 self.assertEqual(obj_decoded, obj_expled)
3685 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3686 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3687 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3688 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3689 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3691 obj_decoded.expl_llen,
3692 len(len_encode(len(obj_encoded))),
3694 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3695 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3698 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3700 self.assertEqual(obj_decoded.expl_offset, offset)
3703 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3704 base_klass = GeneralizedTime
3706 min_datetime = datetime(1900, 1, 1)
3707 max_datetime = datetime(9999, 12, 31)
3709 def test_go_vectors_invalid(self):
3721 b"-20100102030410Z",
3722 b"2010-0102030410Z",
3723 b"2010-0002030410Z",
3724 b"201001-02030410Z",
3725 b"20100102-030410Z",
3726 b"2010010203-0410Z",
3727 b"201001020304-10Z",
3728 # These ones are INVALID in *DER*, but accepted
3729 # by Go's encoding/asn1
3730 b"20100102030405+0607",
3731 b"20100102030405-0607",
3733 with self.assertRaises(DecodeError) as err:
3734 GeneralizedTime(data)
3737 def test_go_vectors_valid(self):
3739 GeneralizedTime(b"20100102030405Z").todatetime(),
3740 datetime(2010, 1, 2, 3, 4, 5, 0),
3745 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3746 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3748 binary(min_size=1, max_size=1),
3750 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3751 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
3754 def test_junk(self, part0, part1, part2):
3755 junk = part0 + part1 + part2
3756 assume(not (set(junk) <= set(digits.encode("ascii"))))
3757 with self.assertRaises(DecodeError):
3758 GeneralizedTime().decode(
3759 GeneralizedTime.tag_default +
3760 len_encode(len(junk)) +
3766 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3767 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3769 binary(min_size=1, max_size=1),
3771 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3772 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
3775 def test_junk_dm(self, part0, part1, part2):
3776 junk = part0 + part1 + part2
3777 assume(not (set(junk) <= set(digits.encode("ascii"))))
3778 with self.assertRaises(DecodeError):
3779 GeneralizedTime().decode(
3780 GeneralizedTime.tag_default +
3781 len_encode(len(junk)) +
3786 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3787 base_klass = UTCTime
3789 min_datetime = datetime(2000, 1, 1)
3790 max_datetime = datetime(2049, 12, 31)
3792 def test_go_vectors_invalid(self):
3818 # These ones are INVALID in *DER*, but accepted
3819 # by Go's encoding/asn1
3820 b"910506164540-0700",
3821 b"910506164540+0730",
3825 with self.assertRaises(DecodeError) as err:
3829 def test_go_vectors_valid(self):
3831 UTCTime(b"910506234540Z").todatetime(),
3832 datetime(1991, 5, 6, 23, 45, 40, 0),
3835 @given(integers(min_value=0, max_value=49))
3836 def test_pre50(self, year):
3838 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3842 @given(integers(min_value=50, max_value=99))
3843 def test_post50(self, year):
3845 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3851 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3852 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3854 binary(min_size=1, max_size=1),
3856 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3857 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
3860 def test_junk(self, part0, part1, part2):
3861 junk = part0 + part1 + part2
3862 assume(not (set(junk) <= set(digits.encode("ascii"))))
3863 with self.assertRaises(DecodeError):
3865 UTCTime.tag_default +
3866 len_encode(len(junk)) +
3872 def any_values_strategy(draw, do_expl=False):
3873 value = draw(one_of(none(), binary()))
3876 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3877 optional = draw(one_of(none(), booleans()))
3879 draw(integers(min_value=0)),
3880 draw(integers(min_value=0)),
3881 draw(integers(min_value=0)),
3883 return (value, expl, optional, _decoded)
3886 class AnyInherited(Any):
3890 class TestAny(CommonMixin, TestCase):
3893 def test_invalid_value_type(self):
3894 with self.assertRaises(InvalidValueType) as err:
3899 def test_optional(self, optional):
3900 obj = Any(optional=optional)
3901 self.assertEqual(obj.optional, optional)
3904 def test_ready(self, value):
3906 self.assertFalse(obj.ready)
3909 pprint(obj, big_blobs=True, with_decode_path=True)
3910 with self.assertRaises(ObjNotReady) as err:
3914 self.assertTrue(obj.ready)
3917 pprint(obj, big_blobs=True, with_decode_path=True)
3920 def test_basic(self, value):
3921 integer_encoded = Integer(value).encode()
3923 Any(integer_encoded),
3924 Any(Integer(value)),
3925 Any(Any(Integer(value))),
3927 self.assertSequenceEqual(bytes(obj), integer_encoded)
3929 obj.decode(obj.encode())[0].vlen,
3930 len(integer_encoded),
3934 pprint(obj, big_blobs=True, with_decode_path=True)
3935 self.assertSequenceEqual(obj.encode(), integer_encoded)
3937 @given(binary(), binary())
3938 def test_comparison(self, value1, value2):
3939 for klass in (Any, AnyInherited):
3940 obj1 = klass(value1)
3941 obj2 = klass(value2)
3942 self.assertEqual(obj1 == obj2, value1 == value2)
3943 self.assertEqual(obj1 != obj2, value1 != value2)
3944 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3946 @given(data_strategy())
3947 def test_call(self, d):
3948 for klass in (Any, AnyInherited):
3954 ) = d.draw(any_values_strategy())
3955 obj_initial = klass(
3958 optional_initial or False,
3966 ) = d.draw(any_values_strategy(do_expl=True))
3967 obj = obj_initial(value, expl, optional)
3969 value_expected = None if value is None else value
3970 self.assertEqual(obj, value_expected)
3971 self.assertEqual(obj.expl_tag, expl or expl_initial)
3972 if obj.default is None:
3973 optional = optional_initial if optional is None else optional
3974 optional = False if optional is None else optional
3975 self.assertEqual(obj.optional, optional)
3977 def test_simultaneous_impl_expl(self):
3978 # override it, as Any does not have implicit tag
3981 def test_decoded(self):
3982 # override it, as Any does not have implicit tag
3985 @given(any_values_strategy())
3986 def test_copy(self, values):
3987 for klass in (Any, AnyInherited):
3988 obj = klass(*values)
3989 obj_copied = obj.copy()
3990 self.assert_copied_basic_fields(obj, obj_copied)
3991 self.assertEqual(obj._value, obj_copied._value)
3993 @given(binary().map(OctetString))
3994 def test_stripped(self, value):
3996 with self.assertRaises(NotEnoughData):
3997 obj.decode(obj.encode()[:-1])
4001 integers(min_value=1).map(tag_ctxc),
4003 def test_stripped_expl(self, value, tag_expl):
4004 obj = Any(value, expl=tag_expl)
4005 with self.assertRaises(NotEnoughData):
4006 obj.decode(obj.encode()[:-1])
4009 integers(min_value=31),
4010 integers(min_value=0),
4013 def test_bad_tag(self, tag, offset, decode_path):
4014 with self.assertRaises(DecodeError) as err:
4016 tag_encode(tag)[:-1],
4018 decode_path=decode_path,
4021 self.assertEqual(err.exception.offset, offset)
4022 self.assertEqual(err.exception.decode_path, decode_path)
4025 integers(min_value=128),
4026 integers(min_value=0),
4029 def test_bad_len(self, l, offset, decode_path):
4030 with self.assertRaises(DecodeError) as err:
4032 Any.tag_default + len_encode(l)[:-1],
4034 decode_path=decode_path,
4037 self.assertEqual(err.exception.offset, offset)
4038 self.assertEqual(err.exception.decode_path, decode_path)
4040 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4042 any_values_strategy(),
4043 integers().map(lambda x: Integer(x).encode()),
4044 integers(min_value=1).map(tag_ctxc),
4045 integers(min_value=0),
4048 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4049 for klass in (Any, AnyInherited):
4050 _, _, optional, _decoded = values
4051 obj = klass(value=value, optional=optional, _decoded=_decoded)
4054 pprint(obj, big_blobs=True, with_decode_path=True)
4055 self.assertFalse(obj.expled)
4056 obj_encoded = obj.encode()
4057 obj_expled = obj(value, expl=tag_expl)
4058 self.assertTrue(obj_expled.expled)
4060 list(obj_expled.pps())
4061 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4062 obj_expled_encoded = obj_expled.encode()
4063 obj_decoded, tail = obj_expled.decode(
4064 obj_expled_encoded + tail_junk,
4068 list(obj_decoded.pps())
4069 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4070 self.assertEqual(tail, tail_junk)
4071 self.assertEqual(obj_decoded, obj_expled)
4072 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4073 self.assertEqual(bytes(obj_decoded), bytes(obj))
4074 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4075 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4076 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4078 obj_decoded.expl_llen,
4079 len(len_encode(len(obj_encoded))),
4081 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4082 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4085 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4087 self.assertEqual(obj_decoded.expl_offset, offset)
4088 self.assertEqual(obj_decoded.tlen, 0)
4089 self.assertEqual(obj_decoded.llen, 0)
4090 self.assertEqual(obj_decoded.vlen, len(value))
4093 integers(min_value=1).map(tag_ctxc),
4094 integers(min_value=0, max_value=3),
4095 integers(min_value=0),
4099 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4100 chunk = Boolean(False, expl=expl).encode()
4102 OctetString.tag_default +
4104 b"".join([chunk] * chunks) +
4107 with self.assertRaises(LenIndefForm):
4111 decode_path=decode_path,
4113 obj, tail = Any().decode(
4116 decode_path=decode_path,
4117 ctx={"bered": True},
4119 self.assertSequenceEqual(tail, junk)
4120 self.assertEqual(obj.offset, offset)
4121 self.assertEqual(obj.tlvlen, len(encoded))
4122 self.assertTrue(obj.lenindef)
4123 self.assertFalse(obj.ber_encoded)
4124 self.assertTrue(obj.bered)
4127 pprint(obj, big_blobs=True, with_decode_path=True)
4128 with self.assertRaises(NotEnoughData) as err:
4132 decode_path=decode_path,
4133 ctx={"bered": True},
4135 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4136 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4138 class SeqOf(SequenceOf):
4139 schema = Boolean(expl=expl)
4141 class Seq(Sequence):
4143 ("type", ObjectIdentifier(defines=((("value",), {
4144 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4149 ("type", ObjectIdentifier("1.2.3")),
4150 ("value", Any(encoded)),
4152 seq_encoded = seq.encode()
4153 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4154 self.assertIsNotNone(seq_decoded["value"].defined)
4156 list(seq_decoded.pps())
4157 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4158 self.assertTrue(seq_decoded.bered)
4159 self.assertFalse(seq_decoded["type"].bered)
4160 self.assertTrue(seq_decoded["value"].bered)
4162 chunk = chunk[:-1] + b"\x01"
4163 chunks = b"".join([chunk] * (chunks + 1))
4164 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4166 ("type", ObjectIdentifier("1.2.3")),
4167 ("value", Any(encoded)),
4169 seq_encoded = seq.encode()
4170 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4171 self.assertIsNotNone(seq_decoded["value"].defined)
4173 list(seq_decoded.pps())
4174 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4175 self.assertTrue(seq_decoded.bered)
4176 self.assertFalse(seq_decoded["type"].bered)
4177 self.assertTrue(seq_decoded["value"].bered)
4181 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4183 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4184 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4186 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4187 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4189 min_size=len(names),
4190 max_size=len(names),
4193 (name, Integer(**tag_kwargs))
4194 for name, tag_kwargs in zip(names, tags)
4197 if value_required or draw(booleans()):
4198 value = draw(tuples(
4199 sampled_from([name for name, _ in schema]),
4200 integers().map(Integer),
4204 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4205 default = draw(one_of(
4207 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
4209 optional = draw(one_of(none(), booleans()))
4211 draw(integers(min_value=0)),
4212 draw(integers(min_value=0)),
4213 draw(integers(min_value=0)),
4215 return (schema, value, expl, default, optional, _decoded)
4218 class ChoiceInherited(Choice):
4222 class TestChoice(CommonMixin, TestCase):
4224 schema = (("whatever", Boolean()),)
4227 def test_schema_required(self):
4228 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4231 def test_impl_forbidden(self):
4232 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
4233 Choice(impl=b"whatever")
4235 def test_invalid_value_type(self):
4236 with self.assertRaises(InvalidValueType) as err:
4237 self.base_klass(123)
4239 with self.assertRaises(ObjUnknown) as err:
4240 self.base_klass(("whenever", Boolean(False)))
4242 with self.assertRaises(InvalidValueType) as err:
4243 self.base_klass(("whatever", Integer(123)))
4247 def test_optional(self, optional):
4248 obj = self.base_klass(
4249 default=self.base_klass(("whatever", Boolean(False))),
4252 self.assertTrue(obj.optional)
4255 def test_ready(self, value):
4256 obj = self.base_klass()
4257 self.assertFalse(obj.ready)
4260 pprint(obj, big_blobs=True, with_decode_path=True)
4261 self.assertIsNone(obj["whatever"])
4262 with self.assertRaises(ObjNotReady) as err:
4265 obj["whatever"] = Boolean()
4266 self.assertFalse(obj.ready)
4269 pprint(obj, big_blobs=True, with_decode_path=True)
4270 obj["whatever"] = Boolean(value)
4271 self.assertTrue(obj.ready)
4274 pprint(obj, big_blobs=True, with_decode_path=True)
4276 @given(booleans(), booleans())
4277 def test_comparison(self, value1, value2):
4278 class WahlInherited(self.base_klass):
4280 for klass in (self.base_klass, WahlInherited):
4281 obj1 = klass(("whatever", Boolean(value1)))
4282 obj2 = klass(("whatever", Boolean(value2)))
4283 self.assertEqual(obj1 == obj2, value1 == value2)
4284 self.assertEqual(obj1 != obj2, value1 != value2)
4285 self.assertEqual(obj1 == obj2._value, value1 == value2)
4286 self.assertFalse(obj1 == obj2._value[1])
4288 @given(data_strategy())
4289 def test_call(self, d):
4290 for klass in (Choice, ChoiceInherited):
4298 ) = d.draw(choice_values_strategy())
4301 schema = schema_initial
4303 value=value_initial,
4305 default=default_initial,
4306 optional=optional_initial or False,
4307 _decoded=_decoded_initial,
4316 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4317 obj = obj_initial(value, expl, default, optional)
4319 value_expected = default if value is None else value
4321 default_initial if value_expected is None
4324 self.assertEqual(obj.choice, value_expected[0])
4325 self.assertEqual(obj.value, int(value_expected[1]))
4326 self.assertEqual(obj.expl_tag, expl or expl_initial)
4327 default_expect = default_initial if default is None else default
4328 if default_expect is not None:
4329 self.assertEqual(obj.default.choice, default_expect[0])
4330 self.assertEqual(obj.default.value, int(default_expect[1]))
4331 if obj.default is None:
4332 optional = optional_initial if optional is None else optional
4333 optional = False if optional is None else optional
4336 self.assertEqual(obj.optional, optional)
4337 self.assertEqual(obj.specs, obj_initial.specs)
4339 def test_simultaneous_impl_expl(self):
4340 # override it, as Any does not have implicit tag
4343 def test_decoded(self):
4344 # override it, as Any does not have implicit tag
4347 @given(choice_values_strategy())
4348 def test_copy(self, values):
4349 _schema, value, expl, default, optional, _decoded = values
4351 class Wahl(self.base_klass):
4357 optional=optional or False,
4360 obj_copied = obj.copy()
4361 self.assertIsNone(obj.tag)
4362 self.assertIsNone(obj_copied.tag)
4363 # hack for assert_copied_basic_fields
4364 obj.tag = "whatever"
4365 obj_copied.tag = "whatever"
4366 self.assert_copied_basic_fields(obj, obj_copied)
4367 self.assertEqual(obj._value, obj_copied._value)
4368 self.assertEqual(obj.specs, obj_copied.specs)
4371 def test_stripped(self, value):
4372 obj = self.base_klass(("whatever", Boolean(value)))
4373 with self.assertRaises(NotEnoughData):
4374 obj.decode(obj.encode()[:-1])
4378 integers(min_value=1).map(tag_ctxc),
4380 def test_stripped_expl(self, value, tag_expl):
4381 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4382 with self.assertRaises(NotEnoughData):
4383 obj.decode(obj.encode()[:-1])
4385 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4386 @given(data_strategy())
4387 def test_symmetric(self, d):
4388 _schema, value, _, default, optional, _decoded = d.draw(
4389 choice_values_strategy(value_required=True)
4391 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4392 offset = d.draw(integers(min_value=0))
4393 tail_junk = d.draw(binary(max_size=5))
4395 class Wahl(self.base_klass):
4405 pprint(obj, big_blobs=True, with_decode_path=True)
4406 self.assertFalse(obj.expled)
4407 obj_encoded = obj.encode()
4408 obj_expled = obj(value, expl=tag_expl)
4409 self.assertTrue(obj_expled.expled)
4411 list(obj_expled.pps())
4412 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4413 obj_expled_encoded = obj_expled.encode()
4414 obj_decoded, tail = obj_expled.decode(
4415 obj_expled_encoded + tail_junk,
4419 list(obj_decoded.pps())
4420 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4421 self.assertEqual(tail, tail_junk)
4422 self.assertEqual(obj_decoded, obj_expled)
4423 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4424 self.assertEqual(obj_decoded.value, obj_expled.value)
4425 self.assertEqual(obj_decoded.choice, obj.choice)
4426 self.assertEqual(obj_decoded.value, obj.value)
4427 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4428 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4429 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4431 obj_decoded.expl_llen,
4432 len(len_encode(len(obj_encoded))),
4434 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4435 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4438 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4440 self.assertEqual(obj_decoded.expl_offset, offset)
4441 self.assertSequenceEqual(
4443 obj_decoded.value.fulloffset - offset:
4444 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4450 def test_set_get(self, value):
4453 ("erste", Boolean()),
4454 ("zweite", Integer()),
4457 with self.assertRaises(ObjUnknown) as err:
4458 obj["whatever"] = "whenever"
4459 with self.assertRaises(InvalidValueType) as err:
4460 obj["zweite"] = Boolean(False)
4461 obj["zweite"] = Integer(value)
4463 with self.assertRaises(ObjUnknown) as err:
4466 self.assertIsNone(obj["erste"])
4467 self.assertEqual(obj["zweite"], Integer(value))
4469 def test_tag_mismatch(self):
4472 ("erste", Boolean()),
4474 int_encoded = Integer(123).encode()
4475 bool_encoded = Boolean(False).encode()
4477 obj.decode(bool_encoded)
4478 with self.assertRaises(TagMismatch):
4479 obj.decode(int_encoded)
4481 def test_tag_mismatch_underlying(self):
4482 class SeqOfBoolean(SequenceOf):
4485 class SeqOfInteger(SequenceOf):
4490 ("erste", SeqOfBoolean()),
4493 int_encoded = SeqOfInteger((Integer(123),)).encode()
4494 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4496 obj.decode(bool_encoded)
4497 with self.assertRaises(TagMismatch) as err:
4498 obj.decode(int_encoded)
4499 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4503 def seq_values_strategy(draw, seq_klass, do_expl=False):
4505 if draw(booleans()):
4508 k: v for k, v in draw(dictionaries(
4511 booleans().map(Boolean),
4512 integers().map(Integer),
4517 if draw(booleans()):
4518 schema = list(draw(dictionaries(
4521 booleans().map(Boolean),
4522 integers().map(Integer),
4528 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4530 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4532 if draw(booleans()):
4533 default = seq_klass()
4535 k: v for k, v in draw(dictionaries(
4538 booleans().map(Boolean),
4539 integers().map(Integer),
4543 optional = draw(one_of(none(), booleans()))
4545 draw(integers(min_value=0)),
4546 draw(integers(min_value=0)),
4547 draw(integers(min_value=0)),
4549 return (value, schema, impl, expl, default, optional, _decoded)
4553 def sequence_strategy(draw, seq_klass):
4554 inputs = draw(lists(
4556 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4557 tuples(just(Integer), integers(), one_of(none(), integers())),
4562 integers(min_value=1),
4563 min_size=len(inputs),
4564 max_size=len(inputs),
4567 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4568 for tag, expled in zip(tags, draw(lists(
4570 min_size=len(inputs),
4571 max_size=len(inputs),
4575 for i, optional in enumerate(draw(lists(
4576 sampled_from(("required", "optional", "empty")),
4577 min_size=len(inputs),
4578 max_size=len(inputs),
4580 if optional in ("optional", "empty"):
4581 inits[i]["optional"] = True
4582 if optional == "empty":
4584 empties = set(empties)
4585 names = list(draw(sets(
4587 min_size=len(inputs),
4588 max_size=len(inputs),
4591 for i, (klass, value, default) in enumerate(inputs):
4592 schema.append((names[i], klass(default=default, **inits[i])))
4593 seq_name = draw(text_letters())
4594 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4597 for i, (klass, value, default) in enumerate(inputs):
4604 "default_value": None if spec.default is None else default,
4608 expect["optional"] = True
4610 expect["presented"] = True
4611 expect["value"] = value
4613 expect["optional"] = True
4614 if default is not None and default == value:
4615 expect["presented"] = False
4616 seq[name] = klass(value)
4617 expects.append(expect)
4622 def sequences_strategy(draw, seq_klass):
4623 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4625 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4626 for tag, expled in zip(tags, draw(lists(
4633 i for i, is_default in enumerate(draw(lists(
4639 names = list(draw(sets(
4644 seq_expectses = draw(lists(
4645 sequence_strategy(seq_klass=seq_klass),
4649 seqs = [seq for seq, _ in seq_expectses]
4651 for i, (name, seq) in enumerate(zip(names, seqs)):
4654 seq(default=(seq if i in defaulted else None), **inits[i]),
4656 seq_name = draw(text_letters())
4657 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4660 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4663 "expects": expects_inner,
4666 seq_outer[name] = seq_inner
4667 if seq_outer.specs[name].default is None:
4668 expect["presented"] = True
4669 expect_outers.append(expect)
4670 return seq_outer, expect_outers
4673 class SeqMixing(object):
4674 def test_invalid_value_type(self):
4675 with self.assertRaises(InvalidValueType) as err:
4676 self.base_klass(123)
4679 def test_invalid_value_type_set(self):
4680 class Seq(self.base_klass):
4681 schema = (("whatever", Boolean()),)
4683 with self.assertRaises(InvalidValueType) as err:
4684 seq["whatever"] = Integer(123)
4688 def test_optional(self, optional):
4689 obj = self.base_klass(default=self.base_klass(), optional=optional)
4690 self.assertTrue(obj.optional)
4692 @given(data_strategy())
4693 def test_ready(self, d):
4695 str(i): v for i, v in enumerate(d.draw(lists(
4702 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4709 for name in d.draw(permutations(
4710 list(ready.keys()) + list(non_ready.keys()),
4712 schema_input.append((name, Boolean()))
4714 class Seq(self.base_klass):
4715 schema = tuple(schema_input)
4717 for name in ready.keys():
4719 seq[name] = Boolean()
4720 self.assertFalse(seq.ready)
4723 pprint(seq, big_blobs=True, with_decode_path=True)
4724 for name, value in ready.items():
4725 seq[name] = Boolean(value)
4726 self.assertFalse(seq.ready)
4729 pprint(seq, big_blobs=True, with_decode_path=True)
4730 with self.assertRaises(ObjNotReady) as err:
4733 for name, value in non_ready.items():
4734 seq[name] = Boolean(value)
4735 self.assertTrue(seq.ready)
4738 pprint(seq, big_blobs=True, with_decode_path=True)
4740 @given(data_strategy())
4741 def test_call(self, d):
4742 class SeqInherited(self.base_klass):
4744 for klass in (self.base_klass, SeqInherited):
4753 ) = d.draw(seq_values_strategy(seq_klass=klass))
4754 obj_initial = klass(
4760 optional_initial or False,
4771 ) = d.draw(seq_values_strategy(
4773 do_expl=impl_initial is None,
4775 obj = obj_initial(value, impl, expl, default, optional)
4776 value_expected = default if value is None else value
4778 default_initial if value_expected is None
4781 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4782 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4783 self.assertEqual(obj.expl_tag, expl or expl_initial)
4785 {} if obj.default is None else obj.default._value,
4786 getattr(default_initial if default is None else default, "_value", {}),
4788 if obj.default is None:
4789 optional = optional_initial if optional is None else optional
4790 optional = False if optional is None else optional
4793 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4794 self.assertEqual(obj.optional, optional)
4796 @given(data_strategy())
4797 def test_copy(self, d):
4798 class SeqInherited(self.base_klass):
4800 for klass in (self.base_klass, SeqInherited):
4801 values = d.draw(seq_values_strategy(seq_klass=klass))
4802 obj = klass(*values)
4803 obj_copied = obj.copy()
4804 self.assert_copied_basic_fields(obj, obj_copied)
4805 self.assertEqual(obj.specs, obj_copied.specs)
4806 self.assertEqual(obj._value, obj_copied._value)
4808 @given(data_strategy())
4809 def test_stripped(self, d):
4810 value = d.draw(integers())
4811 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4813 class Seq(self.base_klass):
4815 schema = (("whatever", Integer()),)
4817 seq["whatever"] = Integer(value)
4818 with self.assertRaises(NotEnoughData):
4819 seq.decode(seq.encode()[:-1])
4821 @given(data_strategy())
4822 def test_stripped_expl(self, d):
4823 value = d.draw(integers())
4824 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4826 class Seq(self.base_klass):
4828 schema = (("whatever", Integer()),)
4830 seq["whatever"] = Integer(value)
4831 with self.assertRaises(NotEnoughData):
4832 seq.decode(seq.encode()[:-1])
4834 @given(binary(min_size=2))
4835 def test_non_tag_mismatch_raised(self, junk):
4837 _, _, len_encoded = tag_strip(memoryview(junk))
4838 len_decode(len_encoded)
4844 class Seq(self.base_klass):
4846 ("whatever", Integer()),
4848 ("whenever", Integer()),
4851 seq["whatever"] = Integer(123)
4852 seq["junk"] = Any(junk)
4853 seq["whenever"] = Integer(123)
4854 with self.assertRaises(DecodeError):
4855 seq.decode(seq.encode())
4858 integers(min_value=31),
4859 integers(min_value=0),
4862 def test_bad_tag(self, tag, offset, decode_path):
4863 with self.assertRaises(DecodeError) as err:
4864 self.base_klass().decode(
4865 tag_encode(tag)[:-1],
4867 decode_path=decode_path,
4870 self.assertEqual(err.exception.offset, offset)
4871 self.assertEqual(err.exception.decode_path, decode_path)
4874 integers(min_value=128),
4875 integers(min_value=0),
4878 def test_bad_len(self, l, offset, decode_path):
4879 with self.assertRaises(DecodeError) as err:
4880 self.base_klass().decode(
4881 self.base_klass.tag_default + len_encode(l)[:-1],
4883 decode_path=decode_path,
4886 self.assertEqual(err.exception.offset, offset)
4887 self.assertEqual(err.exception.decode_path, decode_path)
4889 def _assert_expects(self, seq, expects):
4890 for expect in expects:
4892 seq.specs[expect["name"]].optional,
4895 if expect["default_value"] is not None:
4897 seq.specs[expect["name"]].default,
4898 expect["default_value"],
4900 if expect["presented"]:
4901 self.assertIn(expect["name"], seq)
4902 self.assertEqual(seq[expect["name"]], expect["value"])
4904 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4905 @given(data_strategy())
4906 def test_symmetric(self, d):
4907 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4908 tail_junk = d.draw(binary(max_size=5))
4909 self.assertTrue(seq.ready)
4910 self.assertFalse(seq.decoded)
4911 self._assert_expects(seq, expects)
4914 pprint(seq, big_blobs=True, with_decode_path=True)
4915 self.assertTrue(seq.ready)
4916 seq_encoded = seq.encode()
4917 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4918 self.assertFalse(seq_decoded.lenindef)
4919 self.assertFalse(seq_decoded.ber_encoded)
4920 self.assertFalse(seq_decoded.bered)
4922 t, _, lv = tag_strip(seq_encoded)
4923 _, _, v = len_decode(lv)
4924 seq_encoded_lenindef = t + LENINDEF + v + EOC
4925 seq_decoded_lenindef, tail_lenindef = seq.decode(
4926 seq_encoded_lenindef + tail_junk,
4927 ctx={"bered": True},
4929 self.assertTrue(seq_decoded_lenindef.lenindef)
4930 self.assertTrue(seq_decoded_lenindef.bered)
4931 with self.assertRaises(DecodeError):
4932 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4933 with self.assertRaises(DecodeError):
4934 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4935 repr(seq_decoded_lenindef)
4936 list(seq_decoded_lenindef.pps())
4937 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
4938 self.assertTrue(seq_decoded_lenindef.ready)
4940 for decoded, decoded_tail, encoded in (
4941 (seq_decoded, tail, seq_encoded),
4942 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4944 self.assertEqual(decoded_tail, tail_junk)
4945 self._assert_expects(decoded, expects)
4946 self.assertEqual(seq, decoded)
4947 self.assertEqual(decoded.encode(), seq_encoded)
4948 self.assertEqual(decoded.tlvlen, len(encoded))
4949 for expect in expects:
4950 if not expect["presented"]:
4951 self.assertNotIn(expect["name"], decoded)
4953 self.assertIn(expect["name"], decoded)
4954 obj = decoded[expect["name"]]
4955 self.assertTrue(obj.decoded)
4956 offset = obj.expl_offset if obj.expled else obj.offset
4957 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4958 self.assertSequenceEqual(
4959 seq_encoded[offset:offset + tlvlen],
4963 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4964 @given(data_strategy())
4965 def test_symmetric_with_seq(self, d):
4966 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4967 self.assertTrue(seq.ready)
4968 seq_encoded = seq.encode()
4969 seq_decoded, tail = seq.decode(seq_encoded)
4970 self.assertEqual(tail, b"")
4971 self.assertTrue(seq.ready)
4972 self.assertEqual(seq, seq_decoded)
4973 self.assertEqual(seq_decoded.encode(), seq_encoded)
4974 for expect_outer in expect_outers:
4975 if not expect_outer["presented"]:
4976 self.assertNotIn(expect_outer["name"], seq_decoded)
4978 self.assertIn(expect_outer["name"], seq_decoded)
4979 obj = seq_decoded[expect_outer["name"]]
4980 self.assertTrue(obj.decoded)
4981 offset = obj.expl_offset if obj.expled else obj.offset
4982 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4983 self.assertSequenceEqual(
4984 seq_encoded[offset:offset + tlvlen],
4987 self._assert_expects(obj, expect_outer["expects"])
4989 @given(data_strategy())
4990 def test_default_disappears(self, d):
4991 _schema = list(d.draw(dictionaries(
4993 sets(integers(), min_size=2, max_size=2),
4997 class Seq(self.base_klass):
4999 (n, Integer(default=d))
5000 for n, (_, d) in _schema
5003 for name, (value, _) in _schema:
5004 seq[name] = Integer(value)
5005 self.assertEqual(len(seq._value), len(_schema))
5006 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5007 self.assertGreater(len(seq.encode()), len(empty_seq))
5008 for name, (_, default) in _schema:
5009 seq[name] = Integer(default)
5010 self.assertEqual(len(seq._value), 0)
5011 self.assertSequenceEqual(seq.encode(), empty_seq)
5013 @given(data_strategy())
5014 def test_encoded_default_not_accepted(self, d):
5015 _schema = list(d.draw(dictionaries(
5020 tags = [tag_encode(tag) for tag in d.draw(sets(
5021 integers(min_value=0),
5022 min_size=len(_schema),
5023 max_size=len(_schema),
5026 class SeqWithoutDefault(self.base_klass):
5028 (n, Integer(impl=t))
5029 for (n, _), t in zip(_schema, tags)
5031 seq_without_default = SeqWithoutDefault()
5032 for name, value in _schema:
5033 seq_without_default[name] = Integer(value)
5034 seq_encoded = seq_without_default.encode()
5036 class SeqWithDefault(self.base_klass):
5038 (n, Integer(default=v, impl=t))
5039 for (n, v), t in zip(_schema, tags)
5041 seq_with_default = SeqWithDefault()
5042 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5043 seq_with_default.decode(seq_encoded)
5044 for ctx in ({"bered": True}, {"allow_default_values": True}):
5045 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5046 self.assertTrue(seq_decoded.ber_encoded)
5047 self.assertTrue(seq_decoded.bered)
5048 for name, value in _schema:
5049 self.assertEqual(seq_decoded[name], seq_with_default[name])
5050 self.assertEqual(seq_decoded[name], value)
5052 @given(data_strategy())
5053 def test_missing_from_spec(self, d):
5054 names = list(d.draw(sets(text_letters(), min_size=2)))
5055 tags = [tag_encode(tag) for tag in d.draw(sets(
5056 integers(min_value=0),
5057 min_size=len(names),
5058 max_size=len(names),
5060 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5062 class SeqFull(self.base_klass):
5063 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5064 seq_full = SeqFull()
5065 for i, name in enumerate(names):
5066 seq_full[name] = Integer(i)
5067 seq_encoded = seq_full.encode()
5068 altered = names_tags[:-2] + names_tags[-1:]
5070 class SeqMissing(self.base_klass):
5071 schema = [(n, Integer(impl=t)) for n, t in altered]
5072 seq_missing = SeqMissing()
5073 with self.assertRaises(TagMismatch):
5074 seq_missing.decode(seq_encoded)
5076 @given(data_strategy())
5077 def test_bered(self, d):
5078 class Seq(self.base_klass):
5079 schema = (("underlying", Boolean()),)
5080 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5081 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5082 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5083 self.assertFalse(decoded.ber_encoded)
5084 self.assertFalse(decoded.lenindef)
5085 self.assertTrue(decoded.bered)
5087 class Seq(self.base_klass):
5088 schema = (("underlying", OctetString()),)
5090 tag_encode(form=TagFormConstructed, num=4) +
5092 OctetString(b"whatever").encode() +
5095 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5096 with self.assertRaises(DecodeError):
5097 Seq().decode(encoded)
5098 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5099 self.assertFalse(decoded.ber_encoded)
5100 self.assertFalse(decoded.lenindef)
5101 self.assertTrue(decoded.bered)
5104 class TestSequence(SeqMixing, CommonMixin, TestCase):
5105 base_klass = Sequence
5111 def test_remaining(self, value, junk):
5112 class Seq(Sequence):
5114 ("whatever", Integer()),
5116 int_encoded = Integer(value).encode()
5118 Sequence.tag_default,
5119 len_encode(len(int_encoded + junk)),
5122 with assertRaisesRegex(self, DecodeError, "remaining"):
5123 Seq().decode(junked)
5125 @given(sets(text_letters(), min_size=2))
5126 def test_obj_unknown(self, names):
5127 missing = names.pop()
5129 class Seq(Sequence):
5130 schema = [(n, Boolean()) for n in names]
5132 with self.assertRaises(ObjUnknown) as err:
5135 with self.assertRaises(ObjUnknown) as err:
5136 seq[missing] = Boolean()
5139 def test_x690_vector(self):
5140 class Seq(Sequence):
5142 ("name", IA5String()),
5145 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5146 self.assertEqual(seq["name"], "Smith")
5147 self.assertEqual(seq["ok"], True)
5150 class TestSet(SeqMixing, CommonMixin, TestCase):
5153 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5154 @given(data_strategy())
5155 def test_sorted(self, d):
5157 tag_encode(tag) for tag in
5158 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
5162 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5164 for name, _ in Seq.schema:
5165 seq[name] = OctetString(b"")
5166 seq_encoded = seq.encode()
5167 seq_decoded, _ = seq.decode(seq_encoded)
5168 self.assertSequenceEqual(
5169 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5170 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
5173 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5174 @given(data_strategy())
5175 def test_unsorted(self, d):
5177 tag_encode(tag) for tag in
5178 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
5180 tags = d.draw(permutations(tags))
5181 assume(tags != sorted(tags))
5182 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
5183 seq_encoded = b"".join((
5185 len_encode(len(encoded)),
5190 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
5192 with assertRaisesRegex(self, DecodeError, "unordered SET"):
5193 seq.decode(seq_encoded)
5194 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5195 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5196 self.assertTrue(seq_decoded.ber_encoded)
5197 self.assertTrue(seq_decoded.bered)
5198 self.assertSequenceEqual(
5199 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
5205 def seqof_values_strategy(draw, schema=None, do_expl=False):
5207 schema = draw(sampled_from((Boolean(), Integer())))
5208 bound_min, bound_max = sorted(draw(sets(
5209 integers(min_value=0, max_value=10),
5213 if isinstance(schema, Boolean):
5214 values_generator = booleans().map(Boolean)
5215 elif isinstance(schema, Integer):
5216 values_generator = integers().map(Integer)
5217 values_generator = lists(
5222 values = draw(one_of(none(), values_generator))
5226 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5228 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5229 default = draw(one_of(none(), values_generator))
5230 optional = draw(one_of(none(), booleans()))
5232 draw(integers(min_value=0)),
5233 draw(integers(min_value=0)),
5234 draw(integers(min_value=0)),
5239 (bound_min, bound_max),
5248 class SeqOfMixing(object):
5249 def test_invalid_value_type(self):
5250 with self.assertRaises(InvalidValueType) as err:
5251 self.base_klass(123)
5254 def test_invalid_values_type(self):
5255 class SeqOf(self.base_klass):
5257 with self.assertRaises(InvalidValueType) as err:
5258 SeqOf([Integer(123), Boolean(False), Integer(234)])
5261 def test_schema_required(self):
5262 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5263 self.base_klass.__mro__[1]()
5265 @given(booleans(), booleans(), binary(), binary())
5266 def test_comparison(self, value1, value2, tag1, tag2):
5267 class SeqOf(self.base_klass):
5269 obj1 = SeqOf([Boolean(value1)])
5270 obj2 = SeqOf([Boolean(value2)])
5271 self.assertEqual(obj1 == obj2, value1 == value2)
5272 self.assertEqual(obj1 != obj2, value1 != value2)
5273 self.assertEqual(obj1 == list(obj2), value1 == value2)
5274 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
5275 obj1 = SeqOf([Boolean(value1)], impl=tag1)
5276 obj2 = SeqOf([Boolean(value1)], impl=tag2)
5277 self.assertEqual(obj1 == obj2, tag1 == tag2)
5278 self.assertEqual(obj1 != obj2, tag1 != tag2)
5280 @given(lists(booleans()))
5281 def test_iter(self, values):
5282 class SeqOf(self.base_klass):
5284 obj = SeqOf([Boolean(value) for value in values])
5285 self.assertEqual(len(obj), len(values))
5286 for i, value in enumerate(obj):
5287 self.assertEqual(value, values[i])
5289 @given(data_strategy())
5290 def test_ready(self, d):
5291 ready = [Integer(v) for v in d.draw(lists(
5298 range(d.draw(integers(min_value=1, max_value=5)))
5301 class SeqOf(self.base_klass):
5303 values = d.draw(permutations(ready + non_ready))
5305 for value in values:
5307 self.assertFalse(seqof.ready)
5310 pprint(seqof, big_blobs=True, with_decode_path=True)
5311 with self.assertRaises(ObjNotReady) as err:
5314 for i, value in enumerate(values):
5315 self.assertEqual(seqof[i], value)
5316 if not seqof[i].ready:
5317 seqof[i] = Integer(i)
5318 self.assertTrue(seqof.ready)
5321 pprint(seqof, big_blobs=True, with_decode_path=True)
5323 def test_spec_mismatch(self):
5324 class SeqOf(self.base_klass):
5327 seqof.append(Integer(123))
5328 with self.assertRaises(ValueError):
5329 seqof.append(Boolean(False))
5330 with self.assertRaises(ValueError):
5331 seqof[0] = Boolean(False)
5333 @given(data_strategy())
5334 def test_bounds_satisfied(self, d):
5335 class SeqOf(self.base_klass):
5337 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5338 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5339 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5340 SeqOf(value=value, bounds=(bound_min, bound_max))
5342 @given(data_strategy())
5343 def test_bounds_unsatisfied(self, d):
5344 class SeqOf(self.base_klass):
5346 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5347 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5348 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
5349 with self.assertRaises(BoundsError) as err:
5350 SeqOf(value=value, bounds=(bound_min, bound_max))
5352 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5353 SeqOf(bounds=(bound_min, bound_max)).decode(
5354 SeqOf(value).encode()
5357 value = [Boolean(True)] * d.draw(integers(
5358 min_value=bound_max + 1,
5359 max_value=bound_max + 10,
5361 with self.assertRaises(BoundsError) as err:
5362 SeqOf(value=value, bounds=(bound_min, bound_max))
5364 with assertRaisesRegex(self, DecodeError, "bounds") as err:
5365 SeqOf(bounds=(bound_min, bound_max)).decode(
5366 SeqOf(value).encode()
5370 @given(integers(min_value=1, max_value=10))
5371 def test_out_of_bounds(self, bound_max):
5372 class SeqOf(self.base_klass):
5374 bounds = (0, bound_max)
5376 for _ in range(bound_max):
5377 seqof.append(Integer(123))
5378 with self.assertRaises(BoundsError):
5379 seqof.append(Integer(123))
5381 @given(data_strategy())
5382 def test_call(self, d):
5392 ) = d.draw(seqof_values_strategy())
5394 class SeqOf(self.base_klass):
5395 schema = schema_initial
5396 obj_initial = SeqOf(
5397 value=value_initial,
5398 bounds=bounds_initial,
5401 default=default_initial,
5402 optional=optional_initial or False,
5403 _decoded=_decoded_initial,
5414 ) = d.draw(seqof_values_strategy(
5415 schema=schema_initial,
5416 do_expl=impl_initial is None,
5418 if (default is None) and (obj_initial.default is not None):
5421 (bounds is None) and
5422 (value is not None) and
5423 (bounds_initial is not None) and
5424 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5428 (bounds is None) and
5429 (default is not None) and
5430 (bounds_initial is not None) and
5431 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5443 value_expected = default if value is None else value
5445 default_initial if value_expected is None
5448 value_expected = () if value_expected is None else value_expected
5449 self.assertEqual(obj, value_expected)
5450 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5451 self.assertEqual(obj.expl_tag, expl or expl_initial)
5454 default_initial if default is None else default,
5456 if obj.default is None:
5457 optional = optional_initial if optional is None else optional
5458 optional = False if optional is None else optional
5461 self.assertEqual(obj.optional, optional)
5463 (obj._bound_min, obj._bound_max),
5464 bounds or bounds_initial or (0, float("+inf")),
5467 @given(seqof_values_strategy())
5468 def test_copy(self, values):
5469 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5471 class SeqOf(self.base_klass):
5479 optional=optional or False,
5482 obj_copied = obj.copy()
5483 self.assert_copied_basic_fields(obj, obj_copied)
5484 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5485 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5486 self.assertEqual(obj._value, obj_copied._value)
5490 integers(min_value=1).map(tag_encode),
5492 def test_stripped(self, values, tag_impl):
5493 class SeqOf(self.base_klass):
5494 schema = OctetString()
5495 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5496 with self.assertRaises(NotEnoughData):
5497 obj.decode(obj.encode()[:-1])
5501 integers(min_value=1).map(tag_ctxc),
5503 def test_stripped_expl(self, values, tag_expl):
5504 class SeqOf(self.base_klass):
5505 schema = OctetString()
5506 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5507 with self.assertRaises(NotEnoughData):
5508 obj.decode(obj.encode()[:-1])
5511 integers(min_value=31),
5512 integers(min_value=0),
5515 def test_bad_tag(self, tag, offset, decode_path):
5516 with self.assertRaises(DecodeError) as err:
5517 self.base_klass().decode(
5518 tag_encode(tag)[:-1],
5520 decode_path=decode_path,
5523 self.assertEqual(err.exception.offset, offset)
5524 self.assertEqual(err.exception.decode_path, decode_path)
5527 integers(min_value=128),
5528 integers(min_value=0),
5531 def test_bad_len(self, l, offset, decode_path):
5532 with self.assertRaises(DecodeError) as err:
5533 self.base_klass().decode(
5534 self.base_klass.tag_default + len_encode(l)[:-1],
5536 decode_path=decode_path,
5539 self.assertEqual(err.exception.offset, offset)
5540 self.assertEqual(err.exception.decode_path, decode_path)
5542 @given(binary(min_size=1))
5543 def test_tag_mismatch(self, impl):
5544 assume(impl != self.base_klass.tag_default)
5545 with self.assertRaises(TagMismatch):
5546 self.base_klass(impl=impl).decode(self.base_klass().encode())
5548 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5550 seqof_values_strategy(schema=Integer()),
5551 lists(integers().map(Integer)),
5552 integers(min_value=1).map(tag_ctxc),
5553 integers(min_value=0),
5556 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5557 _, _, _, _, _, default, optional, _decoded = values
5559 class SeqOf(self.base_klass):
5569 pprint(obj, big_blobs=True, with_decode_path=True)
5570 self.assertFalse(obj.expled)
5571 obj_encoded = obj.encode()
5572 obj_expled = obj(value, expl=tag_expl)
5573 self.assertTrue(obj_expled.expled)
5575 list(obj_expled.pps())
5576 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5577 obj_expled_encoded = obj_expled.encode()
5578 obj_decoded, tail = obj_expled.decode(
5579 obj_expled_encoded + tail_junk,
5583 list(obj_decoded.pps())
5584 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5585 self.assertEqual(tail, tail_junk)
5586 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5587 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5588 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5589 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5591 obj_decoded.expl_llen,
5592 len(len_encode(len(obj_encoded))),
5594 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5595 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5598 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5600 self.assertEqual(obj_decoded.expl_offset, offset)
5601 for obj_inner in obj_decoded:
5602 self.assertIn(obj_inner, obj_decoded)
5603 self.assertSequenceEqual(
5606 obj_inner.offset - offset:
5607 obj_inner.offset + obj_inner.tlvlen - offset
5611 t, _, lv = tag_strip(obj_encoded)
5612 _, _, v = len_decode(lv)
5613 obj_encoded_lenindef = t + LENINDEF + v + EOC
5614 obj_decoded_lenindef, tail_lenindef = obj.decode(
5615 obj_encoded_lenindef + tail_junk,
5616 ctx={"bered": True},
5618 self.assertTrue(obj_decoded_lenindef.lenindef)
5619 self.assertTrue(obj_decoded_lenindef.bered)
5620 repr(obj_decoded_lenindef)
5621 list(obj_decoded_lenindef.pps())
5622 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
5623 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5624 with self.assertRaises(DecodeError):
5625 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5626 with self.assertRaises(DecodeError):
5627 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5629 @given(data_strategy())
5630 def test_bered(self, d):
5631 class SeqOf(self.base_klass):
5633 encoded = Boolean(False).encode()
5634 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
5635 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5636 with self.assertRaises(DecodeError):
5637 SeqOf().decode(encoded)
5638 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5639 self.assertFalse(decoded.ber_encoded)
5640 self.assertFalse(decoded.lenindef)
5641 self.assertTrue(decoded.bered)
5643 class SeqOf(self.base_klass):
5644 schema = OctetString()
5645 encoded = OctetString(b"whatever").encode()
5647 tag_encode(form=TagFormConstructed, num=4) +
5649 OctetString(b"whatever").encode() +
5652 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
5653 with self.assertRaises(DecodeError):
5654 SeqOf().decode(encoded)
5655 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
5656 self.assertFalse(decoded.ber_encoded)
5657 self.assertFalse(decoded.lenindef)
5658 self.assertTrue(decoded.bered)
5661 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5662 class SeqOf(SequenceOf):
5666 def _test_symmetric_compare_objs(self, obj1, obj2):
5667 self.assertEqual(obj1, obj2)
5668 self.assertSequenceEqual(list(obj1), list(obj2))
5671 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5676 def _test_symmetric_compare_objs(self, obj1, obj2):
5677 self.assertSetEqual(
5678 set(int(v) for v in obj1),
5679 set(int(v) for v in obj2),
5682 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5683 @given(data_strategy())
5684 def test_sorted(self, d):
5685 values = [OctetString(v) for v in d.draw(lists(binary()))]
5688 schema = OctetString()
5690 seq_encoded = seq.encode()
5691 seq_decoded, _ = seq.decode(seq_encoded)
5692 self.assertSequenceEqual(
5693 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5694 b"".join(sorted([v.encode() for v in values])),
5697 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5698 @given(data_strategy())
5699 def test_unsorted(self, d):
5700 values = [OctetString(v).encode() for v in d.draw(sets(
5701 binary(min_size=1, max_size=5),
5705 values = d.draw(permutations(values))
5706 assume(values != sorted(values))
5707 encoded = b"".join(values)
5708 seq_encoded = b"".join((
5710 len_encode(len(encoded)),
5715 schema = OctetString()
5717 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
5718 seq.decode(seq_encoded)
5720 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
5721 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
5722 self.assertTrue(seq_decoded.ber_encoded)
5723 self.assertTrue(seq_decoded.bered)
5724 self.assertSequenceEqual(
5725 [obj.encode() for obj in seq_decoded],
5730 class TestGoMarshalVectors(TestCase):
5732 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5733 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5734 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5735 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5736 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5738 class Seq(Sequence):
5740 ("erste", Integer()),
5741 ("zweite", Integer(optional=True))
5744 seq["erste"] = Integer(64)
5745 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5746 seq["erste"] = Integer(0x123456)
5747 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5748 seq["erste"] = Integer(64)
5749 seq["zweite"] = Integer(65)
5750 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5752 class NestedSeq(Sequence):
5756 seq["erste"] = Integer(127)
5757 seq["zweite"] = None
5758 nested = NestedSeq()
5759 nested["nest"] = seq
5760 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5762 self.assertSequenceEqual(
5763 OctetString(b"\x01\x02\x03").encode(),
5764 hexdec("0403010203"),
5767 class Seq(Sequence):
5769 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5772 seq["erste"] = Integer(64)
5773 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5775 class Seq(Sequence):
5777 ("erste", Integer(expl=tag_ctxc(5))),
5780 seq["erste"] = Integer(64)
5781 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5783 class Seq(Sequence):
5786 impl=tag_encode(0, klass=TagClassContext),
5791 seq["erste"] = Null()
5792 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5794 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5796 self.assertSequenceEqual(
5797 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5798 hexdec("170d3730303130313030303030305a"),
5800 self.assertSequenceEqual(
5801 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5802 hexdec("170d3039313131353232353631365a"),
5804 self.assertSequenceEqual(
5805 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5806 hexdec("180f32313030303430353132303130315a"),
5809 class Seq(Sequence):
5811 ("erste", GeneralizedTime()),
5814 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5815 self.assertSequenceEqual(
5817 hexdec("3011180f32303039313131353232353631365a"),
5820 self.assertSequenceEqual(
5821 BitString((1, b"\x80")).encode(),
5824 self.assertSequenceEqual(
5825 BitString((12, b"\x81\xF0")).encode(),
5826 hexdec("03030481f0"),
5829 self.assertSequenceEqual(
5830 ObjectIdentifier("1.2.3.4").encode(),
5831 hexdec("06032a0304"),
5833 self.assertSequenceEqual(
5834 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5835 hexdec("06092a864888932d010105"),
5837 self.assertSequenceEqual(
5838 ObjectIdentifier("2.100.3").encode(),
5839 hexdec("0603813403"),
5842 self.assertSequenceEqual(
5843 PrintableString("test").encode(),
5844 hexdec("130474657374"),
5846 self.assertSequenceEqual(
5847 PrintableString("x" * 127).encode(),
5848 hexdec("137F" + "78" * 127),
5850 self.assertSequenceEqual(
5851 PrintableString("x" * 128).encode(),
5852 hexdec("138180" + "78" * 128),
5854 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5856 class Seq(Sequence):
5858 ("erste", IA5String()),
5861 seq["erste"] = IA5String("test")
5862 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5864 class Seq(Sequence):
5866 ("erste", PrintableString()),
5869 seq["erste"] = PrintableString("test")
5870 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5871 # Asterisk is actually not allowable
5872 PrintableString.allowable_chars |= set(b"*")
5873 seq["erste"] = PrintableString("test*")
5874 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5875 PrintableString.allowable_chars -= set(b"*")
5877 class Seq(Sequence):
5879 ("erste", Any(optional=True)),
5880 ("zweite", Integer()),
5883 seq["zweite"] = Integer(64)
5884 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5889 seq.append(Integer(10))
5890 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5892 class _SeqOf(SequenceOf):
5893 schema = PrintableString()
5895 class SeqOf(SequenceOf):
5898 _seqof.append(PrintableString("1"))
5900 seqof.append(_seqof)
5901 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5903 class Seq(Sequence):
5905 ("erste", Integer(default=1)),
5908 seq["erste"] = Integer(0)
5909 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5910 seq["erste"] = Integer(1)
5911 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5912 seq["erste"] = Integer(2)
5913 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5916 class TestPP(TestCase):
5917 @given(data_strategy())
5918 def test_oid_printing(self, d):
5920 str(ObjectIdentifier(k)): v * 2
5921 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5923 chosen = d.draw(sampled_from(sorted(oids)))
5924 chosen_id = oids[chosen]
5925 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5926 self.assertNotIn(chosen_id, pp_console_row(pp))
5927 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5930 class TestAutoAddSlots(TestCase):
5932 class Inher(Integer):
5935 with self.assertRaises(AttributeError):
5937 inher.unexistent = "whatever"
5940 class TestOIDDefines(TestCase):
5941 @given(data_strategy())
5942 def runTest(self, d):
5943 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5944 value_name_chosen = d.draw(sampled_from(value_names))
5946 ObjectIdentifier(oid)
5947 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5949 oid_chosen = d.draw(sampled_from(oids))
5950 values = d.draw(lists(
5952 min_size=len(value_names),
5953 max_size=len(value_names),
5956 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5957 oid: Integer() for oid in oids[:-1]
5960 for i, value_name in enumerate(value_names):
5961 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5963 class Seq(Sequence):
5966 for value_name, value in zip(value_names, values):
5967 seq[value_name] = Any(Integer(value).encode())
5968 seq["type"] = oid_chosen
5969 seq, _ = Seq().decode(seq.encode())
5970 for value_name in value_names:
5971 if value_name == value_name_chosen:
5973 self.assertIsNone(seq[value_name].defined)
5974 if value_name_chosen in oids[:-1]:
5975 self.assertIsNotNone(seq[value_name_chosen].defined)
5976 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5977 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5980 pprint(seq, big_blobs=True, with_decode_path=True)
5983 class TestDefinesByPath(TestCase):
5984 def test_generated(self):
5985 class Seq(Sequence):
5987 ("type", ObjectIdentifier()),
5988 ("value", OctetString(expl=tag_ctxc(123))),
5991 class SeqInner(Sequence):
5993 ("typeInner", ObjectIdentifier()),
5994 ("valueInner", Any()),
5997 class PairValue(SetOf):
6000 class Pair(Sequence):
6002 ("type", ObjectIdentifier()),
6003 ("value", PairValue()),
6006 class Pairs(SequenceOf):
6013 type_octet_stringed,
6015 ObjectIdentifier(oid)
6016 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6018 seq_integered = Seq()
6019 seq_integered["type"] = type_integered
6020 seq_integered["value"] = OctetString(Integer(123).encode())
6021 seq_integered_raw = seq_integered.encode()
6025 (type_octet_stringed, OctetString(b"whatever")),
6026 (type_integered, Integer(123)),
6027 (type_octet_stringed, OctetString(b"whenever")),
6028 (type_integered, Integer(234)),
6030 for t, v in pairs_input:
6033 pair["value"] = PairValue((Any(v),))
6035 seq_inner = SeqInner()
6036 seq_inner["typeInner"] = type_innered
6037 seq_inner["valueInner"] = Any(pairs)
6038 seq_sequenced = Seq()
6039 seq_sequenced["type"] = type_sequenced
6040 seq_sequenced["value"] = OctetString(seq_inner.encode())
6041 seq_sequenced_raw = seq_sequenced.encode()
6043 list(seq_sequenced.pps())
6044 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6046 defines_by_path = []
6047 seq_integered, _ = Seq().decode(seq_integered_raw)
6048 self.assertIsNone(seq_integered["value"].defined)
6049 defines_by_path.append(
6050 (("type",), ((("value",), {
6051 type_integered: Integer(),
6052 type_sequenced: SeqInner(),
6055 seq_integered, _ = Seq().decode(
6057 ctx={"defines_by_path": defines_by_path},
6059 self.assertIsNotNone(seq_integered["value"].defined)
6060 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6061 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6062 self.assertTrue(seq_integered_raw[
6063 seq_integered["value"].defined[1].offset:
6064 ].startswith(Integer(123).encode()))
6066 list(seq_integered.pps())
6067 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6069 seq_sequenced, _ = Seq().decode(
6071 ctx={"defines_by_path": defines_by_path},
6073 self.assertIsNotNone(seq_sequenced["value"].defined)
6074 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6075 seq_inner = seq_sequenced["value"].defined[1]
6076 self.assertIsNone(seq_inner["valueInner"].defined)
6078 list(seq_sequenced.pps())
6079 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6081 defines_by_path.append((
6082 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6083 ((("valueInner",), {type_innered: Pairs()}),),
6085 seq_sequenced, _ = Seq().decode(
6087 ctx={"defines_by_path": defines_by_path},
6089 self.assertIsNotNone(seq_sequenced["value"].defined)
6090 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6091 seq_inner = seq_sequenced["value"].defined[1]
6092 self.assertIsNotNone(seq_inner["valueInner"].defined)
6093 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6094 pairs = seq_inner["valueInner"].defined[1]
6096 self.assertIsNone(pair["value"][0].defined)
6098 list(seq_sequenced.pps())
6099 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6101 defines_by_path.append((
6104 DecodePathDefBy(type_sequenced),
6106 DecodePathDefBy(type_innered),
6111 type_integered: Integer(),
6112 type_octet_stringed: OctetString(),
6115 seq_sequenced, _ = Seq().decode(
6117 ctx={"defines_by_path": defines_by_path},
6119 self.assertIsNotNone(seq_sequenced["value"].defined)
6120 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6121 seq_inner = seq_sequenced["value"].defined[1]
6122 self.assertIsNotNone(seq_inner["valueInner"].defined)
6123 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6124 pairs_got = seq_inner["valueInner"].defined[1]
6125 for pair_input, pair_got in zip(pairs_input, pairs_got):
6126 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
6127 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
6129 list(seq_sequenced.pps())
6130 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6132 @given(oid_strategy(), integers())
6133 def test_simple(self, oid, tgt):
6134 class Inner(Sequence):
6136 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
6137 ObjectIdentifier(oid): Integer(),
6141 class Outer(Sequence):
6144 ("tgt", OctetString()),
6148 inner["oid"] = ObjectIdentifier(oid)
6150 outer["inner"] = inner
6151 outer["tgt"] = OctetString(Integer(tgt).encode())
6152 decoded, _ = Outer().decode(outer.encode())
6153 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
6156 class TestAbsDecodePath(TestCase):
6158 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6159 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6161 def test_concat(self, decode_path, rel_path):
6162 self.assertSequenceEqual(
6163 abs_decode_path(decode_path, rel_path),
6164 decode_path + rel_path,
6168 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
6169 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6171 def test_abs(self, decode_path, rel_path):
6172 self.assertSequenceEqual(
6173 abs_decode_path(decode_path, ("/",) + rel_path),
6178 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
6179 integers(min_value=1, max_value=3),
6180 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
6182 def test_dots(self, decode_path, number_of_dots, rel_path):
6183 self.assertSequenceEqual(
6184 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
6185 decode_path[:-number_of_dots] + rel_path,
6189 class TestStrictDefaultExistence(TestCase):
6190 @given(data_strategy())
6191 def runTest(self, d):
6192 count = d.draw(integers(min_value=1, max_value=10))
6193 chosen = d.draw(integers(min_value=0, max_value=count - 1))
6195 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
6196 for i in range(count)
6198 for klass in (Sequence, Set):
6202 for i in range(count):
6203 seq["int%d" % i] = Integer(123)
6205 chosen_choice = "int%d" % chosen
6206 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
6207 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6209 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
6210 self.assertTrue(decoded.ber_encoded)
6211 self.assertTrue(decoded.bered)
6212 decoded, _ = seq.decode(raw, ctx={"bered": True})
6213 self.assertTrue(decoded.ber_encoded)
6214 self.assertTrue(decoded.bered)
6217 class TestX690PrefixedType(TestCase):
6219 self.assertSequenceEqual(
6220 VisibleString("Jones").encode(),
6221 hexdec("1A054A6F6E6573"),
6223 self.assertSequenceEqual(
6226 impl=tag_encode(3, klass=TagClassApplication),
6228 hexdec("43054A6F6E6573"),
6230 self.assertSequenceEqual(
6234 impl=tag_encode(3, klass=TagClassApplication),
6238 hexdec("A20743054A6F6E6573"),
6240 self.assertSequenceEqual(
6244 impl=tag_encode(3, klass=TagClassApplication),
6246 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
6248 hexdec("670743054A6F6E6573"),
6250 self.assertSequenceEqual(
6251 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
6252 hexdec("82054A6F6E6573"),
6256 class TestExplOOB(TestCase):
6258 expl = tag_ctxc(123)
6259 raw = Integer(123).encode() + Integer(234).encode()
6260 raw = b"".join((expl, len_encode(len(raw)), raw))
6261 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
6262 Integer(expl=expl).decode(raw)
6263 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})