2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2020 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, version 3 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this program. If not, see
16 # <http://www.gnu.org/licenses/>.
19 from copy import deepcopy
20 from datetime import datetime
21 from datetime import timedelta
22 from importlib import import_module
23 from os import environ
24 from random import random
25 from string import ascii_letters
26 from string import digits
27 from string import printable
28 from string import whitespace
29 from time import mktime
31 from unittest import TestCase
33 from hypothesis import assume
34 from hypothesis import given
35 from hypothesis import settings
36 from hypothesis.strategies import binary
37 from hypothesis.strategies import booleans
38 from hypothesis.strategies import composite
39 from hypothesis.strategies import data as data_strategy
40 from hypothesis.strategies import datetimes
41 from hypothesis.strategies import dictionaries
42 from hypothesis.strategies import integers
43 from hypothesis.strategies import just
44 from hypothesis.strategies import lists
45 from hypothesis.strategies import none
46 from hypothesis.strategies import one_of
47 from hypothesis.strategies import permutations
48 from hypothesis.strategies import sampled_from
49 from hypothesis.strategies import sets
50 from hypothesis.strategies import text
51 from hypothesis.strategies import tuples
52 from six import assertRaisesRegex
53 from six import binary_type
54 from six import byte2int
55 from six import indexbytes
56 from six import int2byte
57 from six import iterbytes
59 from six import text_type
60 from six import unichr as six_unichr
61 from six.moves.cPickle import dumps as pickle_dumps
62 from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto
63 from six.moves.cPickle import loads as pickle_loads
65 from pyderasn import _pp
66 from pyderasn import abs_decode_path
67 from pyderasn import Any
68 from pyderasn import BitString
69 from pyderasn import BMPString
70 from pyderasn import Boolean
71 from pyderasn import BoundsError
72 from pyderasn import Choice
73 from pyderasn import DecodeError
74 from pyderasn import DecodePathDefBy
75 from pyderasn import Enumerated
76 from pyderasn import EOC
77 from pyderasn import EOC_LEN
78 from pyderasn import ExceedingData
79 from pyderasn import GeneralizedTime
80 from pyderasn import GeneralString
81 from pyderasn import GraphicString
82 from pyderasn import hexdec
83 from pyderasn import hexenc
84 from pyderasn import IA5String
85 from pyderasn import Integer
86 from pyderasn import InvalidLength
87 from pyderasn import InvalidOID
88 from pyderasn import InvalidValueType
89 from pyderasn import len_decode
90 from pyderasn import len_encode
91 from pyderasn import LEN_YYMMDDHHMMSSZ
92 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
93 from pyderasn import LEN_YYYYMMDDHHMMSSZ
94 from pyderasn import LENINDEF
95 from pyderasn import LenIndefForm
96 from pyderasn import NotEnoughData
97 from pyderasn import Null
98 from pyderasn import NumericString
99 from pyderasn import ObjectIdentifier
100 from pyderasn import ObjNotReady
101 from pyderasn import ObjUnknown
102 from pyderasn import OctetString
103 from pyderasn import pp_console_row
104 from pyderasn import pprint
105 from pyderasn import PrintableString
106 from pyderasn import Sequence
107 from pyderasn import SequenceOf
108 from pyderasn import Set
109 from pyderasn import SetOf
110 from pyderasn import tag_ctxc
111 from pyderasn import tag_ctxp
112 from pyderasn import tag_decode
113 from pyderasn import tag_encode
114 from pyderasn import tag_strip
115 from pyderasn import TagClassApplication
116 from pyderasn import TagClassContext
117 from pyderasn import TagClassPrivate
118 from pyderasn import TagClassUniversal
119 from pyderasn import TagFormConstructed
120 from pyderasn import TagFormPrimitive
121 from pyderasn import TagMismatch
122 from pyderasn import TeletexString
123 from pyderasn import UniversalString
124 from pyderasn import UTCTime
125 from pyderasn import UTF8String
126 from pyderasn import VideotexString
127 from pyderasn import VisibleString
130 max_examples = environ.get("MAX_EXAMPLES")
131 settings.register_profile("local", settings(
133 **({"max_examples": int(max_examples)} if max_examples else {})
135 settings.load_profile("local")
136 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
138 tag_classes = sampled_from((
144 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
145 decode_path_strat = lists(integers(), max_size=3).map(
146 lambda decode_path: tuple(str(dp) for dp in decode_path)
148 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
151 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
153 self_module = import_module(__name__)
156 def register_class(klass):
157 klassname = klass.__name__ + str(time()).replace(".", "")
158 klass.__name__ = klassname
159 klass.__qualname__ = klassname
160 setattr(self_module, klassname, klass)
163 def assert_exceeding_data(self, call, junk):
166 with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)) as err:
171 class TestHex(TestCase):
173 def test_symmetric(self, data):
174 self.assertEqual(hexdec(hexenc(data)), data)
177 class TestTagCoder(TestCase):
178 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
182 integers(min_value=0, max_value=30),
185 def test_short(self, klass, form, num, junk):
186 raw = tag_encode(klass=klass, form=form, num=num)
187 self.assertEqual(tag_decode(raw), (klass, form, num))
188 self.assertEqual(len(raw), 1)
190 byte2int(tag_encode(klass=klass, form=form, num=0)),
191 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
193 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
194 self.assertSequenceEqual(stripped.tobytes(), raw)
195 self.assertEqual(tlen, len(raw))
196 self.assertSequenceEqual(tail, junk)
198 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
202 integers(min_value=31),
205 def test_long(self, klass, form, num, junk):
206 raw = tag_encode(klass=klass, form=form, num=num)
207 self.assertEqual(tag_decode(raw), (klass, form, num))
208 self.assertGreater(len(raw), 1)
210 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
213 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
214 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
215 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
216 self.assertSequenceEqual(stripped.tobytes(), raw)
217 self.assertEqual(tlen, len(raw))
218 self.assertSequenceEqual(tail, junk)
220 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
221 @given(integers(min_value=31))
222 def test_unfinished_tag(self, num):
223 raw = bytearray(tag_encode(num=num))
224 for i in range(1, len(raw)):
226 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
227 tag_strip(bytes(raw))
229 def test_go_vectors_valid(self):
230 for data, (eklass, etag, elen, eform) in (
231 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
232 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
233 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
234 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
235 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
236 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
237 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
238 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
239 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
240 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
242 tag, _, len_encoded = tag_strip(memoryview(data))
243 klass, form, num = tag_decode(tag)
244 _len, _, tail = len_decode(len_encoded)
245 self.assertSequenceEqual(tail, b"")
246 self.assertEqual(klass, eklass)
247 self.assertEqual(num, etag)
248 self.assertEqual(_len, elen)
249 self.assertEqual(form, eform)
251 def test_go_vectors_invalid(self):
259 with self.assertRaises(DecodeError):
260 _, _, len_encoded = tag_strip(memoryview(data))
261 len_decode(len_encoded)
264 integers(min_value=0, max_value=127),
265 integers(min_value=0, max_value=2),
267 def test_long_instead_of_short(self, l, dummy_num):
268 octets = (b"\x00" * dummy_num) + int2byte(l)
269 octets = int2byte((dummy_num + 1) | 0x80) + octets
270 with self.assertRaises(DecodeError):
274 class TestLenCoder(TestCase):
275 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
277 integers(min_value=0, max_value=127),
280 def test_short(self, l, junk):
281 raw = len_encode(l) + junk
282 decoded, llen, tail = len_decode(memoryview(raw))
283 self.assertEqual(decoded, l)
284 self.assertEqual(llen, 1)
285 self.assertEqual(len(raw), 1 + len(junk))
286 self.assertEqual(tail.tobytes(), junk)
288 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
290 integers(min_value=128),
293 def test_long(self, l, junk):
294 raw = len_encode(l) + junk
295 decoded, llen, tail = len_decode(memoryview(raw))
296 self.assertEqual(decoded, l)
297 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
298 self.assertEqual(llen, len(raw) - len(junk))
299 self.assertNotEqual(indexbytes(raw, 1), 0)
300 self.assertSequenceEqual(tail.tobytes(), junk)
302 def test_empty(self):
303 with self.assertRaises(NotEnoughData):
306 @given(integers(min_value=128))
307 def test_stripped(self, _len):
308 with self.assertRaises(NotEnoughData):
309 len_decode(len_encode(_len)[:-1])
312 text_printable = text(alphabet=printable, min_size=1)
316 def text_letters(draw):
317 result = draw(text(alphabet=ascii_letters, min_size=1))
319 result = result.encode("ascii")
323 class CommonMixin(object):
324 def test_tag_default(self):
325 obj = self.base_klass()
326 self.assertEqual(obj.tag, obj.tag_default)
328 def test_simultaneous_impl_expl(self):
329 with self.assertRaises(ValueError):
330 self.base_klass(impl=b"whatever", expl=b"whenever")
332 @given(binary(min_size=1), integers(), integers(), integers())
333 def test_decoded(self, impl, offset, llen, vlen):
334 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
335 self.assertEqual(obj.offset, offset)
336 self.assertEqual(obj.llen, llen)
337 self.assertEqual(obj.vlen, vlen)
338 self.assertEqual(obj.tlen, len(impl))
339 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
341 @given(binary(min_size=1))
342 def test_impl_inherited(self, impl_tag):
343 class Inherited(self.base_klass):
346 self.assertSequenceEqual(obj.impl, impl_tag)
347 self.assertFalse(obj.expled)
349 tag_class, _, tag_num = tag_decode(impl_tag)
350 self.assertEqual(obj.tag_order, (tag_class, tag_num))
352 @given(binary(min_size=1))
353 def test_expl_inherited(self, expl_tag):
354 class Inherited(self.base_klass):
357 self.assertSequenceEqual(obj.expl, expl_tag)
358 self.assertTrue(obj.expled)
360 tag_class, _, tag_num = tag_decode(expl_tag)
361 self.assertEqual(obj.tag_order, (tag_class, tag_num))
363 def assert_copied_basic_fields(self, obj, obj_copied):
364 self.assertEqual(obj, obj_copied)
365 self.assertSequenceEqual(obj.tag, obj_copied.tag)
366 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
367 self.assertEqual(obj.default, obj_copied.default)
368 self.assertEqual(obj.optional, obj_copied.optional)
369 self.assertEqual(obj.offset, obj_copied.offset)
370 self.assertEqual(obj.llen, obj_copied.llen)
371 self.assertEqual(obj.vlen, obj_copied.vlen)
373 self.assertEqual(obj.tag_order, obj_copied.tag_order)
377 def boolean_values_strategy(draw, do_expl=False):
378 value = draw(one_of(none(), booleans()))
382 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
384 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
385 default = draw(one_of(none(), booleans()))
386 optional = draw(one_of(none(), booleans()))
388 draw(integers(min_value=0)),
389 draw(integers(min_value=0)),
390 draw(integers(min_value=0)),
392 return (value, impl, expl, default, optional, _decoded)
395 class BooleanInherited(Boolean):
399 class TestBoolean(CommonMixin, TestCase):
402 def test_invalid_value_type(self):
403 with self.assertRaises(InvalidValueType) as err:
408 def test_optional(self, optional):
409 obj = Boolean(default=Boolean(False), optional=optional)
410 self.assertTrue(obj.optional)
413 def test_ready(self, value):
415 self.assertFalse(obj.ready)
418 pprint(obj, big_blobs=True, with_decode_path=True)
419 with self.assertRaises(ObjNotReady) as err:
423 self.assertTrue(obj.ready)
426 pprint(obj, big_blobs=True, with_decode_path=True)
428 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
429 def test_comparison(self, value1, value2, tag1, tag2):
430 for klass in (Boolean, BooleanInherited):
433 self.assertEqual(obj1 == obj2, value1 == value2)
434 self.assertEqual(obj1 != obj2, value1 != value2)
435 self.assertEqual(obj1 == bool(obj2), value1 == value2)
436 obj1 = klass(value1, impl=tag1)
437 obj2 = klass(value1, impl=tag2)
438 self.assertEqual(obj1 == obj2, tag1 == tag2)
439 self.assertEqual(obj1 != obj2, tag1 != tag2)
441 @given(data_strategy())
442 def test_call(self, d):
443 for klass in (Boolean, BooleanInherited):
451 ) = d.draw(boolean_values_strategy())
457 optional_initial or False,
467 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
468 obj = obj_initial(value, impl, expl, default, optional)
470 value_expected = default if value is None else value
472 default_initial if value_expected is None
475 self.assertEqual(obj, value_expected)
476 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
477 self.assertEqual(obj.expl_tag, expl or expl_initial)
480 default_initial if default is None else default,
482 if obj.default is None:
483 optional = optional_initial if optional is None else optional
484 optional = False if optional is None else optional
487 self.assertEqual(obj.optional, optional)
489 @given(boolean_values_strategy())
490 def test_copy(self, values):
491 for klass in (Boolean, BooleanInherited):
493 for copy_func in copy_funcs:
494 obj_copied = copy_func(obj)
495 self.assert_copied_basic_fields(obj, obj_copied)
499 integers(min_value=1).map(tag_encode),
501 def test_stripped(self, value, tag_impl):
502 obj = Boolean(value, impl=tag_impl)
503 with self.assertRaises(NotEnoughData):
504 obj.decode(obj.encode()[:-1])
508 integers(min_value=1).map(tag_ctxc),
510 def test_stripped_expl(self, value, tag_expl):
511 obj = Boolean(value, expl=tag_expl)
512 with self.assertRaises(NotEnoughData):
513 obj.decode(obj.encode()[:-1])
516 integers(min_value=31),
517 integers(min_value=0),
520 def test_bad_tag(self, tag, offset, decode_path):
521 with self.assertRaises(DecodeError) as err:
523 tag_encode(tag)[:-1],
525 decode_path=decode_path,
528 self.assertEqual(err.exception.offset, offset)
529 self.assertEqual(err.exception.decode_path, decode_path)
532 integers(min_value=31),
533 integers(min_value=0),
536 def test_bad_expl_tag(self, tag, offset, decode_path):
537 with self.assertRaises(DecodeError) as err:
538 Boolean(expl=Boolean.tag_default).decode(
539 tag_encode(tag)[:-1],
541 decode_path=decode_path,
544 self.assertEqual(err.exception.offset, offset)
545 self.assertEqual(err.exception.decode_path, decode_path)
548 integers(min_value=128),
549 integers(min_value=0),
552 def test_bad_len(self, l, offset, decode_path):
553 with self.assertRaises(DecodeError) as err:
555 Boolean.tag_default + len_encode(l)[:-1],
557 decode_path=decode_path,
560 self.assertEqual(err.exception.offset, offset)
561 self.assertEqual(err.exception.decode_path, decode_path)
564 integers(min_value=128),
565 integers(min_value=0),
568 def test_bad_expl_len(self, l, offset, decode_path):
569 with self.assertRaises(DecodeError) as err:
570 Boolean(expl=Boolean.tag_default).decode(
571 Boolean.tag_default + len_encode(l)[:-1],
573 decode_path=decode_path,
576 self.assertEqual(err.exception.offset, offset)
577 self.assertEqual(err.exception.decode_path, decode_path)
579 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
581 boolean_values_strategy(),
583 integers(min_value=1).map(tag_ctxc),
584 integers(min_value=0),
588 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
589 for klass in (Boolean, BooleanInherited):
590 _, _, _, default, optional, _decoded = values
599 pprint(obj, big_blobs=True, with_decode_path=True)
600 self.assertFalse(obj.expled)
601 obj_encoded = obj.encode()
602 obj_expled = obj(value, expl=tag_expl)
603 self.assertTrue(obj_expled.expled)
605 list(obj_expled.pps())
606 pprint(obj_expled, big_blobs=True, with_decode_path=True)
607 obj_expled_hex_encoded = obj_expled.hexencode()
608 ctx_copied = deepcopy(ctx_dummy)
609 obj_decoded, tail = obj_expled.hexdecode(
610 obj_expled_hex_encoded + hexenc(tail_junk),
614 self.assertDictEqual(ctx_copied, ctx_dummy)
616 list(obj_decoded.pps())
617 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
618 self.assertEqual(tail, tail_junk)
619 self.assertEqual(obj_decoded, obj_expled)
620 self.assertNotEqual(obj_decoded, obj)
621 self.assertEqual(bool(obj_decoded), bool(obj_expled))
622 self.assertEqual(bool(obj_decoded), bool(obj))
623 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
624 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
625 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
627 obj_decoded.expl_llen,
628 len(len_encode(len(obj_encoded))),
630 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
631 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
634 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
636 self.assertEqual(obj_decoded.expl_offset, offset)
637 assert_exceeding_data(
639 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
643 evgens = list(obj_expled.decode_evgen(
644 hexdec(obj_expled_hex_encoded) + tail_junk,
646 decode_path=decode_path,
649 self.assertEqual(len(evgens), 1)
650 _decode_path, obj, tail = evgens[0]
651 self.assertSequenceEqual(tail, tail_junk)
652 self.assertEqual(_decode_path, decode_path)
653 self.assertEqual(obj, obj_decoded)
654 self.assertEqual(obj.expl_offset, offset)
658 @given(integers(min_value=2))
659 def test_invalid_len(self, l):
660 with self.assertRaises(InvalidLength):
661 Boolean().decode(b"".join((
667 @given(integers(min_value=0 + 1, max_value=255 - 1))
668 def test_ber_value(self, value):
669 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
670 Boolean().decode(b"".join((
680 obj, _ = Boolean().decode(encoded, ctx={"bered": True})
681 list(Boolean().decode_evgen(encoded, ctx={"bered": True}))
682 self.assertTrue(bool(obj))
683 self.assertTrue(obj.ber_encoded)
684 self.assertFalse(obj.lenindef)
685 self.assertTrue(obj.bered)
687 self.assertTrue(obj.ber_encoded)
688 self.assertFalse(obj.lenindef)
689 self.assertTrue(obj.bered)
692 integers(min_value=1).map(tag_ctxc),
693 binary().filter(lambda x: not x.startswith(EOC)),
695 def test_ber_expl_no_eoc(self, expl, junk):
696 encoded = expl + LENINDEF + Boolean(False).encode()
697 with self.assertRaises(LenIndefForm):
698 Boolean(expl=expl).decode(encoded + junk)
699 with assertRaisesRegex(self, DecodeError, "no EOC"):
700 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
701 obj, tail = Boolean(expl=expl).decode(
702 encoded + EOC + junk,
705 self.assertTrue(obj.expl_lenindef)
706 self.assertFalse(obj.lenindef)
707 self.assertFalse(obj.ber_encoded)
708 self.assertTrue(obj.bered)
710 self.assertTrue(obj.expl_lenindef)
711 self.assertFalse(obj.lenindef)
712 self.assertFalse(obj.ber_encoded)
713 self.assertTrue(obj.bered)
714 self.assertSequenceEqual(tail, junk)
717 pprint(obj, big_blobs=True, with_decode_path=True)
720 integers(min_value=1).map(tag_ctxc),
727 def test_ber_expl(self, expl, values):
733 Boolean(value).encode() +
736 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
738 class SeqOf(SequenceOf):
739 schema = Boolean(expl=expl)
740 with self.assertRaises(LenIndefForm):
741 SeqOf().decode(encoded)
742 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
743 list(SeqOf().decode_evgen(encoded, ctx={"bered": True}))
744 self.assertSequenceEqual(tail, b"")
745 self.assertSequenceEqual([bool(v) for v in seqof], values)
761 len(expl) + 1 + 3 + EOC_LEN,
772 pprint(seqof, big_blobs=True, with_decode_path=True)
776 def integer_values_strategy(draw, do_expl=False):
777 bound_min, value, default, bound_max = sorted(draw(sets(
786 _specs = draw(sets(text_letters()))
789 min_size=len(_specs),
790 max_size=len(_specs),
792 _specs = list(zip(_specs, values))
795 bounds = (bound_min, bound_max)
799 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
801 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
804 optional = draw(one_of(none(), booleans()))
806 draw(integers(min_value=0)),
807 draw(integers(min_value=0)),
808 draw(integers(min_value=0)),
810 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
813 class IntegerInherited(Integer):
817 class TestInteger(CommonMixin, TestCase):
820 def test_invalid_value_type(self):
821 with self.assertRaises(InvalidValueType) as err:
825 @given(sets(text_letters(), min_size=2))
826 def test_unknown_name(self, names_input):
827 missing = names_input.pop()
830 schema = [(n, 123) for n in names_input]
831 with self.assertRaises(ObjUnknown) as err:
835 @given(sets(text_letters(), min_size=2))
836 def test_known_name(self, names_input):
838 schema = [(n, 123) for n in names_input]
839 Int(names_input.pop())
842 def test_optional(self, optional):
843 obj = Integer(default=Integer(0), optional=optional)
844 self.assertTrue(obj.optional)
847 def test_ready(self, value):
849 self.assertFalse(obj.ready)
852 pprint(obj, big_blobs=True, with_decode_path=True)
853 with self.assertRaises(ObjNotReady) as err:
857 self.assertTrue(obj.ready)
860 pprint(obj, big_blobs=True, with_decode_path=True)
863 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
864 def test_comparison(self, value1, value2, tag1, tag2):
865 for klass in (Integer, IntegerInherited):
868 self.assertEqual(obj1 == obj2, value1 == value2)
869 self.assertEqual(obj1 != obj2, value1 != value2)
870 self.assertEqual(obj1 == int(obj2), value1 == value2)
871 obj1 = klass(value1, impl=tag1)
872 obj2 = klass(value1, impl=tag2)
873 self.assertEqual(obj1 == obj2, tag1 == tag2)
874 self.assertEqual(obj1 != obj2, tag1 != tag2)
876 @given(lists(integers()))
877 def test_sorted_works(self, values):
878 self.assertSequenceEqual(
879 [int(v) for v in sorted(Integer(v) for v in values)],
883 @given(data_strategy())
884 def test_named(self, d):
885 names_input = list(d.draw(sets(text_letters(), min_size=1)))
886 values_input = list(d.draw(sets(
888 min_size=len(names_input),
889 max_size=len(names_input),
891 chosen_name = d.draw(sampled_from(names_input))
892 names_input = dict(zip(names_input, values_input))
896 _int = Int(chosen_name)
897 self.assertEqual(_int.named, chosen_name)
898 self.assertEqual(int(_int), names_input[chosen_name])
900 @given(integers(), integers(min_value=0), integers(min_value=0))
901 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
902 value = bound_min + value_delta
903 bound_max = value + bound_delta
904 Integer(value=value, bounds=(bound_min, bound_max))
906 @given(sets(integers(), min_size=3, max_size=3))
907 def test_bounds_unsatisfied(self, values):
908 values = sorted(values)
909 with self.assertRaises(BoundsError) as err:
910 Integer(value=values[0], bounds=(values[1], values[2]))
912 with assertRaisesRegex(self, DecodeError, "bounds") as err:
913 Integer(bounds=(values[1], values[2])).decode(
914 Integer(values[0]).encode()
917 with self.assertRaises(BoundsError) as err:
918 Integer(value=values[2], bounds=(values[0], values[1]))
920 with assertRaisesRegex(self, DecodeError, "bounds") as err:
921 Integer(bounds=(values[0], values[1])).decode(
922 Integer(values[2]).encode()
926 @given(data_strategy())
927 def test_call(self, d):
928 for klass in (Integer, IntegerInherited):
938 ) = d.draw(integer_values_strategy())
945 optional_initial or False,
958 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
959 if (default is None) and (obj_initial.default is not None):
963 (value is not None) and
964 (bounds_initial is not None) and
965 not (bounds_initial[0] <= value <= bounds_initial[1])
970 (default is not None) and
971 (bounds_initial is not None) and
972 not (bounds_initial[0] <= default <= bounds_initial[1])
975 obj = obj_initial(value, bounds, impl, expl, default, optional)
977 value_expected = default if value is None else value
979 default_initial if value_expected is None
982 self.assertEqual(obj, value_expected)
983 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
984 self.assertEqual(obj.expl_tag, expl or expl_initial)
987 default_initial if default is None else default,
989 if obj.default is None:
990 optional = optional_initial if optional is None else optional
991 optional = False if optional is None else optional
994 self.assertEqual(obj.optional, optional)
996 (obj._bound_min, obj._bound_max),
997 bounds or bounds_initial or (float("-inf"), float("+inf")),
1001 {} if _specs_initial is None else dict(_specs_initial),
1004 @given(integer_values_strategy())
1005 def test_copy(self, values):
1006 for klass in (Integer, IntegerInherited):
1007 obj = klass(*values)
1008 for copy_func in copy_funcs:
1009 obj_copied = copy_func(obj)
1010 self.assert_copied_basic_fields(obj, obj_copied)
1011 self.assertEqual(obj.specs, obj_copied.specs)
1012 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1013 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1014 self.assertEqual(obj._value, obj_copied._value)
1018 integers(min_value=1).map(tag_encode),
1020 def test_stripped(self, value, tag_impl):
1021 obj = Integer(value, impl=tag_impl)
1022 with self.assertRaises(NotEnoughData):
1023 obj.decode(obj.encode()[:-1])
1027 integers(min_value=1).map(tag_ctxc),
1029 def test_stripped_expl(self, value, tag_expl):
1030 obj = Integer(value, expl=tag_expl)
1031 with self.assertRaises(NotEnoughData):
1032 obj.decode(obj.encode()[:-1])
1034 def test_zero_len(self):
1035 with self.assertRaises(NotEnoughData):
1036 Integer().decode(b"".join((
1037 Integer.tag_default,
1042 integers(min_value=31),
1043 integers(min_value=0),
1046 def test_bad_tag(self, tag, offset, decode_path):
1047 with self.assertRaises(DecodeError) as err:
1049 tag_encode(tag)[:-1],
1051 decode_path=decode_path,
1054 self.assertEqual(err.exception.offset, offset)
1055 self.assertEqual(err.exception.decode_path, decode_path)
1058 integers(min_value=128),
1059 integers(min_value=0),
1062 def test_bad_len(self, l, offset, decode_path):
1063 with self.assertRaises(DecodeError) as err:
1065 Integer.tag_default + len_encode(l)[:-1],
1067 decode_path=decode_path,
1070 self.assertEqual(err.exception.offset, offset)
1071 self.assertEqual(err.exception.decode_path, decode_path)
1074 sets(integers(), min_size=2, max_size=2),
1075 integers(min_value=0),
1078 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1079 value, bound_min = list(sorted(ints))
1082 bounds = (bound_min, bound_min)
1083 with self.assertRaises(DecodeError) as err:
1085 Integer(value).encode(),
1087 decode_path=decode_path,
1090 self.assertEqual(err.exception.offset, offset)
1091 self.assertEqual(err.exception.decode_path, decode_path)
1093 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1095 integer_values_strategy(),
1097 integers(min_value=1).map(tag_ctxc),
1098 integers(min_value=0),
1102 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
1103 for klass in (Integer, IntegerInherited):
1104 _, _, _, _, default, optional, _, _decoded = values
1113 pprint(obj, big_blobs=True, with_decode_path=True)
1114 self.assertFalse(obj.expled)
1115 obj_encoded = obj.encode()
1116 obj_expled = obj(value, expl=tag_expl)
1117 self.assertTrue(obj_expled.expled)
1119 list(obj_expled.pps())
1120 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1121 obj_expled_encoded = obj_expled.encode()
1122 ctx_copied = deepcopy(ctx_dummy)
1123 obj_decoded, tail = obj_expled.decode(
1124 obj_expled_encoded + tail_junk,
1128 self.assertDictEqual(ctx_copied, ctx_dummy)
1130 list(obj_decoded.pps())
1131 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1132 self.assertEqual(tail, tail_junk)
1133 self.assertEqual(obj_decoded, obj_expled)
1134 self.assertNotEqual(obj_decoded, obj)
1135 self.assertEqual(int(obj_decoded), int(obj_expled))
1136 self.assertEqual(int(obj_decoded), int(obj))
1137 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1138 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1139 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1141 obj_decoded.expl_llen,
1142 len(len_encode(len(obj_encoded))),
1144 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1145 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1148 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1150 self.assertEqual(obj_decoded.expl_offset, offset)
1151 assert_exceeding_data(
1153 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1157 evgens = list(obj_expled.decode_evgen(
1158 obj_expled_encoded + tail_junk,
1160 decode_path=decode_path,
1163 self.assertEqual(len(evgens), 1)
1164 _decode_path, obj, tail = evgens[0]
1165 self.assertSequenceEqual(tail, tail_junk)
1166 self.assertEqual(_decode_path, decode_path)
1167 self.assertEqual(obj, obj_decoded)
1168 self.assertEqual(obj.expl_offset, offset)
1172 def test_go_vectors_valid(self):
1173 for data, expect in ((
1177 (b"\xff\x7f", -129),
1181 (b"\xff\x00", -256),
1185 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1186 (b"\x80\x00\x00\x00", -2147483648),
1189 Integer().decode(b"".join((
1190 Integer.tag_default,
1191 len_encode(len(data)),
1197 def test_go_vectors_invalid(self):
1202 with self.assertRaises(DecodeError):
1203 Integer().decode(b"".join((
1204 Integer.tag_default,
1205 len_encode(len(data)),
1211 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1214 if draw(booleans()):
1215 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1217 integers(min_value=0, max_value=255),
1218 min_size=len(schema),
1219 max_size=len(schema),
1221 schema = list(zip(schema, bits))
1223 def _value(value_required):
1224 if not value_required and draw(booleans()):
1226 generation_choice = 0
1228 generation_choice = draw(sampled_from((1, 2, 3)))
1229 if generation_choice == 1 or draw(booleans()):
1230 return "'%s'B" % "".join(draw(lists(
1231 sampled_from(("0", "1")),
1232 max_size=len(schema),
1234 if generation_choice == 2 or draw(booleans()):
1235 return draw(binary(max_size=len(schema) // 8))
1236 if generation_choice == 3 or draw(booleans()):
1237 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1239 value = _value(value_required)
1240 default = _value(value_required=False)
1244 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1246 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1247 optional = draw(one_of(none(), booleans()))
1249 draw(integers(min_value=0)),
1250 draw(integers(min_value=0)),
1251 draw(integers(min_value=0)),
1253 return (schema, value, impl, expl, default, optional, _decoded)
1256 class BitStringInherited(BitString):
1260 class TestBitString(CommonMixin, TestCase):
1261 base_klass = BitString
1263 @given(lists(booleans()))
1264 def test_b_encoding(self, bits):
1265 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1266 self.assertEqual(obj.bit_len, len(bits))
1267 self.assertSequenceEqual(list(obj), bits)
1268 for i, bit in enumerate(bits):
1269 self.assertEqual(obj[i], bit)
1271 @given(lists(booleans()))
1272 def test_out_of_bounds_bits(self, bits):
1273 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1274 for i in range(len(bits), len(bits) * 2):
1275 self.assertFalse(obj[i])
1277 def test_bad_b_encoding(self):
1278 with self.assertRaises(ValueError):
1279 BitString("'010120101'B")
1282 integers(min_value=1, max_value=255),
1283 integers(min_value=1, max_value=255),
1285 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1286 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1287 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1288 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1290 class BS(BitString):
1291 schema = (("whatever", 0),)
1292 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1293 self.assertEqual(obj.bit_len, leading_zeros + 1)
1294 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1296 def test_zero_len(self):
1297 with self.assertRaises(NotEnoughData):
1298 BitString().decode(b"".join((
1299 BitString.tag_default,
1303 def test_invalid_value_type(self):
1304 with self.assertRaises(InvalidValueType) as err:
1307 with self.assertRaises(InvalidValueType) as err:
1311 def test_obj_unknown(self):
1312 with self.assertRaises(ObjUnknown) as err:
1313 BitString(b"whatever")["whenever"]
1316 def test_get_invalid_type(self):
1317 with self.assertRaises(InvalidValueType) as err:
1318 BitString(b"whatever")[(1, 2, 3)]
1321 @given(data_strategy())
1322 def test_unknown_name(self, d):
1323 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1324 missing = _schema.pop()
1326 class BS(BitString):
1327 schema = [(n, i) for i, n in enumerate(_schema)]
1328 with self.assertRaises(ObjUnknown) as err:
1333 def test_optional(self, optional):
1334 obj = BitString(default=BitString(b""), optional=optional)
1335 self.assertTrue(obj.optional)
1338 def test_ready(self, value):
1340 self.assertFalse(obj.ready)
1343 pprint(obj, big_blobs=True, with_decode_path=True)
1344 with self.assertRaises(ObjNotReady) as err:
1347 obj = BitString(value)
1348 self.assertTrue(obj.ready)
1351 pprint(obj, big_blobs=True, with_decode_path=True)
1354 tuples(integers(min_value=0), binary()),
1355 tuples(integers(min_value=0), binary()),
1359 def test_comparison(self, value1, value2, tag1, tag2):
1360 for klass in (BitString, BitStringInherited):
1361 obj1 = klass(value1)
1362 obj2 = klass(value2)
1363 self.assertEqual(obj1 == obj2, value1 == value2)
1364 self.assertEqual(obj1 != obj2, value1 != value2)
1365 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1366 obj1 = klass(value1, impl=tag1)
1367 obj2 = klass(value1, impl=tag2)
1368 self.assertEqual(obj1 == obj2, tag1 == tag2)
1369 self.assertEqual(obj1 != obj2, tag1 != tag2)
1371 @given(data_strategy())
1372 def test_call(self, d):
1373 for klass in (BitString, BitStringInherited):
1382 ) = d.draw(bit_string_values_strategy())
1385 schema = schema_initial
1387 value=value_initial,
1390 default=default_initial,
1391 optional=optional_initial or False,
1392 _decoded=_decoded_initial,
1402 ) = d.draw(bit_string_values_strategy(
1403 schema=schema_initial,
1404 do_expl=impl_initial is None,
1413 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1414 self.assertEqual(obj.expl_tag, expl or expl_initial)
1415 if obj.default is None:
1416 optional = optional_initial if optional is None else optional
1417 optional = False if optional is None else optional
1420 self.assertEqual(obj.optional, optional)
1421 self.assertEqual(obj.specs, obj_initial.specs)
1423 @given(bit_string_values_strategy())
1424 def test_copy(self, values):
1425 for klass in (BitString, BitStringInherited):
1426 _schema, value, impl, expl, default, optional, _decoded = values
1436 optional=optional or False,
1439 for copy_func in copy_funcs:
1440 obj_copied = copy_func(obj)
1441 self.assert_copied_basic_fields(obj, obj_copied)
1442 self.assertEqual(obj.specs, obj_copied.specs)
1443 self.assertEqual(obj._value, obj_copied._value)
1447 integers(min_value=1).map(tag_encode),
1449 def test_stripped(self, value, tag_impl):
1450 obj = BitString(value, impl=tag_impl)
1451 with self.assertRaises(NotEnoughData):
1452 obj.decode(obj.encode()[:-1])
1456 integers(min_value=1).map(tag_ctxc),
1458 def test_stripped_expl(self, value, tag_expl):
1459 obj = BitString(value, expl=tag_expl)
1460 with self.assertRaises(NotEnoughData):
1461 obj.decode(obj.encode()[:-1])
1464 integers(min_value=31),
1465 integers(min_value=0),
1468 def test_bad_tag(self, tag, offset, decode_path):
1469 with self.assertRaises(DecodeError) as err:
1471 tag_encode(tag)[:-1],
1473 decode_path=decode_path,
1476 self.assertEqual(err.exception.offset, offset)
1477 self.assertEqual(err.exception.decode_path, decode_path)
1480 integers(min_value=128),
1481 integers(min_value=0),
1484 def test_bad_len(self, l, offset, decode_path):
1485 with self.assertRaises(DecodeError) as err:
1487 BitString.tag_default + len_encode(l)[:-1],
1489 decode_path=decode_path,
1492 self.assertEqual(err.exception.offset, offset)
1493 self.assertEqual(err.exception.decode_path, decode_path)
1495 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1496 @given(data_strategy())
1497 def test_symmetric(self, d):
1506 ) = d.draw(bit_string_values_strategy(value_required=True))
1507 tail_junk = d.draw(binary(max_size=5))
1508 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1509 offset = d.draw(integers(min_value=0))
1510 decode_path = d.draw(decode_path_strat)
1511 for klass in (BitString, BitStringInherited):
1522 pprint(obj, big_blobs=True, with_decode_path=True)
1523 self.assertFalse(obj.expled)
1524 obj_encoded = obj.encode()
1525 obj_expled = obj(value, expl=tag_expl)
1526 self.assertTrue(obj_expled.expled)
1528 list(obj_expled.pps())
1529 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1530 obj_expled_encoded = obj_expled.encode()
1531 ctx_copied = deepcopy(ctx_dummy)
1532 obj_decoded, tail = obj_expled.decode(
1533 obj_expled_encoded + tail_junk,
1537 self.assertDictEqual(ctx_copied, ctx_dummy)
1539 list(obj_decoded.pps())
1540 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1541 self.assertEqual(tail, tail_junk)
1542 self.assertEqual(obj_decoded, obj_expled)
1543 self.assertNotEqual(obj_decoded, obj)
1544 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1545 self.assertEqual(bytes(obj_decoded), bytes(obj))
1546 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1547 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1548 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1550 obj_decoded.expl_llen,
1551 len(len_encode(len(obj_encoded))),
1553 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1554 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1557 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1559 self.assertEqual(obj_decoded.expl_offset, offset)
1560 if isinstance(value, tuple):
1561 self.assertSetEqual(set(value), set(obj_decoded.named))
1564 assert_exceeding_data(
1566 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1570 evgens = list(obj_expled.decode_evgen(
1571 obj_expled_encoded + tail_junk,
1573 decode_path=decode_path,
1576 self.assertEqual(len(evgens), 1)
1577 _decode_path, obj, tail = evgens[0]
1578 self.assertSequenceEqual(tail, tail_junk)
1579 self.assertEqual(_decode_path, decode_path)
1580 self.assertEqual(obj.expl_offset, offset)
1584 @given(integers(min_value=1, max_value=255))
1585 def test_bad_zero_value(self, pad_size):
1586 with self.assertRaises(DecodeError):
1587 BitString().decode(b"".join((
1588 BitString.tag_default,
1593 def test_go_vectors_invalid(self):
1599 with self.assertRaises(DecodeError):
1600 BitString().decode(b"".join((
1601 BitString.tag_default,
1606 def test_go_vectors_valid(self):
1607 obj, _ = BitString().decode(b"".join((
1608 BitString.tag_default,
1612 self.assertEqual(bytes(obj), b"")
1613 self.assertEqual(obj.bit_len, 0)
1615 obj, _ = BitString().decode(b"".join((
1616 BitString.tag_default,
1620 self.assertEqual(bytes(obj), b"\x00")
1621 self.assertEqual(obj.bit_len, 1)
1623 obj = BitString((16, b"\x82\x40"))
1624 self.assertTrue(obj[0])
1625 self.assertFalse(obj[1])
1626 self.assertTrue(obj[6])
1627 self.assertTrue(obj[9])
1628 self.assertFalse(obj[17])
1630 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1632 integers(min_value=1, max_value=30),
1635 binary(min_size=1, max_size=5),
1637 binary(min_size=1, max_size=5),
1645 lists(booleans(), min_size=1),
1649 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk, decode_path):
1650 def chunk_constructed(contents):
1652 tag_encode(form=TagFormConstructed, num=3) +
1654 b"".join(BitString(content).encode() for content in contents) +
1658 chunks_len_expected = []
1659 payload_expected = b""
1660 bit_len_expected = 0
1661 for chunk_input in chunk_inputs:
1662 if isinstance(chunk_input, binary_type):
1663 chunks.append(BitString(chunk_input).encode())
1664 payload_expected += chunk_input
1665 bit_len_expected += len(chunk_input) * 8
1666 chunks_len_expected.append(len(chunk_input) + 1)
1668 chunks.append(chunk_constructed(chunk_input))
1669 payload = b"".join(chunk_input)
1670 payload_expected += payload
1671 bit_len_expected += len(payload) * 8
1672 for c in chunk_input:
1673 chunks_len_expected.append(len(c) + 1)
1674 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
1675 chunk_last = BitString("'%s'B" % "".join(
1676 "1" if bit else "0" for bit in chunk_last_bits
1678 chunks_len_expected.append(BitString().decod(chunk_last.encode()).vlen)
1679 payload_expected += bytes(chunk_last)
1680 bit_len_expected += chunk_last.bit_len
1681 encoded_indefinite = (
1682 tag_encode(form=TagFormConstructed, num=impl) +
1685 chunk_last.encode() +
1688 encoded_definite = (
1689 tag_encode(form=TagFormConstructed, num=impl) +
1690 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1694 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1695 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1696 for lenindef_expected, encoded in (
1697 (True, encoded_indefinite),
1698 (False, encoded_definite),
1700 obj, tail = BitString(impl=tag_encode(impl)).decode(
1702 ctx={"bered": True},
1704 self.assertSequenceEqual(tail, junk)
1705 self.assertEqual(obj.bit_len, bit_len_expected)
1706 self.assertSequenceEqual(bytes(obj), payload_expected)
1707 self.assertTrue(obj.ber_encoded)
1708 self.assertEqual(obj.lenindef, lenindef_expected)
1709 self.assertTrue(obj.bered)
1711 self.assertTrue(obj.ber_encoded)
1712 self.assertEqual(obj.lenindef, lenindef_expected)
1713 self.assertTrue(obj.bered)
1714 self.assertEqual(len(encoded), obj.tlvlen)
1717 pprint(obj, big_blobs=True, with_decode_path=True)
1719 evgens = list(BitString(impl=tag_encode(impl)).decode_evgen(
1721 decode_path=decode_path,
1722 ctx={"bered": True},
1724 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
1725 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
1726 self.assertGreater(len(dp), len(decode_path))
1727 self.assertEqual(obj.vlen, chunk_len_expected)
1730 integers(min_value=0),
1733 def test_ber_definite_too_short(self, offset, decode_path):
1734 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1736 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1738 decode_path=decode_path,
1739 ctx={"bered": True},
1741 self.assertEqual(err.exception.decode_path, decode_path)
1742 self.assertEqual(err.exception.offset, offset)
1745 integers(min_value=0),
1748 def test_ber_definite_no_data(self, offset, decode_path):
1749 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1751 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1753 decode_path=decode_path,
1754 ctx={"bered": True},
1756 self.assertEqual(err.exception.decode_path, decode_path)
1757 self.assertEqual(err.exception.offset, offset)
1760 integers(min_value=0),
1762 integers(min_value=1, max_value=3),
1764 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1765 bs = BitString(b"data").encode()
1766 with self.assertRaises(NotEnoughData) as err:
1768 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1770 decode_path=decode_path,
1771 ctx={"bered": True},
1773 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1774 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1777 integers(min_value=0),
1779 integers(min_value=1, max_value=3),
1781 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1782 bs = BitString(b"data").encode()
1783 bs_longer = BitString(b"data-longer").encode()
1784 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1787 tag_encode(3, form=TagFormConstructed) +
1788 len_encode((chunks + 1) * len(bs)) +
1793 decode_path=decode_path,
1794 ctx={"bered": True},
1796 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1797 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1800 integers(min_value=0),
1803 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1804 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1806 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1808 decode_path=decode_path,
1809 ctx={"bered": True},
1811 self.assertEqual(err.exception.decode_path, decode_path)
1812 self.assertEqual(err.exception.offset, offset)
1814 @given(data_strategy())
1815 def test_ber_indefinite_not_multiple(self, d):
1816 bs_short = BitString("'A'H").encode()
1817 bs_full = BitString("'AA'H").encode()
1818 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1819 chunks.append(bs_short)
1820 d.draw(permutations(chunks))
1821 chunks.append(bs_short)
1822 offset = d.draw(integers(min_value=0))
1823 decode_path = d.draw(decode_path_strat)
1824 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1827 tag_encode(3, form=TagFormConstructed) +
1833 decode_path=decode_path,
1834 ctx={"bered": True},
1837 err.exception.decode_path,
1838 decode_path + (str(chunks.index(bs_short)),),
1841 err.exception.offset,
1842 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1845 def test_x690_vector(self):
1846 vector = BitString("'0A3B5F291CD'H")
1847 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1848 self.assertSequenceEqual(tail, b"")
1849 self.assertEqual(obj, vector)
1850 obj, tail = BitString().decode(
1851 hexdec("23800303000A3B0305045F291CD00000"),
1852 ctx={"bered": True},
1854 self.assertSequenceEqual(tail, b"")
1855 self.assertEqual(obj, vector)
1856 self.assertTrue(obj.ber_encoded)
1857 self.assertTrue(obj.lenindef)
1858 self.assertTrue(obj.bered)
1860 self.assertTrue(obj.ber_encoded)
1861 self.assertTrue(obj.lenindef)
1862 self.assertTrue(obj.bered)
1866 def octet_string_values_strategy(draw, do_expl=False):
1867 bound_min, bound_max = sorted(draw(sets(
1868 integers(min_value=0, max_value=1 << 7),
1872 value = draw(one_of(
1874 binary(min_size=bound_min, max_size=bound_max),
1876 default = draw(one_of(
1878 binary(min_size=bound_min, max_size=bound_max),
1881 if draw(booleans()):
1882 bounds = (bound_min, bound_max)
1886 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1888 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1889 optional = draw(one_of(none(), booleans()))
1891 draw(integers(min_value=0)),
1892 draw(integers(min_value=0)),
1893 draw(integers(min_value=0)),
1895 return (value, bounds, impl, expl, default, optional, _decoded)
1898 class OctetStringInherited(OctetString):
1902 class TestOctetString(CommonMixin, TestCase):
1903 base_klass = OctetString
1905 def test_invalid_value_type(self):
1906 with self.assertRaises(InvalidValueType) as err:
1907 OctetString(text_type(123))
1911 def test_optional(self, optional):
1912 obj = OctetString(default=OctetString(b""), optional=optional)
1913 self.assertTrue(obj.optional)
1916 def test_ready(self, value):
1918 self.assertFalse(obj.ready)
1921 pprint(obj, big_blobs=True, with_decode_path=True)
1922 with self.assertRaises(ObjNotReady) as err:
1925 obj = OctetString(value)
1926 self.assertTrue(obj.ready)
1929 pprint(obj, big_blobs=True, with_decode_path=True)
1931 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1932 def test_comparison(self, value1, value2, tag1, tag2):
1933 for klass in (OctetString, OctetStringInherited):
1934 obj1 = klass(value1)
1935 obj2 = klass(value2)
1936 self.assertEqual(obj1 == obj2, value1 == value2)
1937 self.assertEqual(obj1 != obj2, value1 != value2)
1938 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1939 obj1 = klass(value1, impl=tag1)
1940 obj2 = klass(value1, impl=tag2)
1941 self.assertEqual(obj1 == obj2, tag1 == tag2)
1942 self.assertEqual(obj1 != obj2, tag1 != tag2)
1944 @given(lists(binary()))
1945 def test_sorted_works(self, values):
1946 self.assertSequenceEqual(
1947 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1951 @given(data_strategy())
1952 def test_bounds_satisfied(self, d):
1953 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1954 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1955 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1956 OctetString(value=value, bounds=(bound_min, bound_max))
1958 @given(data_strategy())
1959 def test_bounds_unsatisfied(self, d):
1960 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1961 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1962 value = d.draw(binary(max_size=bound_min - 1))
1963 with self.assertRaises(BoundsError) as err:
1964 OctetString(value=value, bounds=(bound_min, bound_max))
1966 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1967 OctetString(bounds=(bound_min, bound_max)).decode(
1968 OctetString(value).encode()
1971 value = d.draw(binary(min_size=bound_max + 1))
1972 with self.assertRaises(BoundsError) as err:
1973 OctetString(value=value, bounds=(bound_min, bound_max))
1975 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1976 OctetString(bounds=(bound_min, bound_max)).decode(
1977 OctetString(value).encode()
1981 @given(data_strategy())
1982 def test_call(self, d):
1983 for klass in (OctetString, OctetStringInherited):
1992 ) = d.draw(octet_string_values_strategy())
1993 obj_initial = klass(
1999 optional_initial or False,
2010 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
2011 if (default is None) and (obj_initial.default is not None):
2014 (bounds is None) and
2015 (value is not None) and
2016 (bounds_initial is not None) and
2017 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2021 (bounds is None) and
2022 (default is not None) and
2023 (bounds_initial is not None) and
2024 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2027 obj = obj_initial(value, bounds, impl, expl, default, optional)
2029 value_expected = default if value is None else value
2031 default_initial if value_expected is None
2034 self.assertEqual(obj, value_expected)
2035 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2036 self.assertEqual(obj.expl_tag, expl or expl_initial)
2039 default_initial if default is None else default,
2041 if obj.default is None:
2042 optional = optional_initial if optional is None else optional
2043 optional = False if optional is None else optional
2046 self.assertEqual(obj.optional, optional)
2048 (obj._bound_min, obj._bound_max),
2049 bounds or bounds_initial or (0, float("+inf")),
2052 @given(octet_string_values_strategy())
2053 def test_copy(self, values):
2054 for klass in (OctetString, OctetStringInherited):
2055 obj = klass(*values)
2056 for copy_func in copy_funcs:
2057 obj_copied = copy_func(obj)
2058 self.assert_copied_basic_fields(obj, obj_copied)
2059 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2060 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2061 self.assertEqual(obj._value, obj_copied._value)
2065 integers(min_value=1).map(tag_encode),
2067 def test_stripped(self, value, tag_impl):
2068 obj = OctetString(value, impl=tag_impl)
2069 with self.assertRaises(NotEnoughData):
2070 obj.decode(obj.encode()[:-1])
2074 integers(min_value=1).map(tag_ctxc),
2076 def test_stripped_expl(self, value, tag_expl):
2077 obj = OctetString(value, expl=tag_expl)
2078 with self.assertRaises(NotEnoughData):
2079 obj.decode(obj.encode()[:-1])
2082 integers(min_value=31),
2083 integers(min_value=0),
2086 def test_bad_tag(self, tag, offset, decode_path):
2087 with self.assertRaises(DecodeError) as err:
2088 OctetString().decode(
2089 tag_encode(tag)[:-1],
2091 decode_path=decode_path,
2094 self.assertEqual(err.exception.offset, offset)
2095 self.assertEqual(err.exception.decode_path, decode_path)
2098 integers(min_value=128),
2099 integers(min_value=0),
2102 def test_bad_len(self, l, offset, decode_path):
2103 with self.assertRaises(DecodeError) as err:
2104 OctetString().decode(
2105 OctetString.tag_default + len_encode(l)[:-1],
2107 decode_path=decode_path,
2110 self.assertEqual(err.exception.offset, offset)
2111 self.assertEqual(err.exception.decode_path, decode_path)
2114 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2115 integers(min_value=0),
2118 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2119 value, bound_min = list(sorted(ints))
2121 class String(OctetString):
2122 bounds = (bound_min, bound_min)
2123 with self.assertRaises(DecodeError) as err:
2125 OctetString(b"\x00" * value).encode(),
2127 decode_path=decode_path,
2130 self.assertEqual(err.exception.offset, offset)
2131 self.assertEqual(err.exception.decode_path, decode_path)
2133 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2135 octet_string_values_strategy(),
2137 integers(min_value=1).map(tag_ctxc),
2138 integers(min_value=0),
2142 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2143 for klass in (OctetString, OctetStringInherited):
2144 _, _, _, _, default, optional, _decoded = values
2153 pprint(obj, big_blobs=True, with_decode_path=True)
2154 self.assertFalse(obj.expled)
2155 obj_encoded = obj.encode()
2156 obj_expled = obj(value, expl=tag_expl)
2157 self.assertTrue(obj_expled.expled)
2159 list(obj_expled.pps())
2160 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2161 obj_expled_encoded = obj_expled.encode()
2162 ctx_copied = deepcopy(ctx_dummy)
2163 obj_decoded, tail = obj_expled.decode(
2164 obj_expled_encoded + tail_junk,
2168 self.assertDictEqual(ctx_copied, ctx_dummy)
2170 list(obj_decoded.pps())
2171 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2172 self.assertEqual(tail, tail_junk)
2173 self.assertEqual(obj_decoded, obj_expled)
2174 self.assertNotEqual(obj_decoded, obj)
2175 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2176 self.assertEqual(bytes(obj_decoded), bytes(obj))
2177 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2178 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2179 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2181 obj_decoded.expl_llen,
2182 len(len_encode(len(obj_encoded))),
2184 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2185 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2188 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2190 self.assertEqual(obj_decoded.expl_offset, offset)
2191 assert_exceeding_data(
2193 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2197 evgens = list(obj_expled.decode_evgen(
2198 obj_expled_encoded + tail_junk,
2200 decode_path=decode_path,
2203 self.assertEqual(len(evgens), 1)
2204 _decode_path, obj, tail = evgens[0]
2205 self.assertSequenceEqual(tail, tail_junk)
2206 self.assertEqual(_decode_path, decode_path)
2207 self.assertEqual(obj.expl_offset, offset)
2211 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2213 integers(min_value=1, max_value=30),
2216 binary(min_size=1, max_size=5),
2218 binary(min_size=1, max_size=5),
2229 def test_constructed(self, impl, chunk_inputs, junk, decode_path):
2230 def chunk_constructed(contents):
2232 tag_encode(form=TagFormConstructed, num=4) +
2234 b"".join(OctetString(content).encode() for content in contents) +
2238 chunks_len_expected = []
2239 payload_expected = b""
2240 for chunk_input in chunk_inputs:
2241 if isinstance(chunk_input, binary_type):
2242 chunks.append(OctetString(chunk_input).encode())
2243 payload_expected += chunk_input
2244 chunks_len_expected.append(len(chunk_input))
2246 chunks.append(chunk_constructed(chunk_input))
2247 payload = b"".join(chunk_input)
2248 payload_expected += payload
2249 for c in chunk_input:
2250 chunks_len_expected.append(len(c))
2251 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
2252 encoded_indefinite = (
2253 tag_encode(form=TagFormConstructed, num=impl) +
2258 encoded_definite = (
2259 tag_encode(form=TagFormConstructed, num=impl) +
2260 len_encode(len(b"".join(chunks))) +
2263 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2264 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2265 for lenindef_expected, encoded in (
2266 (True, encoded_indefinite),
2267 (False, encoded_definite),
2269 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2271 ctx={"bered": True},
2273 self.assertSequenceEqual(tail, junk)
2274 self.assertSequenceEqual(bytes(obj), payload_expected)
2275 self.assertTrue(obj.ber_encoded)
2276 self.assertEqual(obj.lenindef, lenindef_expected)
2277 self.assertTrue(obj.bered)
2279 self.assertTrue(obj.ber_encoded)
2280 self.assertEqual(obj.lenindef, lenindef_expected)
2281 self.assertTrue(obj.bered)
2282 self.assertEqual(len(encoded), obj.tlvlen)
2285 pprint(obj, big_blobs=True, with_decode_path=True)
2287 evgens = list(OctetString(impl=tag_encode(impl)).decode_evgen(
2289 decode_path=decode_path,
2290 ctx={"bered": True},
2292 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
2293 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
2294 self.assertGreater(len(dp), len(decode_path))
2295 self.assertEqual(obj.vlen, chunk_len_expected)
2298 integers(min_value=0),
2301 def test_ber_definite_too_short(self, offset, decode_path):
2302 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2303 OctetString().decode(
2304 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2306 decode_path=decode_path,
2307 ctx={"bered": True},
2309 self.assertEqual(err.exception.decode_path, decode_path)
2310 self.assertEqual(err.exception.offset, offset)
2313 integers(min_value=0),
2315 integers(min_value=1, max_value=3),
2317 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2318 bs = OctetString(b"data").encode()
2319 with self.assertRaises(NotEnoughData) as err:
2320 OctetString().decode(
2321 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2323 decode_path=decode_path,
2324 ctx={"bered": True},
2326 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2327 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2330 integers(min_value=0),
2332 integers(min_value=1, max_value=3),
2334 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2335 bs = OctetString(b"data").encode()
2336 bs_longer = OctetString(b"data-longer").encode()
2337 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2338 OctetString().decode(
2340 tag_encode(4, form=TagFormConstructed) +
2341 len_encode((chunks + 1) * len(bs)) +
2346 decode_path=decode_path,
2347 ctx={"bered": True},
2349 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2350 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2354 def null_values_strategy(draw, do_expl=False):
2358 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2360 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2361 optional = draw(one_of(none(), booleans()))
2363 draw(integers(min_value=0)),
2364 draw(integers(min_value=0)),
2365 draw(integers(min_value=0)),
2367 return (impl, expl, optional, _decoded)
2370 class NullInherited(Null):
2374 class TestNull(CommonMixin, TestCase):
2377 def test_ready(self):
2379 self.assertTrue(obj.ready)
2382 pprint(obj, big_blobs=True, with_decode_path=True)
2384 @given(binary(min_size=1), binary(min_size=1))
2385 def test_comparison(self, tag1, tag2):
2386 for klass in (Null, NullInherited):
2387 obj1 = klass(impl=tag1)
2388 obj2 = klass(impl=tag2)
2389 self.assertEqual(obj1 == obj2, tag1 == tag2)
2390 self.assertEqual(obj1 != obj2, tag1 != tag2)
2391 self.assertNotEqual(obj1, tag2)
2393 @given(data_strategy())
2394 def test_call(self, d):
2395 for klass in (Null, NullInherited):
2401 ) = d.draw(null_values_strategy())
2402 obj_initial = klass(
2405 optional=optional_initial or False,
2406 _decoded=_decoded_initial,
2413 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2414 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2415 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2416 self.assertEqual(obj.expl_tag, expl or expl_initial)
2417 optional = optional_initial if optional is None else optional
2418 optional = False if optional is None else optional
2419 self.assertEqual(obj.optional, optional)
2421 @given(null_values_strategy())
2422 def test_copy(self, values):
2423 for klass in (Null, NullInherited):
2424 impl, expl, optional, _decoded = values
2428 optional=optional or False,
2431 for copy_func in copy_funcs:
2432 obj_copied = copy_func(obj)
2433 self.assert_copied_basic_fields(obj, obj_copied)
2435 @given(integers(min_value=1).map(tag_encode))
2436 def test_stripped(self, tag_impl):
2437 obj = Null(impl=tag_impl)
2438 with self.assertRaises(NotEnoughData):
2439 obj.decode(obj.encode()[:-1])
2441 @given(integers(min_value=1).map(tag_ctxc))
2442 def test_stripped_expl(self, tag_expl):
2443 obj = Null(expl=tag_expl)
2444 with self.assertRaises(NotEnoughData):
2445 obj.decode(obj.encode()[:-1])
2448 integers(min_value=31),
2449 integers(min_value=0),
2452 def test_bad_tag(self, tag, offset, decode_path):
2453 with self.assertRaises(DecodeError) as err:
2455 tag_encode(tag)[:-1],
2457 decode_path=decode_path,
2460 self.assertEqual(err.exception.offset, offset)
2461 self.assertEqual(err.exception.decode_path, decode_path)
2464 integers(min_value=128),
2465 integers(min_value=0),
2468 def test_bad_len(self, l, offset, decode_path):
2469 with self.assertRaises(DecodeError) as err:
2471 Null.tag_default + len_encode(l)[:-1],
2473 decode_path=decode_path,
2476 self.assertEqual(err.exception.offset, offset)
2477 self.assertEqual(err.exception.decode_path, decode_path)
2479 @given(binary(min_size=1))
2480 def test_tag_mismatch(self, impl):
2481 assume(impl != Null.tag_default)
2482 with self.assertRaises(TagMismatch):
2483 Null(impl=impl).decode(Null().encode())
2486 null_values_strategy(),
2487 integers(min_value=1).map(tag_ctxc),
2488 integers(min_value=0),
2492 def test_symmetric(self, values, tag_expl, offset, tail_junk, decode_path):
2493 for klass in (Null, NullInherited):
2494 _, _, optional, _decoded = values
2495 obj = klass(optional=optional, _decoded=_decoded)
2498 pprint(obj, big_blobs=True, with_decode_path=True)
2499 self.assertFalse(obj.expled)
2500 obj_encoded = obj.encode()
2501 obj_expled = obj(expl=tag_expl)
2502 self.assertTrue(obj_expled.expled)
2504 list(obj_expled.pps())
2505 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2506 obj_expled_encoded = obj_expled.encode()
2507 ctx_copied = deepcopy(ctx_dummy)
2508 obj_decoded, tail = obj_expled.decode(
2509 obj_expled_encoded + tail_junk,
2513 self.assertDictEqual(ctx_copied, ctx_dummy)
2515 list(obj_decoded.pps())
2516 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2517 self.assertEqual(tail, tail_junk)
2518 self.assertEqual(obj_decoded, obj_expled)
2519 self.assertNotEqual(obj_decoded, obj)
2520 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2521 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2522 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2524 obj_decoded.expl_llen,
2525 len(len_encode(len(obj_encoded))),
2527 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2528 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2531 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2533 self.assertEqual(obj_decoded.expl_offset, offset)
2534 assert_exceeding_data(
2536 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2540 evgens = list(obj_expled.decode_evgen(
2541 obj_expled_encoded + tail_junk,
2543 decode_path=decode_path,
2546 self.assertEqual(len(evgens), 1)
2547 _decode_path, obj, tail = evgens[0]
2548 self.assertSequenceEqual(tail, tail_junk)
2549 self.assertEqual(_decode_path, decode_path)
2550 self.assertEqual(obj, obj_decoded)
2551 self.assertEqual(obj.expl_offset, offset)
2556 @given(integers(min_value=1))
2557 def test_invalid_len(self, l):
2558 with self.assertRaises(InvalidLength):
2559 Null().decode(b"".join((
2566 def oid_strategy(draw):
2567 first_arc = draw(integers(min_value=0, max_value=2))
2569 if first_arc in (0, 1):
2570 second_arc = draw(integers(min_value=0, max_value=39))
2572 second_arc = draw(integers(min_value=0))
2573 other_arcs = draw(lists(integers(min_value=0)))
2574 return tuple([first_arc, second_arc] + other_arcs)
2578 def oid_values_strategy(draw, do_expl=False):
2579 value = draw(one_of(none(), oid_strategy()))
2583 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2585 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2586 default = draw(one_of(none(), oid_strategy()))
2587 optional = draw(one_of(none(), booleans()))
2589 draw(integers(min_value=0)),
2590 draw(integers(min_value=0)),
2591 draw(integers(min_value=0)),
2593 return (value, impl, expl, default, optional, _decoded)
2596 class ObjectIdentifierInherited(ObjectIdentifier):
2600 class TestObjectIdentifier(CommonMixin, TestCase):
2601 base_klass = ObjectIdentifier
2603 def test_invalid_value_type(self):
2604 with self.assertRaises(InvalidValueType) as err:
2605 ObjectIdentifier(123)
2609 def test_optional(self, optional):
2610 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2611 self.assertTrue(obj.optional)
2613 @given(oid_strategy())
2614 def test_ready(self, value):
2615 obj = ObjectIdentifier()
2616 self.assertFalse(obj.ready)
2619 pprint(obj, big_blobs=True, with_decode_path=True)
2620 with self.assertRaises(ObjNotReady) as err:
2623 obj = ObjectIdentifier(value)
2624 self.assertTrue(obj.ready)
2625 self.assertFalse(obj.ber_encoded)
2628 pprint(obj, big_blobs=True, with_decode_path=True)
2631 @given(oid_strategy(), oid_strategy(), binary(min_size=1), binary(min_size=1))
2632 def test_comparison(self, value1, value2, tag1, tag2):
2633 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2634 obj1 = klass(value1)
2635 obj2 = klass(value2)
2636 self.assertEqual(obj1 == obj2, value1 == value2)
2637 self.assertEqual(obj1 != obj2, value1 != value2)
2638 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2639 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2640 obj1 = klass(value1, impl=tag1)
2641 obj2 = klass(value1, impl=tag2)
2642 self.assertEqual(obj1 == obj2, tag1 == tag2)
2643 self.assertEqual(obj1 != obj2, tag1 != tag2)
2645 @given(lists(oid_strategy()))
2646 def test_sorted_works(self, values):
2647 self.assertSequenceEqual(
2648 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2652 @given(data_strategy())
2653 def test_call(self, d):
2654 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2662 ) = d.draw(oid_values_strategy())
2663 obj_initial = klass(
2664 value=value_initial,
2667 default=default_initial,
2668 optional=optional_initial or False,
2669 _decoded=_decoded_initial,
2678 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2687 value_expected = default if value is None else value
2689 default_initial if value_expected is None
2692 self.assertEqual(obj, value_expected)
2693 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2694 self.assertEqual(obj.expl_tag, expl or expl_initial)
2697 default_initial if default is None else default,
2699 if obj.default is None:
2700 optional = optional_initial if optional is None else optional
2701 optional = False if optional is None else optional
2704 self.assertEqual(obj.optional, optional)
2706 @given(oid_values_strategy())
2707 def test_copy(self, values):
2708 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2725 for copy_func in copy_funcs:
2726 obj_copied = copy_func(obj)
2727 self.assert_copied_basic_fields(obj, obj_copied)
2728 self.assertEqual(obj._value, obj_copied._value)
2730 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2733 integers(min_value=1).map(tag_encode),
2735 def test_stripped(self, value, tag_impl):
2736 obj = ObjectIdentifier(value, impl=tag_impl)
2737 with self.assertRaises(NotEnoughData):
2738 obj.decode(obj.encode()[:-1])
2742 integers(min_value=1).map(tag_ctxc),
2744 def test_stripped_expl(self, value, tag_expl):
2745 obj = ObjectIdentifier(value, expl=tag_expl)
2746 with self.assertRaises(NotEnoughData):
2747 obj.decode(obj.encode()[:-1])
2750 integers(min_value=31),
2751 integers(min_value=0),
2754 def test_bad_tag(self, tag, offset, decode_path):
2755 with self.assertRaises(DecodeError) as err:
2756 ObjectIdentifier().decode(
2757 tag_encode(tag)[:-1],
2759 decode_path=decode_path,
2762 self.assertEqual(err.exception.offset, offset)
2763 self.assertEqual(err.exception.decode_path, decode_path)
2766 integers(min_value=128),
2767 integers(min_value=0),
2770 def test_bad_len(self, l, offset, decode_path):
2771 with self.assertRaises(DecodeError) as err:
2772 ObjectIdentifier().decode(
2773 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2775 decode_path=decode_path,
2778 self.assertEqual(err.exception.offset, offset)
2779 self.assertEqual(err.exception.decode_path, decode_path)
2781 def test_zero_oid(self):
2782 with self.assertRaises(NotEnoughData):
2783 ObjectIdentifier().decode(
2784 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2787 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2788 @given(oid_strategy())
2789 def test_unfinished_oid(self, value):
2790 assume(list(value)[-1] > 255)
2791 obj_encoded = ObjectIdentifier(value).encode()
2792 obj, _ = ObjectIdentifier().decode(obj_encoded)
2793 data = obj_encoded[obj.tlen + obj.llen:-1]
2795 ObjectIdentifier.tag_default,
2796 len_encode(len(data)),
2799 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2802 @given(integers(min_value=0))
2803 def test_invalid_short(self, value):
2804 with self.assertRaises(InvalidOID):
2805 ObjectIdentifier((value,))
2806 with self.assertRaises(InvalidOID):
2807 ObjectIdentifier("%d" % value)
2809 @given(integers(min_value=3), integers(min_value=0))
2810 def test_invalid_first_arc(self, first_arc, second_arc):
2811 with self.assertRaises(InvalidOID):
2812 ObjectIdentifier((first_arc, second_arc))
2813 with self.assertRaises(InvalidOID):
2814 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2816 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2817 def test_invalid_second_arc(self, first_arc, second_arc):
2818 with self.assertRaises(InvalidOID):
2819 ObjectIdentifier((first_arc, second_arc))
2820 with self.assertRaises(InvalidOID):
2821 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2823 @given(text(alphabet=ascii_letters + ".", min_size=1))
2824 def test_junk(self, oid):
2825 with self.assertRaises(InvalidOID):
2826 ObjectIdentifier(oid)
2828 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2829 @given(oid_strategy())
2830 def test_validness(self, oid):
2831 obj = ObjectIdentifier(oid)
2832 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2835 pprint(obj, big_blobs=True, with_decode_path=True)
2837 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2839 oid_values_strategy(),
2841 integers(min_value=1).map(tag_ctxc),
2842 integers(min_value=0),
2846 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2847 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2848 _, _, _, default, optional, _decoded = values
2857 pprint(obj, big_blobs=True, with_decode_path=True)
2858 self.assertFalse(obj.expled)
2859 obj_encoded = obj.encode()
2860 obj_expled = obj(value, expl=tag_expl)
2861 self.assertTrue(obj_expled.expled)
2863 list(obj_expled.pps())
2864 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2865 obj_expled_encoded = obj_expled.encode()
2866 ctx_copied = deepcopy(ctx_dummy)
2867 obj_decoded, tail = obj_expled.decode(
2868 obj_expled_encoded + tail_junk,
2872 self.assertDictEqual(ctx_copied, ctx_dummy)
2874 list(obj_decoded.pps())
2875 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2876 self.assertEqual(tail, tail_junk)
2877 self.assertEqual(obj_decoded, obj_expled)
2878 self.assertNotEqual(obj_decoded, obj)
2879 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2880 self.assertEqual(tuple(obj_decoded), tuple(obj))
2881 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2882 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2883 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2885 obj_decoded.expl_llen,
2886 len(len_encode(len(obj_encoded))),
2888 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2889 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2892 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2894 self.assertEqual(obj_decoded.expl_offset, offset)
2895 assert_exceeding_data(
2897 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2901 evgens = list(obj_expled.decode_evgen(
2902 obj_expled_encoded + tail_junk,
2904 decode_path=decode_path,
2907 self.assertEqual(len(evgens), 1)
2908 _decode_path, obj, tail = evgens[0]
2909 self.assertSequenceEqual(tail, tail_junk)
2910 self.assertEqual(_decode_path, decode_path)
2911 self.assertEqual(obj, obj_decoded)
2912 self.assertEqual(obj.expl_offset, offset)
2917 oid_strategy().map(ObjectIdentifier),
2918 oid_strategy().map(ObjectIdentifier),
2920 def test_add(self, oid1, oid2):
2921 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2922 for oid_to_add in (oid2, tuple(oid2)):
2923 self.assertEqual(oid1 + oid_to_add, oid_expect)
2924 with self.assertRaises(InvalidValueType):
2927 def test_go_vectors_valid(self):
2928 for data, expect in (
2930 (b"\x55\x02", (2, 5, 2)),
2931 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2932 (b"\x81\x34\x03", (2, 100, 3)),
2935 ObjectIdentifier().decode(b"".join((
2936 ObjectIdentifier.tag_default,
2937 len_encode(len(data)),
2943 def test_go_vectors_invalid(self):
2944 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2945 with self.assertRaises(DecodeError):
2946 ObjectIdentifier().decode(b"".join((
2947 Integer.tag_default,
2948 len_encode(len(data)),
2952 def test_x690_vector(self):
2954 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2955 ObjectIdentifier((2, 999, 3)),
2958 def test_nonnormalized_first_arc(self):
2960 ObjectIdentifier.tag_default +
2963 ObjectIdentifier((1, 0)).encode()[-1:]
2965 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2966 self.assertTrue(obj.ber_encoded)
2967 self.assertTrue(obj.bered)
2969 self.assertTrue(obj.ber_encoded)
2970 self.assertTrue(obj.bered)
2971 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2972 ObjectIdentifier().decode(tampered)
2974 @given(data_strategy())
2975 def test_negative_arcs(self, d):
2976 oid = list(d.draw(oid_strategy()))
2979 idx = d.draw(integers(min_value=3, max_value=len(oid)))
2981 if oid[idx - 1] == 0:
2983 with self.assertRaises(InvalidOID):
2984 ObjectIdentifier(tuple(oid))
2985 with self.assertRaises(InvalidOID):
2986 ObjectIdentifier(".".join(str(i) for i in oid))
2988 @given(data_strategy())
2989 def test_plused_arcs(self, d):
2990 oid = [str(arc) for arc in d.draw(oid_strategy())]
2991 idx = d.draw(integers(min_value=0, max_value=len(oid)))
2992 oid[idx - 1] = "+" + oid[idx - 1]
2993 with self.assertRaises(InvalidOID):
2994 ObjectIdentifier(".".join(str(i) for i in oid))
2996 @given(data_strategy())
2997 def test_nonnormalized_arcs(self, d):
2998 arcs = d.draw(lists(
2999 integers(min_value=0, max_value=100),
3003 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
3004 _, _, lv = tag_strip(dered)
3005 _, _, v = len_decode(lv)
3006 v_no_first_arc = v[1:]
3007 idx_for_tamper = d.draw(integers(
3009 max_value=len(v_no_first_arc) - 1,
3011 tampered = list(bytearray(v_no_first_arc))
3012 for _ in range(d.draw(integers(min_value=1, max_value=3))):
3013 tampered.insert(idx_for_tamper, 0x80)
3014 tampered = bytes(bytearray(tampered))
3016 ObjectIdentifier.tag_default +
3017 len_encode(len(tampered)) +
3020 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3021 self.assertTrue(obj.ber_encoded)
3022 self.assertTrue(obj.bered)
3024 self.assertTrue(obj.ber_encoded)
3025 self.assertTrue(obj.bered)
3026 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
3027 ObjectIdentifier().decode(tampered)
3031 def enumerated_values_strategy(draw, schema=None, do_expl=False):
3033 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
3034 values = list(draw(sets(
3036 min_size=len(schema),
3037 max_size=len(schema),
3039 schema = list(zip(schema, values))
3040 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
3044 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3046 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3047 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
3048 optional = draw(one_of(none(), booleans()))
3050 draw(integers(min_value=0)),
3051 draw(integers(min_value=0)),
3052 draw(integers(min_value=0)),
3054 return (schema, value, impl, expl, default, optional, _decoded)
3057 class TestEnumerated(CommonMixin, TestCase):
3058 class EWhatever(Enumerated):
3059 schema = (("whatever", 0),)
3061 base_klass = EWhatever
3063 def test_schema_required(self):
3064 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3067 def test_invalid_value_type(self):
3068 with self.assertRaises(InvalidValueType) as err:
3069 self.base_klass((1, 2))
3072 @given(sets(text_letters(), min_size=2))
3073 def test_unknown_name(self, schema_input):
3074 missing = schema_input.pop()
3076 class E(Enumerated):
3077 schema = [(n, 123) for n in schema_input]
3078 with self.assertRaises(ObjUnknown) as err:
3083 sets(text_letters(), min_size=2),
3084 sets(integers(), min_size=2),
3086 def test_unknown_value(self, schema_input, values_input):
3088 missing_value = values_input.pop()
3089 _input = list(zip(schema_input, values_input))
3091 class E(Enumerated):
3093 with self.assertRaises(DecodeError) as err:
3098 def test_optional(self, optional):
3099 obj = self.base_klass(default="whatever", optional=optional)
3100 self.assertTrue(obj.optional)
3102 def test_ready(self):
3103 obj = self.base_klass()
3104 self.assertFalse(obj.ready)
3107 pprint(obj, big_blobs=True, with_decode_path=True)
3108 with self.assertRaises(ObjNotReady) as err:
3111 obj = self.base_klass("whatever")
3112 self.assertTrue(obj.ready)
3115 pprint(obj, big_blobs=True, with_decode_path=True)
3117 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
3118 def test_comparison(self, value1, value2, tag1, tag2):
3119 class E(Enumerated):
3121 ("whatever0", value1),
3122 ("whatever1", value2),
3125 class EInherited(E):
3127 for klass in (E, EInherited):
3128 obj1 = klass(value1)
3129 obj2 = klass(value2)
3130 self.assertEqual(obj1 == obj2, value1 == value2)
3131 self.assertEqual(obj1 != obj2, value1 != value2)
3132 self.assertEqual(obj1 == int(obj2), value1 == value2)
3133 obj1 = klass(value1, impl=tag1)
3134 obj2 = klass(value1, impl=tag2)
3135 self.assertEqual(obj1 == obj2, tag1 == tag2)
3136 self.assertEqual(obj1 != obj2, tag1 != tag2)
3138 @given(data_strategy())
3139 def test_call(self, d):
3148 ) = d.draw(enumerated_values_strategy())
3150 class E(Enumerated):
3151 schema = schema_initial
3153 value=value_initial,
3156 default=default_initial,
3157 optional=optional_initial or False,
3158 _decoded=_decoded_initial,
3168 ) = d.draw(enumerated_values_strategy(
3169 schema=schema_initial,
3170 do_expl=impl_initial is None,
3180 value_expected = default if value is None else value
3182 default_initial if value_expected is None
3187 dict(schema_initial).get(value_expected, value_expected),
3189 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3190 self.assertEqual(obj.expl_tag, expl or expl_initial)
3193 default_initial if default is None else default,
3195 if obj.default is None:
3196 optional = optional_initial if optional is None else optional
3197 optional = False if optional is None else optional
3200 self.assertEqual(obj.optional, optional)
3201 self.assertEqual(obj.specs, dict(schema_initial))
3203 @given(enumerated_values_strategy())
3204 def test_copy(self, values):
3205 schema_input, value, impl, expl, default, optional, _decoded = values
3207 class E(Enumerated):
3208 schema = schema_input
3218 for copy_func in copy_funcs:
3219 obj_copied = copy_func(obj)
3220 self.assert_copied_basic_fields(obj, obj_copied)
3221 self.assertEqual(obj.specs, obj_copied.specs)
3223 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3224 @given(data_strategy())
3225 def test_symmetric(self, d):
3226 schema_input, _, _, _, default, optional, _decoded = d.draw(
3227 enumerated_values_strategy(),
3229 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3230 offset = d.draw(integers(min_value=0))
3231 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3232 tail_junk = d.draw(binary(max_size=5))
3233 decode_path = d.draw(decode_path_strat)
3235 class E(Enumerated):
3236 schema = schema_input
3245 pprint(obj, big_blobs=True, with_decode_path=True)
3246 self.assertFalse(obj.expled)
3247 obj_encoded = obj.encode()
3248 obj_expled = obj(value, expl=tag_expl)
3249 self.assertTrue(obj_expled.expled)
3251 list(obj_expled.pps())
3252 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3253 obj_expled_encoded = obj_expled.encode()
3254 ctx_copied = deepcopy(ctx_dummy)
3255 obj_decoded, tail = obj_expled.decode(
3256 obj_expled_encoded + tail_junk,
3260 self.assertDictEqual(ctx_copied, ctx_dummy)
3262 list(obj_decoded.pps())
3263 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3264 self.assertEqual(tail, tail_junk)
3265 self.assertEqual(obj_decoded, obj_expled)
3266 self.assertNotEqual(obj_decoded, obj)
3267 self.assertEqual(int(obj_decoded), int(obj_expled))
3268 self.assertEqual(int(obj_decoded), int(obj))
3269 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3270 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3271 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3273 obj_decoded.expl_llen,
3274 len(len_encode(len(obj_encoded))),
3276 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3277 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3280 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3282 self.assertEqual(obj_decoded.expl_offset, offset)
3283 assert_exceeding_data(
3285 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3289 evgens = list(obj_expled.decode_evgen(
3290 obj_expled_encoded + tail_junk,
3292 decode_path=decode_path,
3295 self.assertEqual(len(evgens), 1)
3296 _decode_path, obj, tail = evgens[0]
3297 self.assertSequenceEqual(tail, tail_junk)
3298 self.assertEqual(_decode_path, decode_path)
3299 self.assertEqual(obj, obj_decoded)
3300 self.assertEqual(obj.expl_offset, offset)
3306 def string_values_strategy(draw, alphabet, do_expl=False):
3307 bound_min, bound_max = sorted(draw(sets(
3308 integers(min_value=0, max_value=1 << 7),
3312 value = draw(one_of(
3314 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3316 default = draw(one_of(
3318 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3321 if draw(booleans()):
3322 bounds = (bound_min, bound_max)
3326 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3328 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3329 optional = draw(one_of(none(), booleans()))
3331 draw(integers(min_value=0)),
3332 draw(integers(min_value=0)),
3333 draw(integers(min_value=0)),
3335 return (value, bounds, impl, expl, default, optional, _decoded)
3338 class StringMixin(object):
3339 def test_invalid_value_type(self):
3340 with self.assertRaises(InvalidValueType) as err:
3341 self.base_klass((1, 2))
3344 def text_alphabet(self):
3345 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3346 return printable + whitespace
3350 def test_optional(self, optional):
3351 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3352 self.assertTrue(obj.optional)
3354 @given(data_strategy())
3355 def test_ready(self, d):
3356 obj = self.base_klass()
3357 self.assertFalse(obj.ready)
3360 pprint(obj, big_blobs=True, with_decode_path=True)
3362 with self.assertRaises(ObjNotReady) as err:
3365 value = d.draw(text(alphabet=self.text_alphabet()))
3366 obj = self.base_klass(value)
3367 self.assertTrue(obj.ready)
3370 pprint(obj, big_blobs=True, with_decode_path=True)
3373 @given(data_strategy())
3374 def test_comparison(self, d):
3375 value1 = d.draw(text(alphabet=self.text_alphabet()))
3376 value2 = d.draw(text(alphabet=self.text_alphabet()))
3377 tag1 = d.draw(binary(min_size=1))
3378 tag2 = d.draw(binary(min_size=1))
3379 obj1 = self.base_klass(value1)
3380 obj2 = self.base_klass(value2)
3381 self.assertEqual(obj1 == obj2, value1 == value2)
3382 self.assertEqual(obj1 != obj2, value1 != value2)
3383 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3384 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3385 obj1 = self.base_klass(value1, impl=tag1)
3386 obj2 = self.base_klass(value1, impl=tag2)
3387 self.assertEqual(obj1 == obj2, tag1 == tag2)
3388 self.assertEqual(obj1 != obj2, tag1 != tag2)
3390 @given(data_strategy())
3391 def test_bounds_satisfied(self, d):
3392 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3393 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3394 value = d.draw(text(
3395 alphabet=self.text_alphabet(),
3399 self.base_klass(value=value, bounds=(bound_min, bound_max))
3401 @given(data_strategy())
3402 def test_bounds_unsatisfied(self, d):
3403 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3404 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3405 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3406 with self.assertRaises(BoundsError) as err:
3407 self.base_klass(value=value, bounds=(bound_min, bound_max))
3409 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3410 self.base_klass(bounds=(bound_min, bound_max)).decode(
3411 self.base_klass(value).encode()
3414 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3415 with self.assertRaises(BoundsError) as err:
3416 self.base_klass(value=value, bounds=(bound_min, bound_max))
3418 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3419 self.base_klass(bounds=(bound_min, bound_max)).decode(
3420 self.base_klass(value).encode()
3424 @given(data_strategy())
3425 def test_call(self, d):
3434 ) = d.draw(string_values_strategy(self.text_alphabet()))
3435 obj_initial = self.base_klass(
3441 optional_initial or False,
3452 ) = d.draw(string_values_strategy(
3453 self.text_alphabet(),
3454 do_expl=impl_initial is None,
3456 if (default is None) and (obj_initial.default is not None):
3459 (bounds is None) and
3460 (value is not None) and
3461 (bounds_initial is not None) and
3462 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3466 (bounds is None) and
3467 (default is not None) and
3468 (bounds_initial is not None) and
3469 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3472 obj = obj_initial(value, bounds, impl, expl, default, optional)
3474 value_expected = default if value is None else value
3476 default_initial if value_expected is None
3479 self.assertEqual(obj, value_expected)
3480 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3481 self.assertEqual(obj.expl_tag, expl or expl_initial)
3484 default_initial if default is None else default,
3486 if obj.default is None:
3487 optional = optional_initial if optional is None else optional
3488 optional = False if optional is None else optional
3491 self.assertEqual(obj.optional, optional)
3493 (obj._bound_min, obj._bound_max),
3494 bounds or bounds_initial or (0, float("+inf")),
3497 @given(data_strategy())
3498 def test_copy(self, d):
3499 values = d.draw(string_values_strategy(self.text_alphabet()))
3500 obj = self.base_klass(*values)
3501 for copy_func in copy_funcs:
3502 obj_copied = copy_func(obj)
3503 self.assert_copied_basic_fields(obj, obj_copied)
3504 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3505 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3506 self.assertEqual(obj._value, obj_copied._value)
3508 @given(data_strategy())
3509 def test_stripped(self, d):
3510 value = d.draw(text(alphabet=self.text_alphabet()))
3511 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3512 obj = self.base_klass(value, impl=tag_impl)
3513 with self.assertRaises(NotEnoughData):
3514 obj.decode(obj.encode()[:-1])
3516 @given(data_strategy())
3517 def test_stripped_expl(self, d):
3518 value = d.draw(text(alphabet=self.text_alphabet()))
3519 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3520 obj = self.base_klass(value, expl=tag_expl)
3521 with self.assertRaises(NotEnoughData):
3522 obj.decode(obj.encode()[:-1])
3525 integers(min_value=31),
3526 integers(min_value=0),
3529 def test_bad_tag(self, tag, offset, decode_path):
3530 with self.assertRaises(DecodeError) as err:
3531 self.base_klass().decode(
3532 tag_encode(tag)[:-1],
3534 decode_path=decode_path,
3537 self.assertEqual(err.exception.offset, offset)
3538 self.assertEqual(err.exception.decode_path, decode_path)
3541 integers(min_value=128),
3542 integers(min_value=0),
3545 def test_bad_len(self, l, offset, decode_path):
3546 with self.assertRaises(DecodeError) as err:
3547 self.base_klass().decode(
3548 self.base_klass.tag_default + len_encode(l)[:-1],
3550 decode_path=decode_path,
3553 self.assertEqual(err.exception.offset, offset)
3554 self.assertEqual(err.exception.decode_path, decode_path)
3557 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3558 integers(min_value=0),
3561 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3562 value, bound_min = list(sorted(ints))
3564 class String(self.base_klass):
3565 # Multiply this value by four, to satisfy UTF-32 bounds
3566 # (4 bytes per character) validation
3567 bounds = (bound_min * 4, bound_min * 4)
3568 with self.assertRaises(DecodeError) as err:
3570 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3572 decode_path=decode_path,
3575 self.assertEqual(err.exception.offset, offset)
3576 self.assertEqual(err.exception.decode_path, decode_path)
3578 @given(data_strategy())
3579 def test_symmetric(self, d):
3580 values = d.draw(string_values_strategy(self.text_alphabet()))
3581 value = d.draw(text(alphabet=self.text_alphabet()))
3582 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3583 offset = d.draw(integers(min_value=0))
3584 tail_junk = d.draw(binary(max_size=5))
3585 decode_path = d.draw(decode_path_strat)
3586 _, _, _, _, default, optional, _decoded = values
3587 obj = self.base_klass(
3595 pprint(obj, big_blobs=True, with_decode_path=True)
3596 self.assertFalse(obj.expled)
3597 obj_encoded = obj.encode()
3598 obj_expled = obj(value, expl=tag_expl)
3599 self.assertTrue(obj_expled.expled)
3601 list(obj_expled.pps())
3602 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3603 obj_expled_encoded = obj_expled.encode()
3604 ctx_copied = deepcopy(ctx_dummy)
3605 obj_decoded, tail = obj_expled.decode(
3606 obj_expled_encoded + tail_junk,
3610 self.assertDictEqual(ctx_copied, ctx_dummy)
3612 list(obj_decoded.pps())
3613 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3614 self.assertEqual(tail, tail_junk)
3615 self.assertEqual(obj_decoded, obj_expled)
3616 self.assertNotEqual(obj_decoded, obj)
3617 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3618 self.assertEqual(bytes(obj_decoded), bytes(obj))
3619 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3620 self.assertEqual(text_type(obj_decoded), text_type(obj))
3621 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3622 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3623 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3625 obj_decoded.expl_llen,
3626 len(len_encode(len(obj_encoded))),
3628 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3629 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3632 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3634 self.assertEqual(obj_decoded.expl_offset, offset)
3635 assert_exceeding_data(
3637 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3641 evgens = list(obj_expled.decode_evgen(
3642 obj_expled_encoded + tail_junk,
3644 decode_path=decode_path,
3647 self.assertEqual(len(evgens), 1)
3648 _decode_path, obj, tail = evgens[0]
3649 self.assertSequenceEqual(tail, tail_junk)
3650 self.assertEqual(_decode_path, decode_path)
3651 if not getattr(self, "evgen_mode_skip_value", True):
3652 self.assertEqual(obj, obj_decoded)
3653 self.assertEqual(obj.expl_offset, offset)
3658 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3659 base_klass = UTF8String
3662 cyrillic_letters = text(
3663 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3669 class UnicodeDecodeErrorMixin(object):
3670 @given(cyrillic_letters)
3671 def test_unicode_decode_error(self, cyrillic_text):
3672 with self.assertRaises(DecodeError):
3673 self.base_klass(cyrillic_text)
3676 class TestNumericString(StringMixin, CommonMixin, TestCase):
3677 base_klass = NumericString
3679 def text_alphabet(self):
3682 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3683 def test_non_numeric(self, non_numeric_text):
3684 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3685 self.base_klass(non_numeric_text)
3688 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3689 integers(min_value=0),
3692 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3693 value, bound_min = list(sorted(ints))
3695 class String(self.base_klass):
3696 bounds = (bound_min, bound_min)
3697 with self.assertRaises(DecodeError) as err:
3699 self.base_klass(b"1" * value).encode(),
3701 decode_path=decode_path,
3704 self.assertEqual(err.exception.offset, offset)
3705 self.assertEqual(err.exception.decode_path, decode_path)
3708 class TestPrintableString(
3709 UnicodeDecodeErrorMixin,
3714 base_klass = PrintableString
3716 def text_alphabet(self):
3717 return ascii_letters + digits + " '()+,-./:=?"
3719 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3720 def test_non_printable(self, non_printable_text):
3721 with assertRaisesRegex(self, DecodeError, "non-printable"):
3722 self.base_klass(non_printable_text)
3725 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3726 integers(min_value=0),
3729 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3730 value, bound_min = list(sorted(ints))
3732 class String(self.base_klass):
3733 bounds = (bound_min, bound_min)
3734 with self.assertRaises(DecodeError) as err:
3736 self.base_klass(b"1" * value).encode(),
3738 decode_path=decode_path,
3741 self.assertEqual(err.exception.offset, offset)
3742 self.assertEqual(err.exception.decode_path, decode_path)
3744 def test_allowable_invalid_chars(self):
3746 ("*", {"allow_asterisk": True}),
3747 ("&", {"allow_ampersand": True}),
3748 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3751 obj = self.base_klass(s)
3752 for prop in kwargs.keys():
3753 self.assertFalse(getattr(obj, prop))
3755 with assertRaisesRegex(self, DecodeError, "non-printable"):
3757 self.base_klass(s, **kwargs)
3758 klass = self.base_klass(**kwargs)
3760 for prop in kwargs.keys():
3761 self.assertTrue(getattr(obj, prop))
3764 for prop in kwargs.keys():
3765 self.assertTrue(getattr(obj, prop))
3768 class TestTeletexString(
3769 UnicodeDecodeErrorMixin,
3774 base_klass = TeletexString
3777 class TestVideotexString(
3778 UnicodeDecodeErrorMixin,
3783 base_klass = VideotexString
3786 class TestIA5String(
3787 UnicodeDecodeErrorMixin,
3792 base_klass = IA5String
3795 class TestGraphicString(
3796 UnicodeDecodeErrorMixin,
3801 base_klass = GraphicString
3804 class TestVisibleString(
3805 UnicodeDecodeErrorMixin,
3810 base_klass = VisibleString
3812 def test_x690_vector(self):
3813 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3814 self.assertSequenceEqual(tail, b"")
3815 self.assertEqual(str(obj), "Jones")
3816 self.assertFalse(obj.ber_encoded)
3817 self.assertFalse(obj.lenindef)
3818 self.assertFalse(obj.bered)
3820 obj, tail = VisibleString().decode(
3821 hexdec("3A0904034A6F6E04026573"),
3822 ctx={"bered": True},
3824 self.assertSequenceEqual(tail, b"")
3825 self.assertEqual(str(obj), "Jones")
3826 self.assertTrue(obj.ber_encoded)
3827 self.assertFalse(obj.lenindef)
3828 self.assertTrue(obj.bered)
3830 self.assertTrue(obj.ber_encoded)
3831 self.assertFalse(obj.lenindef)
3832 self.assertTrue(obj.bered)
3834 obj, tail = VisibleString().decode(
3835 hexdec("3A8004034A6F6E040265730000"),
3836 ctx={"bered": True},
3838 self.assertSequenceEqual(tail, b"")
3839 self.assertEqual(str(obj), "Jones")
3840 self.assertTrue(obj.ber_encoded)
3841 self.assertTrue(obj.lenindef)
3842 self.assertTrue(obj.bered)
3844 self.assertTrue(obj.ber_encoded)
3845 self.assertTrue(obj.lenindef)
3846 self.assertTrue(obj.bered)
3849 class TestGeneralString(
3850 UnicodeDecodeErrorMixin,
3855 base_klass = GeneralString
3858 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3859 base_klass = UniversalString
3862 class TestBMPString(StringMixin, CommonMixin, TestCase):
3863 base_klass = BMPString
3867 def generalized_time_values_strategy(
3875 if draw(booleans()):
3876 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3878 value = value.replace(microsecond=0)
3880 if draw(booleans()):
3881 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3883 default = default.replace(microsecond=0)
3887 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3889 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3890 optional = draw(one_of(none(), booleans()))
3892 draw(integers(min_value=0)),
3893 draw(integers(min_value=0)),
3894 draw(integers(min_value=0)),
3896 return (value, impl, expl, default, optional, _decoded)
3899 class TimeMixin(object):
3900 def test_invalid_value_type(self):
3901 with self.assertRaises(InvalidValueType) as err:
3902 self.base_klass(datetime.now().timetuple())
3905 @given(data_strategy())
3906 def test_optional(self, d):
3907 default = d.draw(datetimes(
3908 min_value=self.min_datetime,
3909 max_value=self.max_datetime,
3911 optional = d.draw(booleans())
3912 obj = self.base_klass(default=default, optional=optional)
3913 self.assertTrue(obj.optional)
3915 @given(data_strategy())
3916 def test_ready(self, d):
3917 obj = self.base_klass()
3918 self.assertFalse(obj.ready)
3921 pprint(obj, big_blobs=True, with_decode_path=True)
3922 with self.assertRaises(ObjNotReady) as err:
3925 value = d.draw(datetimes(
3926 min_value=self.min_datetime,
3927 max_value=self.max_datetime,
3929 obj = self.base_klass(value)
3930 self.assertTrue(obj.ready)
3933 pprint(obj, big_blobs=True, with_decode_path=True)
3935 @given(data_strategy())
3936 def test_comparison(self, d):
3937 value1 = d.draw(datetimes(
3938 min_value=self.min_datetime,
3939 max_value=self.max_datetime,
3941 value2 = d.draw(datetimes(
3942 min_value=self.min_datetime,
3943 max_value=self.max_datetime,
3945 tag1 = d.draw(binary(min_size=1))
3946 tag2 = d.draw(binary(min_size=1))
3948 value1 = value1.replace(microsecond=0)
3949 value2 = value2.replace(microsecond=0)
3950 obj1 = self.base_klass(value1)
3951 obj2 = self.base_klass(value2)
3952 self.assertEqual(obj1 == obj2, value1 == value2)
3953 self.assertEqual(obj1 != obj2, value1 != value2)
3954 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3955 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3956 obj1 = self.base_klass(value1, impl=tag1)
3957 obj2 = self.base_klass(value1, impl=tag2)
3958 self.assertEqual(obj1 == obj2, tag1 == tag2)
3959 self.assertEqual(obj1 != obj2, tag1 != tag2)
3961 @given(data_strategy())
3962 def test_call(self, d):
3970 ) = d.draw(generalized_time_values_strategy(
3971 min_datetime=self.min_datetime,
3972 max_datetime=self.max_datetime,
3973 omit_ms=self.omit_ms,
3975 obj_initial = self.base_klass(
3976 value=value_initial,
3979 default=default_initial,
3980 optional=optional_initial or False,
3981 _decoded=_decoded_initial,
3990 ) = d.draw(generalized_time_values_strategy(
3991 min_datetime=self.min_datetime,
3992 max_datetime=self.max_datetime,
3993 omit_ms=self.omit_ms,
3994 do_expl=impl_initial is None,
4004 value_expected = default if value is None else value
4006 default_initial if value_expected is None
4009 self.assertEqual(obj, value_expected)
4010 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4011 self.assertEqual(obj.expl_tag, expl or expl_initial)
4014 default_initial if default is None else default,
4016 if obj.default is None:
4017 optional = optional_initial if optional is None else optional
4018 optional = False if optional is None else optional
4021 self.assertEqual(obj.optional, optional)
4023 @given(data_strategy())
4024 def test_copy(self, d):
4025 values = d.draw(generalized_time_values_strategy(
4026 min_datetime=self.min_datetime,
4027 max_datetime=self.max_datetime,
4029 obj = self.base_klass(*values)
4030 for copy_func in copy_funcs:
4031 obj_copied = copy_func(obj)
4032 self.assert_copied_basic_fields(obj, obj_copied)
4033 self.assertEqual(obj._value, obj_copied._value)
4035 @given(data_strategy())
4036 def test_stripped(self, d):
4037 value = d.draw(datetimes(
4038 min_value=self.min_datetime,
4039 max_value=self.max_datetime,
4041 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4042 obj = self.base_klass(value, impl=tag_impl)
4043 with self.assertRaises(NotEnoughData):
4044 obj.decode(obj.encode()[:-1])
4046 @given(data_strategy())
4047 def test_stripped_expl(self, d):
4048 value = d.draw(datetimes(
4049 min_value=self.min_datetime,
4050 max_value=self.max_datetime,
4052 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4053 obj = self.base_klass(value, expl=tag_expl)
4054 with self.assertRaises(NotEnoughData):
4055 obj.decode(obj.encode()[:-1])
4057 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4058 @given(data_strategy())
4059 def test_symmetric(self, d):
4060 values = d.draw(generalized_time_values_strategy(
4061 min_datetime=self.min_datetime,
4062 max_datetime=self.max_datetime,
4064 value = d.draw(datetimes(
4065 min_value=self.min_datetime,
4066 max_value=self.max_datetime,
4068 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4069 offset = d.draw(integers(min_value=0))
4070 tail_junk = d.draw(binary(max_size=5))
4071 _, _, _, default, optional, _decoded = values
4072 obj = self.base_klass(
4080 pprint(obj, big_blobs=True, with_decode_path=True)
4081 self.assertFalse(obj.expled)
4082 obj_encoded = obj.encode()
4083 self.additional_symmetric_check(value, obj_encoded)
4084 obj_expled = obj(value, expl=tag_expl)
4085 self.assertTrue(obj_expled.expled)
4087 list(obj_expled.pps())
4088 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4089 obj_expled_encoded = obj_expled.encode()
4090 ctx_copied = deepcopy(ctx_dummy)
4091 obj_decoded, tail = obj_expled.decode(
4092 obj_expled_encoded + tail_junk,
4096 self.assertDictEqual(ctx_copied, ctx_dummy)
4098 list(obj_decoded.pps())
4099 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4100 self.assertEqual(tail, tail_junk)
4101 self.assertEqual(obj_decoded, obj_expled)
4102 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
4103 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
4104 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4105 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4106 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4108 obj_decoded.expl_llen,
4109 len(len_encode(len(obj_encoded))),
4111 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4112 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4115 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4117 self.assertEqual(obj_decoded.expl_offset, offset)
4118 assert_exceeding_data(
4120 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4125 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
4126 base_klass = GeneralizedTime
4128 min_datetime = datetime(1900, 1, 1)
4129 max_datetime = datetime(9999, 12, 31)
4130 evgen_mode_skip_value = False
4132 def additional_symmetric_check(self, value, obj_encoded):
4133 if value.microsecond > 0:
4134 self.assertFalse(obj_encoded.endswith(b"0Z"))
4136 def test_repr_not_ready(self):
4137 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
4138 repr(GeneralizedTime())
4140 def test_x690_vector_valid(self):
4144 b"19920722132100.3Z",
4146 GeneralizedTime(data)
4148 def test_x690_vector_invalid(self):
4151 b"19920622123421.0Z",
4152 b"19920722132100.30Z",
4154 with self.assertRaises(DecodeError) as err:
4155 GeneralizedTime(data)
4158 def test_go_vectors_invalid(self):
4170 b"-20100102030410Z",
4171 b"2010-0102030410Z",
4172 b"2010-0002030410Z",
4173 b"201001-02030410Z",
4174 b"20100102-030410Z",
4175 b"2010010203-0410Z",
4176 b"201001020304-10Z",
4177 # These ones are INVALID in *DER*, but accepted
4178 # by Go's encoding/asn1
4179 b"20100102030405+0607",
4180 b"20100102030405-0607",
4182 with self.assertRaises(DecodeError) as err:
4183 GeneralizedTime(data)
4186 def test_go_vectors_valid(self):
4188 GeneralizedTime(b"20100102030405Z").todatetime(),
4189 datetime(2010, 1, 2, 3, 4, 5, 0),
4192 def test_go_vectors_valid_ber(self):
4194 b"20100102030405+0607",
4195 b"20100102030405-0607",
4197 GeneralizedTime(data, ctx={"bered": True})
4199 def test_utc_offsets(self):
4200 """Some know equal UTC offsets
4203 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4207 "200101011130-0700",
4208 "200101011500-03:30",
4211 self.assertEqual(dts[0], dts[1])
4212 self.assertEqual(dts[0], dts[2])
4213 self.assertEqual(dts[0], dts[3])
4215 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4216 @given(data_strategy())
4217 def test_valid_ber(self, d):
4218 min_year = 1901 if PY2 else 2
4219 year = d.draw(integers(min_value=min_year, max_value=9999))
4220 month = d.draw(integers(min_value=1, max_value=12))
4221 day = d.draw(integers(min_value=1, max_value=28))
4222 hours = d.draw(integers(min_value=0, max_value=23))
4223 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4224 dt = datetime(year, month, day, hours)
4225 fractions_sign = d.draw(sampled_from(" ,."))
4227 if fractions_sign != " ":
4228 fractions = random()
4229 if d.draw(booleans()):
4230 minutes = d.draw(integers(min_value=0, max_value=59))
4231 data += "%02d" % minutes
4232 dt += timedelta(seconds=60 * minutes)
4233 if d.draw(booleans()):
4234 seconds = d.draw(integers(min_value=0, max_value=59))
4235 data += "%02d" % seconds
4236 dt += timedelta(seconds=seconds)
4237 if fractions is not None:
4238 dt += timedelta(microseconds=10**6 * fractions)
4239 elif fractions is not None:
4240 dt += timedelta(seconds=60 * fractions)
4241 elif fractions is not None:
4242 dt += timedelta(seconds=3600 * fractions)
4243 if fractions is not None:
4244 data += fractions_sign + str(fractions)[2:]
4245 if d.draw(booleans()):
4247 elif d.draw(booleans()):
4248 offset_hour = d.draw(integers(min_value=0, max_value=13))
4250 if d.draw(booleans()):
4255 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4256 data += "%02d" % offset_hour
4257 minutes_separator = d.draw(sampled_from((None, "", ":")))
4258 if minutes_separator is not None:
4259 offset_minute = d.draw(integers(min_value=0, max_value=59))
4260 dt -= timedelta(seconds=sign * 60 * offset_minute)
4261 data += "%s%02d" % (minutes_separator, offset_minute)
4262 data = data.encode("ascii")
4263 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4265 GeneralizedTime().decod(data_der)
4270 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4273 mktime(obj.todatetime().timetuple()),
4274 mktime(dt.timetuple()),
4277 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4278 self.assertEqual(obj.ber_encoded, not dered)
4279 self.assertEqual(obj.bered, not dered)
4280 self.assertEqual(obj.ber_raw, None if dered else data)
4281 self.assertEqual(obj.encode() == data_der, dered)
4286 def test_invalid_ber(self):
4288 # "00010203040506.07",
4289 "-0010203040506.07",
4290 "0001-203040506.07",
4291 "000102-3040506.07",
4292 "00010203-40506.07",
4293 "0001020304-506.07",
4294 "000102030405-6.07",
4295 "00010203040506.-7",
4296 "+0010203040506.07",
4297 "0001+203040506.07",
4298 "000102+3040506.07",
4299 "00010203+40506.07",
4300 "0001020304+506.07",
4301 "000102030405+6.07",
4302 "00010203040506.+7",
4303 " 0010203040506.07",
4304 "0001 203040506.07",
4305 "000102 3040506.07",
4306 "00010203 40506.07",
4307 "0001020304 506.07",
4308 "000102030405 6.07",
4309 "00010203040506. 7",
4310 "001 0203040506.07",
4311 "00012 03040506.07",
4312 "0001023 040506.07",
4313 "000102034 0506.07",
4314 "00010203045 06.07",
4315 "0001020304056 .07",
4316 "00010203040506.7 ",
4396 "00010203040506.07+15",
4397 "00010203040506.07-15",
4398 "00010203040506.07+14:60",
4399 "00010203040506.07+1460",
4400 "00010203040506.07-1460",
4401 "00010203040506.07+00:60",
4402 "00010203040506.07-00:60",
4404 "00010203040506+15",
4405 "00010203040506-15",
4406 "00010203040506+14:60",
4407 "00010203040506+1460",
4408 "00010203040506-1460",
4409 "00010203040506+00:60",
4410 "00010203040506-00:60",
4419 with self.assertRaises(DecodeError):
4420 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4421 data = data.replace(".", ",")
4422 with self.assertRaises(DecodeError):
4423 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4427 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4428 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4430 binary(min_size=1, max_size=1),
4432 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4433 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4436 def test_junk(self, part0, part1, part2):
4437 junk = part0 + part1 + part2
4438 assume(not (set(junk) <= set(digits.encode("ascii"))))
4439 with self.assertRaises(DecodeError):
4440 GeneralizedTime().decode(
4441 GeneralizedTime.tag_default +
4442 len_encode(len(junk)) +
4448 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4449 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4451 binary(min_size=1, max_size=1),
4453 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4454 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4457 def test_junk_dm(self, part0, part1, part2):
4458 junk = part0 + part1 + part2
4459 assume(not (set(junk) <= set(digits.encode("ascii"))))
4460 with self.assertRaises(DecodeError):
4461 GeneralizedTime().decode(
4462 GeneralizedTime.tag_default +
4463 len_encode(len(junk)) +
4467 def test_ns_fractions(self):
4468 GeneralizedTime(b"20010101000000.000001Z")
4469 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
4470 GeneralizedTime(b"20010101000000.0000001Z")
4472 def test_non_pure_integers(self):
4474 # b"20000102030405Z,
4481 b"20000102030405.+6Z",
4482 b"20000102030405.-6Z",
4489 b"20000102030405._6Z",
4490 b"20000102030405.6_Z",
4497 b"20000102030405. 6Z",
4504 b"20000102030405.6 Z",
4506 with self.assertRaises(DecodeError):
4507 GeneralizedTime(data)
4510 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4511 base_klass = UTCTime
4513 min_datetime = datetime(2000, 1, 1)
4514 max_datetime = datetime(2049, 12, 31)
4515 evgen_mode_skip_value = False
4517 def additional_symmetric_check(self, value, obj_encoded):
4520 def test_repr_not_ready(self):
4521 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
4524 def test_x690_vector_valid(self):
4532 def test_x690_vector_invalid(self):
4537 with self.assertRaises(DecodeError) as err:
4541 def test_go_vectors_invalid(self):
4567 # These ones are INVALID in *DER*, but accepted
4568 # by Go's encoding/asn1
4569 b"910506164540-0700",
4570 b"910506164540+0730",
4574 with self.assertRaises(DecodeError) as err:
4578 def test_go_vectors_valid(self):
4580 UTCTime(b"910506234540Z").todatetime(),
4581 datetime(1991, 5, 6, 23, 45, 40, 0),
4584 def test_non_pure_integers(self):
4613 with self.assertRaises(DecodeError):
4616 def test_x680_vector_valid_ber(self):
4618 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4619 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4620 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4621 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4623 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4624 obj = UTCTime().decod(data_der, ctx={"bered": True})
4625 self.assertEqual(obj, dt)
4626 self.assertEqual(obj.todatetime(), dt)
4627 self.assertTrue(obj.ber_encoded)
4628 self.assertTrue(obj.bered)
4629 self.assertEqual(obj.ber_raw, data)
4630 self.assertNotEqual(obj.encode(), data_der)
4633 def test_go_vectors_valid_ber(self):
4635 b"910506164540-0700",
4636 b"910506164540+0730",
4640 data = UTCTime.tag_default + len_encode(len(data)) + data
4641 obj = UTCTime().decod(data, ctx={"bered": True})
4642 self.assertTrue(obj.ber_encoded)
4643 self.assertTrue(obj.bered)
4644 self.assertNotEqual(obj.encode(), data)
4647 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4648 @given(data_strategy())
4649 def test_valid_ber(self, d):
4650 year = d.draw(integers(min_value=0, max_value=99))
4651 month = d.draw(integers(min_value=1, max_value=12))
4652 day = d.draw(integers(min_value=1, max_value=28))
4653 hours = d.draw(integers(min_value=0, max_value=23))
4654 minute = d.draw(integers(min_value=0, max_value=59))
4655 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4657 year + (2000 if year < 50 else 1900),
4664 if d.draw(booleans()):
4666 seconds = d.draw(integers(min_value=0, max_value=59))
4667 data += "%02d" % seconds
4668 dt += timedelta(seconds=seconds)
4669 if d.draw(booleans()):
4673 offset_hour = d.draw(integers(min_value=0, max_value=13))
4674 offset_minute = d.draw(integers(min_value=0, max_value=59))
4675 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4676 if d.draw(booleans()):
4682 data += "%02d%02d" % (offset_hour, offset_minute)
4683 data = data.encode("ascii")
4684 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4685 obj = UTCTime().decod(data_der, ctx={"bered": True})
4686 self.assertEqual(obj, dt)
4687 self.assertEqual(obj.todatetime(), dt)
4688 self.assertEqual(obj.ber_encoded, not dered)
4689 self.assertEqual(obj.bered, not dered)
4690 self.assertEqual(obj.ber_raw, None if dered else data)
4691 self.assertEqual(obj.encode() == data_der, dered)
4696 def test_invalid_ber(self):
4737 b"0001020304+0000Z",
4746 with self.assertRaises(DecodeError):
4747 UTCTime(data, ctx={"bered": True})
4748 data = data[:8] + data[8+2:]
4749 with self.assertRaises(DecodeError):
4750 UTCTime(data, ctx={"bered": True})
4795 b"000102030405+000",
4796 b"000102030405+000Z",
4797 b"000102030405+0000Z",
4798 b"000102030405+-101",
4799 b"000102030405+01-1",
4800 b"000102030405+0060",
4801 b"000102030405+1401",
4802 b"500101000002+0003",
4804 with self.assertRaises(DecodeError):
4805 UTCTime(data, ctx={"bered": True})
4807 @given(integers(min_value=0, max_value=49))
4808 def test_pre50(self, year):
4810 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4814 @given(integers(min_value=50, max_value=99))
4815 def test_post50(self, year):
4817 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4823 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4824 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4826 binary(min_size=1, max_size=1),
4828 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4829 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4832 def test_junk(self, part0, part1, part2):
4833 junk = part0 + part1 + part2
4834 assume(not (set(junk) <= set(digits.encode("ascii"))))
4835 with self.assertRaises(DecodeError):
4837 UTCTime.tag_default +
4838 len_encode(len(junk)) +
4844 def tlv_value_strategy(draw):
4845 tag_num = draw(integers(min_value=1))
4846 data = draw(binary())
4847 return b"".join((tag_encode(tag_num), len_encode(len(data)), data))
4851 def any_values_strategy(draw, do_expl=False):
4852 value = draw(one_of(none(), tlv_value_strategy()))
4855 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4856 optional = draw(one_of(none(), booleans()))
4858 draw(integers(min_value=0)),
4859 draw(integers(min_value=0)),
4860 draw(integers(min_value=0)),
4862 return (value, expl, optional, _decoded)
4865 class AnyInherited(Any):
4869 class TestAny(CommonMixin, TestCase):
4872 def test_invalid_value_type(self):
4873 with self.assertRaises(InvalidValueType) as err:
4878 def test_optional(self, optional):
4879 obj = Any(optional=optional)
4880 self.assertEqual(obj.optional, optional)
4882 @given(tlv_value_strategy())
4883 def test_ready(self, value):
4885 self.assertFalse(obj.ready)
4888 pprint(obj, big_blobs=True, with_decode_path=True)
4889 with self.assertRaises(ObjNotReady) as err:
4893 self.assertTrue(obj.ready)
4896 pprint(obj, big_blobs=True, with_decode_path=True)
4899 def test_basic(self, value):
4900 integer_encoded = Integer(value).encode()
4902 Any(integer_encoded),
4903 Any(Integer(value)),
4904 Any(Any(Integer(value))),
4906 self.assertSequenceEqual(bytes(obj), integer_encoded)
4908 obj.decode(obj.encode())[0].vlen,
4909 len(integer_encoded),
4913 pprint(obj, big_blobs=True, with_decode_path=True)
4914 self.assertSequenceEqual(obj.encode(), integer_encoded)
4916 @given(tlv_value_strategy(), tlv_value_strategy())
4917 def test_comparison(self, value1, value2):
4918 for klass in (Any, AnyInherited):
4919 obj1 = klass(value1)
4920 obj2 = klass(value2)
4921 self.assertEqual(obj1 == obj2, value1 == value2)
4922 self.assertEqual(obj1 != obj2, value1 != value2)
4923 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4925 @given(data_strategy())
4926 def test_call(self, d):
4927 for klass in (Any, AnyInherited):
4933 ) = d.draw(any_values_strategy())
4934 obj_initial = klass(
4937 optional_initial or False,
4945 ) = d.draw(any_values_strategy(do_expl=True))
4946 obj = obj_initial(value, expl, optional)
4948 value_expected = None if value is None else value
4949 self.assertEqual(obj, value_expected)
4950 self.assertEqual(obj.expl_tag, expl or expl_initial)
4951 if obj.default is None:
4952 optional = optional_initial if optional is None else optional
4953 optional = False if optional is None else optional
4954 self.assertEqual(obj.optional, optional)
4956 def test_simultaneous_impl_expl(self):
4957 # override it, as Any does not have implicit tag
4960 def test_decoded(self):
4961 # override it, as Any does not have implicit tag
4964 @given(any_values_strategy())
4965 def test_copy(self, values):
4966 for klass in (Any, AnyInherited):
4967 obj = klass(*values)
4968 for copy_func in copy_funcs:
4969 obj_copied = copy_func(obj)
4970 self.assert_copied_basic_fields(obj, obj_copied)
4971 self.assertEqual(obj._value, obj_copied._value)
4973 @given(binary().map(OctetString))
4974 def test_stripped(self, value):
4976 with self.assertRaises(NotEnoughData):
4977 obj.decode(obj.encode()[:-1])
4980 tlv_value_strategy(),
4981 integers(min_value=1).map(tag_ctxc),
4983 def test_stripped_expl(self, value, tag_expl):
4984 obj = Any(value, expl=tag_expl)
4985 with self.assertRaises(NotEnoughData):
4986 obj.decode(obj.encode()[:-1])
4989 integers(min_value=31),
4990 integers(min_value=0),
4993 def test_bad_tag(self, tag, offset, decode_path):
4994 with self.assertRaises(DecodeError) as err:
4996 tag_encode(tag)[:-1],
4998 decode_path=decode_path,
5001 self.assertEqual(err.exception.offset, offset)
5002 self.assertEqual(err.exception.decode_path, decode_path)
5005 integers(min_value=128),
5006 integers(min_value=0),
5009 def test_bad_len(self, l, offset, decode_path):
5010 with self.assertRaises(DecodeError) as err:
5012 Any.tag_default + len_encode(l)[:-1],
5014 decode_path=decode_path,
5017 self.assertEqual(err.exception.offset, offset)
5018 self.assertEqual(err.exception.decode_path, decode_path)
5020 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5022 any_values_strategy(),
5023 integers().map(lambda x: Integer(x).encode()),
5024 integers(min_value=1).map(tag_ctxc),
5025 integers(min_value=0),
5029 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
5030 for klass in (Any, AnyInherited):
5031 _, _, optional, _decoded = values
5032 obj = klass(value=value, optional=optional, _decoded=_decoded)
5035 pprint(obj, big_blobs=True, with_decode_path=True)
5036 self.assertFalse(obj.expled)
5037 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5038 self.assertEqual(obj.tag_order, (tag_class, tag_num))
5039 obj_encoded = obj.encode()
5040 obj_expled = obj(value, expl=tag_expl)
5041 self.assertTrue(obj_expled.expled)
5042 tag_class, _, tag_num = tag_decode(tag_expl)
5043 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5045 list(obj_expled.pps())
5046 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5047 obj_expled_encoded = obj_expled.encode()
5048 ctx_copied = deepcopy(ctx_dummy)
5049 obj_decoded, tail = obj_expled.decode(
5050 obj_expled_encoded + tail_junk,
5054 self.assertDictEqual(ctx_copied, ctx_dummy)
5056 list(obj_decoded.pps())
5057 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5058 self.assertEqual(tail, tail_junk)
5059 self.assertEqual(obj_decoded, obj_expled)
5060 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
5061 self.assertEqual(bytes(obj_decoded), bytes(obj))
5062 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5063 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5064 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5066 obj_decoded.expl_llen,
5067 len(len_encode(len(obj_encoded))),
5069 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5070 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5073 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5075 self.assertEqual(obj_decoded.expl_offset, offset)
5076 self.assertEqual(obj_decoded.tlen, 0)
5077 self.assertEqual(obj_decoded.llen, 0)
5078 self.assertEqual(obj_decoded.vlen, len(value))
5079 assert_exceeding_data(
5081 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5085 evgens = list(obj_expled.decode_evgen(
5086 obj_expled_encoded + tail_junk,
5088 decode_path=decode_path,
5091 self.assertEqual(len(evgens), 1)
5092 _decode_path, obj, tail = evgens[0]
5093 self.assertSequenceEqual(tail, tail_junk)
5094 self.assertEqual(_decode_path, decode_path)
5095 self.assertEqual(obj.expl_offset, offset)
5100 integers(min_value=1).map(tag_ctxc),
5101 integers(min_value=0, max_value=3),
5102 integers(min_value=0),
5106 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
5107 chunk = Boolean(False, expl=expl).encode()
5109 OctetString.tag_default +
5111 b"".join([chunk] * chunks) +
5114 with self.assertRaises(LenIndefForm):
5118 decode_path=decode_path,
5120 obj, tail = Any().decode(
5123 decode_path=decode_path,
5124 ctx={"bered": True},
5126 self.assertSequenceEqual(tail, junk)
5127 self.assertEqual(obj.offset, offset)
5128 self.assertEqual(obj.tlvlen, len(encoded))
5129 self.assertTrue(obj.lenindef)
5130 self.assertFalse(obj.ber_encoded)
5131 self.assertTrue(obj.bered)
5133 self.assertTrue(obj.lenindef)
5134 self.assertFalse(obj.ber_encoded)
5135 self.assertTrue(obj.bered)
5138 pprint(obj, big_blobs=True, with_decode_path=True)
5139 with self.assertRaises(NotEnoughData) as err:
5143 decode_path=decode_path,
5144 ctx={"bered": True},
5146 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
5147 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
5149 class SeqOf(SequenceOf):
5150 schema = Boolean(expl=expl)
5152 class Seq(Sequence):
5154 ("type", ObjectIdentifier(defines=((("value",), {
5155 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
5160 ("type", ObjectIdentifier("1.2.3")),
5161 ("value", Any(encoded)),
5163 seq_encoded = seq.encode()
5164 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5165 self.assertIsNotNone(seq_decoded["value"].defined)
5167 list(seq_decoded.pps())
5168 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5169 self.assertTrue(seq_decoded.bered)
5170 self.assertFalse(seq_decoded["type"].bered)
5171 self.assertTrue(seq_decoded["value"].bered)
5173 chunk = chunk[:-1] + b"\x01"
5174 chunks = b"".join([chunk] * (chunks + 1))
5175 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
5177 ("type", ObjectIdentifier("1.2.3")),
5178 ("value", Any(encoded)),
5180 seq_encoded = seq.encode()
5181 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5182 self.assertIsNotNone(seq_decoded["value"].defined)
5184 list(seq_decoded.pps())
5185 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5186 self.assertTrue(seq_decoded.bered)
5187 self.assertFalse(seq_decoded["type"].bered)
5188 self.assertTrue(seq_decoded["value"].bered)
5192 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
5194 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
5195 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
5197 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
5198 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
5200 min_size=len(names),
5201 max_size=len(names),
5204 (name, Integer(**tag_kwargs))
5205 for name, tag_kwargs in zip(names, tags)
5208 if value_required or draw(booleans()):
5209 value = draw(tuples(
5210 sampled_from([name for name, _ in schema]),
5211 integers().map(Integer),
5215 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5216 default = draw(one_of(
5218 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5220 optional = draw(one_of(none(), booleans()))
5222 draw(integers(min_value=0)),
5223 draw(integers(min_value=0)),
5224 draw(integers(min_value=0)),
5226 return (schema, value, expl, default, optional, _decoded)
5229 class ChoiceInherited(Choice):
5233 class TestChoice(CommonMixin, TestCase):
5235 schema = (("whatever", Boolean()),)
5238 def test_schema_required(self):
5239 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5242 def test_impl_forbidden(self):
5243 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
5244 Choice(impl=b"whatever")
5246 def test_invalid_value_type(self):
5247 with self.assertRaises(InvalidValueType) as err:
5248 self.base_klass(123)
5250 with self.assertRaises(ObjUnknown) as err:
5251 self.base_klass(("whenever", Boolean(False)))
5253 with self.assertRaises(InvalidValueType) as err:
5254 self.base_klass(("whatever", Integer(123)))
5258 def test_optional(self, optional):
5259 obj = self.base_klass(
5260 default=self.base_klass(("whatever", Boolean(False))),
5263 self.assertTrue(obj.optional)
5266 def test_ready(self, value):
5267 obj = self.base_klass()
5268 self.assertFalse(obj.ready)
5271 pprint(obj, big_blobs=True, with_decode_path=True)
5272 self.assertIsNone(obj["whatever"])
5273 with self.assertRaises(ObjNotReady) as err:
5276 obj["whatever"] = Boolean()
5277 self.assertFalse(obj.ready)
5280 pprint(obj, big_blobs=True, with_decode_path=True)
5281 obj["whatever"] = Boolean(value)
5282 self.assertTrue(obj.ready)
5285 pprint(obj, big_blobs=True, with_decode_path=True)
5287 @given(booleans(), booleans())
5288 def test_comparison(self, value1, value2):
5289 class WahlInherited(self.base_klass):
5291 for klass in (self.base_klass, WahlInherited):
5292 obj1 = klass(("whatever", Boolean(value1)))
5293 obj2 = klass(("whatever", Boolean(value2)))
5294 self.assertEqual(obj1 == obj2, value1 == value2)
5295 self.assertEqual(obj1 != obj2, value1 != value2)
5296 self.assertEqual(obj1 == obj2._value, value1 == value2)
5297 self.assertFalse(obj1 == obj2._value[1])
5299 @given(data_strategy())
5300 def test_call(self, d):
5301 for klass in (Choice, ChoiceInherited):
5309 ) = d.draw(choice_values_strategy())
5312 schema = schema_initial
5314 value=value_initial,
5316 default=default_initial,
5317 optional=optional_initial or False,
5318 _decoded=_decoded_initial,
5327 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5328 obj = obj_initial(value, expl, default, optional)
5330 value_expected = default if value is None else value
5332 default_initial if value_expected is None
5335 self.assertEqual(obj.choice, value_expected[0])
5336 self.assertEqual(obj.value, int(value_expected[1]))
5337 self.assertEqual(obj.expl_tag, expl or expl_initial)
5338 default_expect = default_initial if default is None else default
5339 if default_expect is not None:
5340 self.assertEqual(obj.default.choice, default_expect[0])
5341 self.assertEqual(obj.default.value, int(default_expect[1]))
5342 if obj.default is None:
5343 optional = optional_initial if optional is None else optional
5344 optional = False if optional is None else optional
5347 self.assertEqual(obj.optional, optional)
5348 self.assertEqual(obj.specs, obj_initial.specs)
5350 def test_simultaneous_impl_expl(self):
5351 # override it, as Any does not have implicit tag
5354 def test_decoded(self):
5355 # override it, as Any does not have implicit tag
5358 @given(choice_values_strategy())
5359 def test_copy(self, values):
5360 _schema, value, expl, default, optional, _decoded = values
5362 class Wahl(self.base_klass):
5364 register_class(Wahl)
5369 optional=optional or False,
5372 for copy_func in copy_funcs:
5373 obj_copied = copy_func(obj)
5374 self.assertIsNone(obj.tag)
5375 self.assertIsNone(obj_copied.tag)
5376 # hack for assert_copied_basic_fields
5377 obj.tag = "whatever"
5378 obj_copied.tag = "whatever"
5379 self.assert_copied_basic_fields(obj, obj_copied)
5381 self.assertEqual(obj._value, obj_copied._value)
5382 self.assertEqual(obj.specs, obj_copied.specs)
5385 def test_stripped(self, value):
5386 obj = self.base_klass(("whatever", Boolean(value)))
5387 with self.assertRaises(NotEnoughData):
5388 obj.decode(obj.encode()[:-1])
5392 integers(min_value=1).map(tag_ctxc),
5394 def test_stripped_expl(self, value, tag_expl):
5395 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5396 with self.assertRaises(NotEnoughData):
5397 obj.decode(obj.encode()[:-1])
5399 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5400 @given(data_strategy())
5401 def test_symmetric(self, d):
5402 _schema, value, _, default, optional, _decoded = d.draw(
5403 choice_values_strategy(value_required=True)
5405 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5406 offset = d.draw(integers(min_value=0))
5407 tail_junk = d.draw(binary(max_size=5))
5408 decode_path = d.draw(decode_path_strat)
5410 class Wahl(self.base_klass):
5420 pprint(obj, big_blobs=True, with_decode_path=True)
5421 self.assertFalse(obj.expled)
5422 self.assertEqual(obj.tag_order, obj.value.tag_order)
5423 obj_encoded = obj.encode()
5424 obj_expled = obj(value, expl=tag_expl)
5425 self.assertTrue(obj_expled.expled)
5426 tag_class, _, tag_num = tag_decode(tag_expl)
5427 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5429 list(obj_expled.pps())
5430 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5431 obj_expled_encoded = obj_expled.encode()
5432 ctx_copied = deepcopy(ctx_dummy)
5433 obj_decoded, tail = obj_expled.decode(
5434 obj_expled_encoded + tail_junk,
5438 self.assertDictEqual(ctx_copied, ctx_dummy)
5440 list(obj_decoded.pps())
5441 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5442 self.assertEqual(tail, tail_junk)
5443 self.assertEqual(obj_decoded, obj_expled)
5444 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5445 self.assertEqual(obj_decoded.value, obj_expled.value)
5446 self.assertEqual(obj_decoded.choice, obj.choice)
5447 self.assertEqual(obj_decoded.value, obj.value)
5448 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5449 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5450 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5452 obj_decoded.expl_llen,
5453 len(len_encode(len(obj_encoded))),
5455 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5456 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5459 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5461 self.assertEqual(obj_decoded.expl_offset, offset)
5462 self.assertSequenceEqual(
5464 obj_decoded.value.fulloffset - offset:
5465 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5469 assert_exceeding_data(
5471 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5475 evgens = list(obj_expled.decode_evgen(
5476 obj_expled_encoded + tail_junk,
5478 decode_path=decode_path,
5481 self.assertEqual(len(evgens), 2)
5482 _decode_path, obj, tail = evgens[0]
5483 self.assertEqual(_decode_path, decode_path + (obj_decoded.choice,))
5484 _decode_path, obj, tail = evgens[1]
5485 self.assertSequenceEqual(tail, tail_junk)
5486 self.assertEqual(_decode_path, decode_path)
5487 self.assertEqual(obj.expl_offset, offset)
5492 def test_set_get(self, value):
5495 ("erste", Boolean()),
5496 ("zweite", Integer()),
5499 with self.assertRaises(ObjUnknown) as err:
5500 obj["whatever"] = "whenever"
5501 with self.assertRaises(InvalidValueType) as err:
5502 obj["zweite"] = Boolean(False)
5503 obj["zweite"] = Integer(value)
5505 with self.assertRaises(ObjUnknown) as err:
5508 self.assertIsNone(obj["erste"])
5509 self.assertEqual(obj["zweite"], Integer(value))
5511 def test_tag_mismatch(self):
5514 ("erste", Boolean()),
5516 int_encoded = Integer(123).encode()
5517 bool_encoded = Boolean(False).encode()
5519 obj.decode(bool_encoded)
5520 with self.assertRaises(TagMismatch):
5521 obj.decode(int_encoded)
5523 def test_tag_mismatch_underlying(self):
5524 class SeqOfBoolean(SequenceOf):
5527 class SeqOfInteger(SequenceOf):
5532 ("erste", SeqOfBoolean()),
5535 int_encoded = SeqOfInteger((Integer(123),)).encode()
5536 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5538 obj.decode(bool_encoded)
5539 with self.assertRaises(TagMismatch) as err:
5540 obj.decode(int_encoded)
5541 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5545 def seq_values_strategy(draw, seq_klass, do_expl=False):
5547 if draw(booleans()):
5549 value._value = draw(dictionaries(
5552 booleans().map(Boolean),
5553 integers().map(Integer),
5557 if draw(booleans()):
5558 schema = list(draw(dictionaries(
5561 booleans().map(Boolean),
5562 integers().map(Integer),
5568 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5570 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5572 if draw(booleans()):
5573 default = seq_klass()
5574 default._value = draw(dictionaries(
5577 booleans().map(Boolean),
5578 integers().map(Integer),
5581 optional = draw(one_of(none(), booleans()))
5583 draw(integers(min_value=0)),
5584 draw(integers(min_value=0)),
5585 draw(integers(min_value=0)),
5587 return (value, schema, impl, expl, default, optional, _decoded)
5591 def sequence_strategy(draw, seq_klass):
5592 inputs = draw(lists(
5594 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5595 tuples(just(Integer), integers(), one_of(none(), integers())),
5600 integers(min_value=1),
5601 min_size=len(inputs),
5602 max_size=len(inputs),
5605 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5606 for tag, expled in zip(tags, draw(lists(
5608 min_size=len(inputs),
5609 max_size=len(inputs),
5613 for i, optional in enumerate(draw(lists(
5614 sampled_from(("required", "optional", "empty")),
5615 min_size=len(inputs),
5616 max_size=len(inputs),
5618 if optional in ("optional", "empty"):
5619 inits[i]["optional"] = True
5620 if optional == "empty":
5622 empties = set(empties)
5623 names = list(draw(sets(
5625 min_size=len(inputs),
5626 max_size=len(inputs),
5629 for i, (klass, value, default) in enumerate(inputs):
5630 schema.append((names[i], klass(default=default, **inits[i])))
5631 seq_name = draw(text_letters())
5632 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5635 for i, (klass, value, default) in enumerate(inputs):
5642 "default_value": None if spec.default is None else default,
5646 expect["optional"] = True
5648 expect["presented"] = True
5649 expect["value"] = value
5651 expect["optional"] = True
5652 if default is not None and default == value:
5653 expect["presented"] = False
5654 seq[name] = klass(value)
5655 expects.append(expect)
5660 def sequences_strategy(draw, seq_klass):
5661 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5663 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5664 for tag, expled in zip(tags, draw(lists(
5671 i for i, is_default in enumerate(draw(lists(
5677 names = list(draw(sets(
5682 seq_expectses = draw(lists(
5683 sequence_strategy(seq_klass=seq_klass),
5687 seqs = [seq for seq, _ in seq_expectses]
5689 for i, (name, seq) in enumerate(zip(names, seqs)):
5692 seq(default=(seq if i in defaulted else None), **inits[i]),
5694 seq_name = draw(text_letters())
5695 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5698 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5701 "expects": expects_inner,
5704 seq_outer[name] = seq_inner
5705 if seq_outer.specs[name].default is None:
5706 expect["presented"] = True
5707 expect_outers.append(expect)
5708 return seq_outer, expect_outers
5711 class SeqMixing(object):
5712 def test_invalid_value_type(self):
5713 with self.assertRaises(InvalidValueType) as err:
5714 self.base_klass(123)
5717 def test_invalid_value_type_set(self):
5718 class Seq(self.base_klass):
5719 schema = (("whatever", Boolean()),)
5721 with self.assertRaises(InvalidValueType) as err:
5722 seq["whatever"] = Integer(123)
5726 def test_optional(self, optional):
5727 obj = self.base_klass(default=self.base_klass(), optional=optional)
5728 self.assertTrue(obj.optional)
5730 @given(data_strategy())
5731 def test_ready(self, d):
5733 str(i): v for i, v in enumerate(d.draw(lists(
5740 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5747 for name in d.draw(permutations(
5748 list(ready.keys()) + list(non_ready.keys()),
5750 schema_input.append((name, Boolean()))
5752 class Seq(self.base_klass):
5753 schema = tuple(schema_input)
5755 for name in ready.keys():
5757 seq[name] = Boolean()
5758 self.assertFalse(seq.ready)
5761 pprint(seq, big_blobs=True, with_decode_path=True)
5762 for name, value in ready.items():
5763 seq[name] = Boolean(value)
5764 self.assertFalse(seq.ready)
5767 pprint(seq, big_blobs=True, with_decode_path=True)
5768 with self.assertRaises(ObjNotReady) as err:
5771 for name, value in non_ready.items():
5772 seq[name] = Boolean(value)
5773 self.assertTrue(seq.ready)
5776 pprint(seq, big_blobs=True, with_decode_path=True)
5778 @given(data_strategy())
5779 def test_call(self, d):
5780 class SeqInherited(self.base_klass):
5782 for klass in (self.base_klass, SeqInherited):
5791 ) = d.draw(seq_values_strategy(seq_klass=klass))
5792 obj_initial = klass(
5798 optional_initial or False,
5809 ) = d.draw(seq_values_strategy(
5811 do_expl=impl_initial is None,
5813 obj = obj_initial(value, impl, expl, default, optional)
5814 value_expected = default if value is None else value
5816 default_initial if value_expected is None
5819 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5820 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5821 self.assertEqual(obj.expl_tag, expl or expl_initial)
5823 {} if obj.default is None else obj.default._value,
5824 getattr(default_initial if default is None else default, "_value", {}),
5826 if obj.default is None:
5827 optional = optional_initial if optional is None else optional
5828 optional = False if optional is None else optional
5831 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5832 self.assertEqual(obj.optional, optional)
5834 @given(data_strategy())
5835 def test_copy(self, d):
5836 class SeqInherited(self.base_klass):
5838 register_class(SeqInherited)
5839 for klass in (self.base_klass, SeqInherited):
5840 values = d.draw(seq_values_strategy(seq_klass=klass))
5841 obj = klass(*values)
5842 for copy_func in copy_funcs:
5843 obj_copied = copy_func(obj)
5844 self.assert_copied_basic_fields(obj, obj_copied)
5845 self.assertEqual(obj.specs, obj_copied.specs)
5846 self.assertEqual(obj._value, obj_copied._value)
5848 @given(data_strategy())
5849 def test_stripped(self, d):
5850 value = d.draw(integers())
5851 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5853 class Seq(self.base_klass):
5855 schema = (("whatever", Integer()),)
5857 seq["whatever"] = Integer(value)
5858 with self.assertRaises(NotEnoughData):
5859 seq.decode(seq.encode()[:-1])
5861 @given(data_strategy())
5862 def test_stripped_expl(self, d):
5863 value = d.draw(integers())
5864 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5866 class Seq(self.base_klass):
5868 schema = (("whatever", Integer()),)
5870 seq["whatever"] = Integer(value)
5871 with self.assertRaises(NotEnoughData):
5872 seq.decode(seq.encode()[:-1])
5874 @given(integers(min_value=3), binary(min_size=2))
5875 def test_non_tag_mismatch_raised(self, junk_tag_num, junk):
5876 junk = tag_encode(junk_tag_num) + junk
5878 _, _, len_encoded = tag_strip(memoryview(junk))
5879 len_decode(len_encoded)
5885 class Seq(self.base_klass):
5887 ("whatever", Integer()),
5889 ("whenever", Integer()),
5892 seq["whatever"] = Integer(123)
5893 seq["junk"] = Any(junk)
5894 seq["whenever"] = Integer(123)
5895 with self.assertRaises(DecodeError):
5896 seq.decode(seq.encode())
5899 integers(min_value=31),
5900 integers(min_value=0),
5903 def test_bad_tag(self, tag, offset, decode_path):
5904 with self.assertRaises(DecodeError) as err:
5905 self.base_klass().decode(
5906 tag_encode(tag)[:-1],
5908 decode_path=decode_path,
5911 self.assertEqual(err.exception.offset, offset)
5912 self.assertEqual(err.exception.decode_path, decode_path)
5915 integers(min_value=128),
5916 integers(min_value=0),
5919 def test_bad_len(self, l, offset, decode_path):
5920 with self.assertRaises(DecodeError) as err:
5921 self.base_klass().decode(
5922 self.base_klass.tag_default + len_encode(l)[:-1],
5924 decode_path=decode_path,
5927 self.assertEqual(err.exception.offset, offset)
5928 self.assertEqual(err.exception.decode_path, decode_path)
5930 def _assert_expects(self, seq, expects):
5931 for expect in expects:
5933 seq.specs[expect["name"]].optional,
5936 if expect["default_value"] is not None:
5938 seq.specs[expect["name"]].default,
5939 expect["default_value"],
5941 if expect["presented"]:
5942 self.assertIn(expect["name"], seq)
5943 self.assertEqual(seq[expect["name"]], expect["value"])
5945 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5946 @given(data_strategy())
5947 def test_symmetric(self, d):
5948 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5949 tail_junk = d.draw(binary(max_size=5))
5950 decode_path = d.draw(decode_path_strat)
5951 self.assertTrue(seq.ready)
5952 self.assertFalse(seq.decoded)
5953 self._assert_expects(seq, expects)
5956 pprint(seq, big_blobs=True, with_decode_path=True)
5957 self.assertTrue(seq.ready)
5958 seq_encoded = seq.encode()
5959 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5960 self.assertFalse(seq_decoded.lenindef)
5961 self.assertFalse(seq_decoded.ber_encoded)
5962 self.assertFalse(seq_decoded.bered)
5964 t, _, lv = tag_strip(seq_encoded)
5965 _, _, v = len_decode(lv)
5966 seq_encoded_lenindef = t + LENINDEF + v + EOC
5967 with self.assertRaises(DecodeError):
5968 seq.decode(seq_encoded_lenindef)
5969 ctx_copied = deepcopy(ctx_dummy)
5970 ctx_copied["bered"] = True
5971 seq_decoded_lenindef, tail_lenindef = seq.decode(
5972 seq_encoded_lenindef + tail_junk,
5975 del ctx_copied["bered"]
5976 self.assertDictEqual(ctx_copied, ctx_dummy)
5977 self.assertTrue(seq_decoded_lenindef.lenindef)
5978 self.assertTrue(seq_decoded_lenindef.bered)
5979 seq_decoded_lenindef = copy(seq_decoded_lenindef)
5980 self.assertTrue(seq_decoded_lenindef.lenindef)
5981 self.assertTrue(seq_decoded_lenindef.bered)
5982 with self.assertRaises(DecodeError):
5983 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5984 with self.assertRaises(DecodeError):
5985 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5986 repr(seq_decoded_lenindef)
5987 list(seq_decoded_lenindef.pps())
5988 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5989 self.assertTrue(seq_decoded_lenindef.ready)
5991 for decoded, decoded_tail, encoded in (
5992 (seq_decoded, tail, seq_encoded),
5993 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5995 self.assertEqual(decoded_tail, tail_junk)
5996 self._assert_expects(decoded, expects)
5997 self.assertEqual(seq, decoded)
5998 self.assertEqual(decoded.encode(), seq_encoded)
5999 self.assertEqual(decoded.tlvlen, len(encoded))
6000 for expect in expects:
6001 if not expect["presented"]:
6002 self.assertNotIn(expect["name"], decoded)
6004 self.assertIn(expect["name"], decoded)
6005 obj = decoded[expect["name"]]
6006 self.assertTrue(obj.decoded)
6007 offset = obj.expl_offset if obj.expled else obj.offset
6008 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6009 self.assertSequenceEqual(
6010 seq_encoded[offset:offset + tlvlen],
6014 evgens = list(seq.decode_evgen(
6015 encoded + decoded_tail,
6016 decode_path=decode_path,
6017 ctx={"bered": True},
6019 self.assertEqual(len(evgens), len(list(decoded._values_for_encoding())) + 1)
6020 for _decode_path, obj, _ in evgens[:-1]:
6021 self.assertEqual(_decode_path[:-1], decode_path)
6024 _decode_path, obj, tail = evgens[-1]
6025 self.assertEqual(_decode_path, decode_path)
6029 assert_exceeding_data(
6031 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
6035 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6036 @given(data_strategy())
6037 def test_symmetric_with_seq(self, d):
6038 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
6039 self.assertTrue(seq.ready)
6040 seq_encoded = seq.encode()
6041 seq_decoded, tail = seq.decode(seq_encoded)
6042 self.assertEqual(tail, b"")
6043 self.assertTrue(seq.ready)
6044 self.assertEqual(seq, seq_decoded)
6045 self.assertEqual(seq_decoded.encode(), seq_encoded)
6046 for expect_outer in expect_outers:
6047 if not expect_outer["presented"]:
6048 self.assertNotIn(expect_outer["name"], seq_decoded)
6050 self.assertIn(expect_outer["name"], seq_decoded)
6051 obj = seq_decoded[expect_outer["name"]]
6052 self.assertTrue(obj.decoded)
6053 offset = obj.expl_offset if obj.expled else obj.offset
6054 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6055 self.assertSequenceEqual(
6056 seq_encoded[offset:offset + tlvlen],
6059 self._assert_expects(obj, expect_outer["expects"])
6061 @given(data_strategy())
6062 def test_default_disappears(self, d):
6063 _schema = list(d.draw(dictionaries(
6065 sets(integers(), min_size=2, max_size=2),
6069 class Seq(self.base_klass):
6071 (n, Integer(default=d))
6072 for n, (_, d) in _schema
6075 for name, (value, _) in _schema:
6076 seq[name] = Integer(value)
6077 self.assertEqual(len(seq._value), len(_schema))
6078 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
6079 self.assertGreater(len(seq.encode()), len(empty_seq))
6080 for name, (_, default) in _schema:
6081 seq[name] = Integer(default)
6082 self.assertEqual(len(seq._value), 0)
6083 self.assertSequenceEqual(seq.encode(), empty_seq)
6085 @given(data_strategy())
6086 def test_encoded_default_not_accepted(self, d):
6087 _schema = list(d.draw(dictionaries(
6092 tags = [tag_encode(tag) for tag in d.draw(sets(
6093 integers(min_value=1),
6094 min_size=len(_schema),
6095 max_size=len(_schema),
6098 class SeqWithoutDefault(self.base_klass):
6100 (n, Integer(impl=t))
6101 for (n, _), t in zip(_schema, tags)
6103 seq_without_default = SeqWithoutDefault()
6104 for name, value in _schema:
6105 seq_without_default[name] = Integer(value)
6106 seq_encoded = seq_without_default.encode()
6108 class SeqWithDefault(self.base_klass):
6110 (n, Integer(default=v, impl=t))
6111 for (n, v), t in zip(_schema, tags)
6113 seq_with_default = SeqWithDefault()
6114 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6115 seq_with_default.decode(seq_encoded)
6116 for ctx in ({"bered": True}, {"allow_default_values": True}):
6117 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
6118 self.assertTrue(seq_decoded.ber_encoded)
6119 self.assertTrue(seq_decoded.bered)
6120 seq_decoded = copy(seq_decoded)
6121 self.assertTrue(seq_decoded.ber_encoded)
6122 self.assertTrue(seq_decoded.bered)
6123 for name, value in _schema:
6124 self.assertEqual(seq_decoded[name], seq_with_default[name])
6125 self.assertEqual(seq_decoded[name], value)
6127 @given(data_strategy())
6128 def test_missing_from_spec(self, d):
6129 names = list(d.draw(sets(text_letters(), min_size=2)))
6130 tags = [tag_encode(tag) for tag in d.draw(sets(
6131 integers(min_value=1),
6132 min_size=len(names),
6133 max_size=len(names),
6135 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
6137 class SeqFull(self.base_klass):
6138 schema = [(n, Integer(impl=t)) for n, t in names_tags]
6139 seq_full = SeqFull()
6140 for i, name in enumerate(names):
6141 seq_full[name] = Integer(i)
6142 seq_encoded = seq_full.encode()
6143 altered = names_tags[:-2] + names_tags[-1:]
6145 class SeqMissing(self.base_klass):
6146 schema = [(n, Integer(impl=t)) for n, t in altered]
6147 seq_missing = SeqMissing()
6148 with self.assertRaises(TagMismatch):
6149 seq_missing.decode(seq_encoded)
6151 def test_bered(self):
6152 class Seq(self.base_klass):
6153 schema = (("underlying", Boolean()),)
6154 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
6155 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6156 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6157 self.assertFalse(decoded.ber_encoded)
6158 self.assertFalse(decoded.lenindef)
6159 self.assertTrue(decoded.bered)
6160 decoded = copy(decoded)
6161 self.assertFalse(decoded.ber_encoded)
6162 self.assertFalse(decoded.lenindef)
6163 self.assertTrue(decoded.bered)
6165 class Seq(self.base_klass):
6166 schema = (("underlying", OctetString()),)
6168 tag_encode(form=TagFormConstructed, num=4) +
6170 OctetString(b"whatever").encode() +
6173 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6174 with self.assertRaises(DecodeError):
6175 Seq().decode(encoded)
6176 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6177 self.assertFalse(decoded.ber_encoded)
6178 self.assertFalse(decoded.lenindef)
6179 self.assertTrue(decoded.bered)
6180 decoded = copy(decoded)
6181 self.assertFalse(decoded.ber_encoded)
6182 self.assertFalse(decoded.lenindef)
6183 self.assertTrue(decoded.bered)
6186 class TestSequence(SeqMixing, CommonMixin, TestCase):
6187 base_klass = Sequence
6193 def test_remaining(self, value, junk):
6194 class Seq(Sequence):
6196 ("whatever", Integer()),
6198 int_encoded = Integer(value).encode()
6200 Sequence.tag_default,
6201 len_encode(len(int_encoded + junk)),
6204 with assertRaisesRegex(self, DecodeError, "remaining"):
6205 Seq().decode(junked)
6207 @given(sets(text_letters(), min_size=2))
6208 def test_obj_unknown(self, names):
6209 missing = names.pop()
6211 class Seq(Sequence):
6212 schema = [(n, Boolean()) for n in names]
6214 with self.assertRaises(ObjUnknown) as err:
6217 with self.assertRaises(ObjUnknown) as err:
6218 seq[missing] = Boolean()
6221 def test_x690_vector(self):
6222 class Seq(Sequence):
6224 ("name", IA5String()),
6227 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
6228 self.assertEqual(seq["name"], "Smith")
6229 self.assertEqual(seq["ok"], True)
6232 class TestSet(SeqMixing, CommonMixin, TestCase):
6235 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6236 @given(data_strategy())
6237 def test_sorted(self, d):
6238 class DummySeq(Sequence):
6239 schema = (("null", Null()),)
6241 tag_nums = d.draw(sets(integers(min_value=1), min_size=1, max_size=50))
6242 _, _, dummy_seq_tag_num = tag_decode(DummySeq.tag_default)
6243 assume(any(i > dummy_seq_tag_num for i in tag_nums))
6244 tag_nums -= set([dummy_seq_tag_num])
6245 _schema = [(str(i), OctetString(impl=tag_encode(i))) for i in tag_nums]
6246 _schema.append(("seq", DummySeq()))
6249 schema = d.draw(permutations(_schema))
6251 for name, _ in _schema:
6253 seq[name] = OctetString(name.encode("ascii"))
6254 seq["seq"] = DummySeq((("null", Null()),))
6256 seq_encoded = seq.encode()
6257 seq_decoded, _ = seq.decode(seq_encoded)
6258 seq_encoded_expected = []
6259 for tag_num in sorted(tag_nums | set([dummy_seq_tag_num])):
6260 if tag_num == dummy_seq_tag_num:
6261 seq_encoded_expected.append(seq["seq"].encode())
6263 seq_encoded_expected.append(seq[str(tag_num)].encode())
6264 self.assertSequenceEqual(
6265 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6266 b"".join(seq_encoded_expected),
6269 encoded = b"".join(seq[str(i)].encode() for i in tag_nums)
6270 encoded += seq["seq"].encode()
6271 seq_encoded = b"".join((
6273 len_encode(len(encoded)),
6276 with assertRaisesRegex(self, DecodeError, "unordered SET"):
6277 seq.decode(seq_encoded)
6278 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6279 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6280 self.assertTrue(seq_decoded.ber_encoded)
6281 self.assertTrue(seq_decoded.bered)
6282 seq_decoded = copy(seq_decoded)
6283 self.assertTrue(seq_decoded.ber_encoded)
6284 self.assertTrue(seq_decoded.bered)
6286 def test_same_value_twice(self):
6289 ("bool", Boolean()),
6293 encoded = b"".join((
6294 Integer(123).encode(),
6295 Integer(234).encode(),
6296 Boolean(True).encode(),
6298 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6299 with self.assertRaises(TagMismatch):
6300 Seq().decod(encoded, ctx={"allow_unordered_set": True})
6304 def seqof_values_strategy(draw, schema=None, do_expl=False):
6306 schema = draw(sampled_from((Boolean(), Integer())))
6307 bound_min, bound_max = sorted(draw(sets(
6308 integers(min_value=0, max_value=10),
6312 if isinstance(schema, Boolean):
6313 values_generator = booleans().map(Boolean)
6314 elif isinstance(schema, Integer):
6315 values_generator = integers().map(Integer)
6316 values_generator = lists(
6321 values = draw(one_of(none(), values_generator))
6325 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6327 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6328 default = draw(one_of(none(), values_generator))
6329 optional = draw(one_of(none(), booleans()))
6331 draw(integers(min_value=0)),
6332 draw(integers(min_value=0)),
6333 draw(integers(min_value=0)),
6338 (bound_min, bound_max),
6347 class SeqOfMixing(object):
6348 def test_invalid_value_type(self):
6349 with self.assertRaises(InvalidValueType) as err:
6350 self.base_klass(123)
6353 def test_invalid_values_type(self):
6354 class SeqOf(self.base_klass):
6356 with self.assertRaises(InvalidValueType) as err:
6357 SeqOf([Integer(123), Boolean(False), Integer(234)])
6360 def test_schema_required(self):
6361 with assertRaisesRegex(self, ValueError, "schema must be specified"):
6362 self.base_klass.__mro__[1]()
6364 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6365 def test_comparison(self, value1, value2, tag1, tag2):
6366 class SeqOf(self.base_klass):
6368 obj1 = SeqOf([Boolean(value1)])
6369 obj2 = SeqOf([Boolean(value2)])
6370 self.assertEqual(obj1 == obj2, value1 == value2)
6371 self.assertEqual(obj1 != obj2, value1 != value2)
6372 self.assertEqual(obj1 == list(obj2), value1 == value2)
6373 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6374 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6375 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6376 self.assertEqual(obj1 == obj2, tag1 == tag2)
6377 self.assertEqual(obj1 != obj2, tag1 != tag2)
6379 @given(lists(booleans()))
6380 def test_iter(self, values):
6381 class SeqOf(self.base_klass):
6383 obj = SeqOf([Boolean(value) for value in values])
6384 self.assertEqual(len(obj), len(values))
6385 for i, value in enumerate(obj):
6386 self.assertEqual(value, values[i])
6388 @given(data_strategy())
6389 def test_ready(self, d):
6390 ready = [Integer(v) for v in d.draw(lists(
6397 range(d.draw(integers(min_value=1, max_value=5)))
6400 class SeqOf(self.base_klass):
6402 values = d.draw(permutations(ready + non_ready))
6404 for value in values:
6406 self.assertFalse(seqof.ready)
6409 pprint(seqof, big_blobs=True, with_decode_path=True)
6410 with self.assertRaises(ObjNotReady) as err:
6413 for i, value in enumerate(values):
6414 self.assertEqual(seqof[i], value)
6415 if not seqof[i].ready:
6416 seqof[i] = Integer(i)
6417 self.assertTrue(seqof.ready)
6420 pprint(seqof, big_blobs=True, with_decode_path=True)
6422 def test_spec_mismatch(self):
6423 class SeqOf(self.base_klass):
6426 seqof.append(Integer(123))
6427 with self.assertRaises(ValueError):
6428 seqof.append(Boolean(False))
6429 with self.assertRaises(ValueError):
6430 seqof[0] = Boolean(False)
6432 @given(data_strategy())
6433 def test_bounds_satisfied(self, d):
6434 class SeqOf(self.base_klass):
6436 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6437 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6438 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6439 SeqOf(value=value, bounds=(bound_min, bound_max))
6441 @given(data_strategy())
6442 def test_bounds_unsatisfied(self, d):
6443 class SeqOf(self.base_klass):
6445 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6446 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6447 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
6448 with self.assertRaises(BoundsError) as err:
6449 SeqOf(value=value, bounds=(bound_min, bound_max))
6451 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6452 SeqOf(bounds=(bound_min, bound_max)).decode(
6453 SeqOf(value).encode()
6456 value = [Boolean(True)] * d.draw(integers(
6457 min_value=bound_max + 1,
6458 max_value=bound_max + 10,
6460 with self.assertRaises(BoundsError) as err:
6461 SeqOf(value=value, bounds=(bound_min, bound_max))
6463 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6464 SeqOf(bounds=(bound_min, bound_max)).decode(
6465 SeqOf(value).encode()
6469 @given(integers(min_value=1, max_value=10))
6470 def test_out_of_bounds(self, bound_max):
6471 class SeqOf(self.base_klass):
6473 bounds = (0, bound_max)
6475 for _ in range(bound_max):
6476 seqof.append(Integer(123))
6477 with self.assertRaises(BoundsError):
6478 seqof.append(Integer(123))
6480 @given(data_strategy())
6481 def test_call(self, d):
6491 ) = d.draw(seqof_values_strategy())
6493 class SeqOf(self.base_klass):
6494 schema = schema_initial
6495 obj_initial = SeqOf(
6496 value=value_initial,
6497 bounds=bounds_initial,
6500 default=default_initial,
6501 optional=optional_initial or False,
6502 _decoded=_decoded_initial,
6513 ) = d.draw(seqof_values_strategy(
6514 schema=schema_initial,
6515 do_expl=impl_initial is None,
6517 if (default is None) and (obj_initial.default is not None):
6520 (bounds is None) and
6521 (value is not None) and
6522 (bounds_initial is not None) and
6523 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6527 (bounds is None) and
6528 (default is not None) and
6529 (bounds_initial is not None) and
6530 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6542 value_expected = default if value is None else value
6544 default_initial if value_expected is None
6547 value_expected = () if value_expected is None else value_expected
6548 self.assertEqual(obj, value_expected)
6549 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6550 self.assertEqual(obj.expl_tag, expl or expl_initial)
6553 default_initial if default is None else default,
6555 if obj.default is None:
6556 optional = optional_initial if optional is None else optional
6557 optional = False if optional is None else optional
6560 self.assertEqual(obj.optional, optional)
6562 (obj._bound_min, obj._bound_max),
6563 bounds or bounds_initial or (0, float("+inf")),
6566 @given(seqof_values_strategy())
6567 def test_copy(self, values):
6568 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6570 class SeqOf(self.base_klass):
6572 register_class(SeqOf)
6579 optional=optional or False,
6582 for copy_func in copy_funcs:
6583 obj_copied = copy_func(obj)
6584 self.assert_copied_basic_fields(obj, obj_copied)
6585 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6586 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6587 self.assertEqual(obj._value, obj_copied._value)
6591 integers(min_value=1).map(tag_encode),
6593 def test_stripped(self, values, tag_impl):
6594 class SeqOf(self.base_klass):
6595 schema = OctetString()
6596 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6597 with self.assertRaises(NotEnoughData):
6598 obj.decode(obj.encode()[:-1])
6602 integers(min_value=1).map(tag_ctxc),
6604 def test_stripped_expl(self, values, tag_expl):
6605 class SeqOf(self.base_klass):
6606 schema = OctetString()
6607 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6608 with self.assertRaises(NotEnoughData):
6609 obj.decode(obj.encode()[:-1])
6612 integers(min_value=31),
6613 integers(min_value=0),
6616 def test_bad_tag(self, tag, offset, decode_path):
6617 with self.assertRaises(DecodeError) as err:
6618 self.base_klass().decode(
6619 tag_encode(tag)[:-1],
6621 decode_path=decode_path,
6624 self.assertEqual(err.exception.offset, offset)
6625 self.assertEqual(err.exception.decode_path, decode_path)
6628 integers(min_value=128),
6629 integers(min_value=0),
6632 def test_bad_len(self, l, offset, decode_path):
6633 with self.assertRaises(DecodeError) as err:
6634 self.base_klass().decode(
6635 self.base_klass.tag_default + len_encode(l)[:-1],
6637 decode_path=decode_path,
6640 self.assertEqual(err.exception.offset, offset)
6641 self.assertEqual(err.exception.decode_path, decode_path)
6643 @given(binary(min_size=1))
6644 def test_tag_mismatch(self, impl):
6645 assume(impl != self.base_klass.tag_default)
6646 with self.assertRaises(TagMismatch):
6647 self.base_klass(impl=impl).decode(self.base_klass().encode())
6649 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6651 seqof_values_strategy(schema=Integer()),
6652 lists(integers().map(Integer)),
6653 integers(min_value=1).map(tag_ctxc),
6654 integers(min_value=0),
6658 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
6659 _, _, _, _, _, default, optional, _decoded = values
6661 class SeqOf(self.base_klass):
6671 pprint(obj, big_blobs=True, with_decode_path=True)
6672 self.assertFalse(obj.expled)
6673 obj_encoded = obj.encode()
6674 obj_expled = obj(value, expl=tag_expl)
6675 self.assertTrue(obj_expled.expled)
6677 list(obj_expled.pps())
6678 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6679 obj_expled_encoded = obj_expled.encode()
6680 ctx_copied = deepcopy(ctx_dummy)
6681 obj_decoded, tail = obj_expled.decode(
6682 obj_expled_encoded + tail_junk,
6686 self.assertDictEqual(ctx_copied, ctx_dummy)
6688 list(obj_decoded.pps())
6689 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6690 self.assertEqual(tail, tail_junk)
6691 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6692 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6693 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6694 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6696 obj_decoded.expl_llen,
6697 len(len_encode(len(obj_encoded))),
6699 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
6700 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
6703 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
6705 self.assertEqual(obj_decoded.expl_offset, offset)
6706 for obj_inner in obj_decoded:
6707 self.assertIn(obj_inner, obj_decoded)
6708 self.assertSequenceEqual(
6711 obj_inner.offset - offset:
6712 obj_inner.offset + obj_inner.tlvlen - offset
6716 t, _, lv = tag_strip(obj_encoded)
6717 _, _, v = len_decode(lv)
6718 obj_encoded_lenindef = t + LENINDEF + v + EOC
6719 with self.assertRaises(DecodeError):
6720 obj.decode(obj_encoded_lenindef)
6721 obj_decoded_lenindef, tail_lenindef = obj.decode(
6722 obj_encoded_lenindef + tail_junk,
6723 ctx={"bered": True},
6725 self.assertTrue(obj_decoded_lenindef.lenindef)
6726 self.assertTrue(obj_decoded_lenindef.bered)
6727 obj_decoded_lenindef = copy(obj_decoded_lenindef)
6728 self.assertTrue(obj_decoded_lenindef.lenindef)
6729 self.assertTrue(obj_decoded_lenindef.bered)
6730 repr(obj_decoded_lenindef)
6731 list(obj_decoded_lenindef.pps())
6732 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
6733 self.assertEqual(tail_lenindef, tail_junk)
6734 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
6735 with self.assertRaises(DecodeError):
6736 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
6737 with self.assertRaises(DecodeError):
6738 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
6740 evgens = list(obj.decode_evgen(
6741 obj_encoded_lenindef + tail_junk,
6742 decode_path=decode_path,
6743 ctx={"bered": True},
6745 self.assertEqual(len(evgens), len(obj_decoded_lenindef) + 1)
6746 for i, (_decode_path, obj, _) in enumerate(evgens[:-1]):
6747 self.assertEqual(_decode_path, decode_path + (str(i),))
6750 _decode_path, obj, tail = evgens[-1]
6751 self.assertEqual(_decode_path, decode_path)
6755 assert_exceeding_data(
6757 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
6761 def test_bered(self):
6762 class SeqOf(self.base_klass):
6764 encoded = Boolean(False).encode()
6765 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
6766 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6767 with self.assertRaises(DecodeError):
6768 SeqOf().decode(encoded)
6769 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6770 self.assertFalse(decoded.ber_encoded)
6771 self.assertFalse(decoded.lenindef)
6772 self.assertTrue(decoded.bered)
6773 decoded = copy(decoded)
6774 self.assertFalse(decoded.ber_encoded)
6775 self.assertFalse(decoded.lenindef)
6776 self.assertTrue(decoded.bered)
6778 class SeqOf(self.base_klass):
6779 schema = OctetString()
6780 encoded = OctetString(b"whatever").encode()
6782 tag_encode(form=TagFormConstructed, num=4) +
6784 OctetString(b"whatever").encode() +
6787 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6788 with self.assertRaises(DecodeError):
6789 SeqOf().decode(encoded)
6790 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6791 self.assertFalse(decoded.ber_encoded)
6792 self.assertFalse(decoded.lenindef)
6793 self.assertTrue(decoded.bered)
6794 decoded = copy(decoded)
6795 self.assertFalse(decoded.ber_encoded)
6796 self.assertFalse(decoded.lenindef)
6797 self.assertTrue(decoded.bered)
6800 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
6801 class SeqOf(SequenceOf):
6805 def _test_symmetric_compare_objs(self, obj1, obj2):
6806 self.assertEqual(obj1, obj2)
6807 self.assertSequenceEqual(list(obj1), list(obj2))
6810 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
6815 def _test_symmetric_compare_objs(self, obj1, obj2):
6816 self.assertSetEqual(
6817 set(int(v) for v in obj1),
6818 set(int(v) for v in obj2),
6821 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6822 @given(data_strategy())
6823 def test_sorted(self, d):
6824 values = [OctetString(v) for v in d.draw(lists(binary()))]
6827 schema = OctetString()
6829 seq_encoded = seq.encode()
6830 seq_decoded, _ = seq.decode(seq_encoded)
6831 self.assertSequenceEqual(
6832 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6833 b"".join(sorted([v.encode() for v in values])),
6836 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6837 @given(data_strategy())
6838 def test_unsorted(self, d):
6839 values = [OctetString(v).encode() for v in d.draw(sets(
6840 binary(min_size=1, max_size=5),
6844 values = d.draw(permutations(values))
6845 assume(values != sorted(values))
6846 encoded = b"".join(values)
6847 seq_encoded = b"".join((
6849 len_encode(len(encoded)),
6854 schema = OctetString()
6856 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6857 seq.decode(seq_encoded)
6859 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6860 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6861 self.assertTrue(seq_decoded.ber_encoded)
6862 self.assertTrue(seq_decoded.bered)
6863 seq_decoded = copy(seq_decoded)
6864 self.assertTrue(seq_decoded.ber_encoded)
6865 self.assertTrue(seq_decoded.bered)
6866 self.assertSequenceEqual(
6867 [obj.encode() for obj in seq_decoded],
6872 class TestGoMarshalVectors(TestCase):
6874 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6875 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6876 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6877 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6878 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6880 class Seq(Sequence):
6882 ("erste", Integer()),
6883 ("zweite", Integer(optional=True))
6886 seq["erste"] = Integer(64)
6887 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6888 seq["erste"] = Integer(0x123456)
6889 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6890 seq["erste"] = Integer(64)
6891 seq["zweite"] = Integer(65)
6892 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6894 class NestedSeq(Sequence):
6898 seq["erste"] = Integer(127)
6899 seq["zweite"] = None
6900 nested = NestedSeq()
6901 nested["nest"] = seq
6902 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6904 self.assertSequenceEqual(
6905 OctetString(b"\x01\x02\x03").encode(),
6906 hexdec("0403010203"),
6909 class Seq(Sequence):
6911 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6914 seq["erste"] = Integer(64)
6915 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6917 class Seq(Sequence):
6919 ("erste", Integer(expl=tag_ctxc(5))),
6922 seq["erste"] = Integer(64)
6923 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6925 class Seq(Sequence):
6928 impl=tag_encode(0, klass=TagClassContext),
6933 seq["erste"] = Null()
6934 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6936 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6938 self.assertSequenceEqual(
6939 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6940 hexdec("170d3730303130313030303030305a"),
6942 self.assertSequenceEqual(
6943 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6944 hexdec("170d3039313131353232353631365a"),
6946 self.assertSequenceEqual(
6947 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6948 hexdec("180f32313030303430353132303130315a"),
6951 class Seq(Sequence):
6953 ("erste", GeneralizedTime()),
6956 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6957 self.assertSequenceEqual(
6959 hexdec("3011180f32303039313131353232353631365a"),
6962 self.assertSequenceEqual(
6963 BitString((1, b"\x80")).encode(),
6966 self.assertSequenceEqual(
6967 BitString((12, b"\x81\xF0")).encode(),
6968 hexdec("03030481f0"),
6971 self.assertSequenceEqual(
6972 ObjectIdentifier("1.2.3.4").encode(),
6973 hexdec("06032a0304"),
6975 self.assertSequenceEqual(
6976 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6977 hexdec("06092a864888932d010105"),
6979 self.assertSequenceEqual(
6980 ObjectIdentifier("2.100.3").encode(),
6981 hexdec("0603813403"),
6984 self.assertSequenceEqual(
6985 PrintableString("test").encode(),
6986 hexdec("130474657374"),
6988 self.assertSequenceEqual(
6989 PrintableString("x" * 127).encode(),
6990 hexdec("137F" + "78" * 127),
6992 self.assertSequenceEqual(
6993 PrintableString("x" * 128).encode(),
6994 hexdec("138180" + "78" * 128),
6996 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6998 class Seq(Sequence):
7000 ("erste", IA5String()),
7003 seq["erste"] = IA5String("test")
7004 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
7006 class Seq(Sequence):
7008 ("erste", PrintableString()),
7011 seq["erste"] = PrintableString("test")
7012 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
7013 # Asterisk is actually not allowable
7014 PrintableString._allowable_chars |= set(b"*")
7015 seq["erste"] = PrintableString("test*")
7016 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
7017 PrintableString._allowable_chars -= set(b"*")
7019 class Seq(Sequence):
7021 ("erste", Any(optional=True)),
7022 ("zweite", Integer()),
7025 seq["zweite"] = Integer(64)
7026 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7031 seq.append(Integer(10))
7032 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
7034 class _SeqOf(SequenceOf):
7035 schema = PrintableString()
7037 class SeqOf(SequenceOf):
7040 _seqof.append(PrintableString("1"))
7042 seqof.append(_seqof)
7043 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
7045 class Seq(Sequence):
7047 ("erste", Integer(default=1)),
7050 seq["erste"] = Integer(0)
7051 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
7052 seq["erste"] = Integer(1)
7053 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7054 seq["erste"] = Integer(2)
7055 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
7058 class TestPP(TestCase):
7059 @given(data_strategy())
7060 def test_oid_printing(self, d):
7062 str(ObjectIdentifier(k)): v * 2
7063 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
7065 chosen = d.draw(sampled_from(sorted(oids)))
7066 chosen_id = oids[chosen]
7067 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
7068 self.assertNotIn(chosen_id, pp_console_row(pp))
7071 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
7075 class TestAutoAddSlots(TestCase):
7077 class Inher(Integer):
7080 with self.assertRaises(AttributeError):
7082 inher.unexistent = "whatever"
7085 class TestOIDDefines(TestCase):
7086 @given(data_strategy())
7087 def runTest(self, d):
7088 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
7089 value_name_chosen = d.draw(sampled_from(value_names))
7091 ObjectIdentifier(oid)
7092 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
7094 oid_chosen = d.draw(sampled_from(oids))
7095 values = d.draw(lists(
7097 min_size=len(value_names),
7098 max_size=len(value_names),
7100 for definable_class in (Any, OctetString, BitString):
7102 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
7103 oid: Integer() for oid in oids[:-1]
7106 for i, value_name in enumerate(value_names):
7107 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
7109 class Seq(Sequence):
7112 for value_name, value in zip(value_names, values):
7113 seq[value_name] = definable_class(Integer(value).encode())
7114 seq["type"] = oid_chosen
7115 seq, _ = Seq().decode(seq.encode())
7116 for value_name in value_names:
7117 if value_name == value_name_chosen:
7119 self.assertIsNone(seq[value_name].defined)
7120 if value_name_chosen in oids[:-1]:
7121 self.assertIsNotNone(seq[value_name_chosen].defined)
7122 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
7123 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
7126 pprint(seq, big_blobs=True, with_decode_path=True)
7129 class TestDefinesByPath(TestCase):
7130 def test_generated(self):
7131 class Seq(Sequence):
7133 ("type", ObjectIdentifier()),
7134 ("value", OctetString(expl=tag_ctxc(123))),
7137 class SeqInner(Sequence):
7139 ("typeInner", ObjectIdentifier()),
7140 ("valueInner", Any()),
7143 class PairValue(SetOf):
7146 class Pair(Sequence):
7148 ("type", ObjectIdentifier()),
7149 ("value", PairValue()),
7152 class Pairs(SequenceOf):
7159 type_octet_stringed,
7161 ObjectIdentifier(oid)
7162 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
7164 seq_integered = Seq()
7165 seq_integered["type"] = type_integered
7166 seq_integered["value"] = OctetString(Integer(123).encode())
7167 seq_integered_raw = seq_integered.encode()
7171 (type_octet_stringed, OctetString(b"whatever")),
7172 (type_integered, Integer(123)),
7173 (type_octet_stringed, OctetString(b"whenever")),
7174 (type_integered, Integer(234)),
7176 for t, v in pairs_input:
7179 ("value", PairValue((Any(v),))),
7181 seq_inner = SeqInner()
7182 seq_inner["typeInner"] = type_innered
7183 seq_inner["valueInner"] = Any(pairs)
7184 seq_sequenced = Seq()
7185 seq_sequenced["type"] = type_sequenced
7186 seq_sequenced["value"] = OctetString(seq_inner.encode())
7187 seq_sequenced_raw = seq_sequenced.encode()
7189 list(seq_sequenced.pps())
7190 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7192 defines_by_path = []
7193 ctx_copied = deepcopy(ctx_dummy)
7194 seq_integered, _ = Seq().decode(
7198 self.assertDictEqual(ctx_copied, ctx_dummy)
7199 self.assertIsNone(seq_integered["value"].defined)
7200 defines_by_path.append(
7201 (("type",), ((("value",), {
7202 type_integered: Integer(),
7203 type_sequenced: SeqInner(),
7206 ctx_copied["defines_by_path"] = defines_by_path
7207 seq_integered, _ = Seq().decode(
7211 del ctx_copied["defines_by_path"]
7212 self.assertDictEqual(ctx_copied, ctx_dummy)
7213 self.assertIsNotNone(seq_integered["value"].defined)
7214 self.assertEqual(seq_integered["value"].defined[0], type_integered)
7215 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
7216 self.assertTrue(seq_integered_raw[
7217 seq_integered["value"].defined[1].offset:
7218 ].startswith(Integer(123).encode()))
7220 list(seq_integered.pps())
7221 pprint(seq_integered, big_blobs=True, with_decode_path=True)
7223 ctx_copied["defines_by_path"] = defines_by_path
7224 seq_sequenced, _ = Seq().decode(
7228 del ctx_copied["defines_by_path"]
7229 self.assertDictEqual(ctx_copied, ctx_dummy)
7230 self.assertIsNotNone(seq_sequenced["value"].defined)
7231 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7232 seq_inner = seq_sequenced["value"].defined[1]
7233 self.assertIsNone(seq_inner["valueInner"].defined)
7235 list(seq_sequenced.pps())
7236 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7238 defines_by_path.append((
7239 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
7240 ((("valueInner",), {type_innered: Pairs()}),),
7242 ctx_copied["defines_by_path"] = defines_by_path
7243 seq_sequenced, _ = Seq().decode(
7247 del ctx_copied["defines_by_path"]
7248 self.assertDictEqual(ctx_copied, ctx_dummy)
7249 self.assertIsNotNone(seq_sequenced["value"].defined)
7250 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7251 seq_inner = seq_sequenced["value"].defined[1]
7252 self.assertIsNotNone(seq_inner["valueInner"].defined)
7253 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7254 pairs = seq_inner["valueInner"].defined[1]
7256 self.assertIsNone(pair["value"][0].defined)
7258 list(seq_sequenced.pps())
7259 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7261 defines_by_path.append((
7264 DecodePathDefBy(type_sequenced),
7266 DecodePathDefBy(type_innered),
7271 type_integered: Integer(),
7272 type_octet_stringed: OctetString(),
7275 ctx_copied["defines_by_path"] = defines_by_path
7276 seq_sequenced, _ = Seq().decode(
7280 del ctx_copied["defines_by_path"]
7281 self.assertDictEqual(ctx_copied, ctx_dummy)
7282 self.assertIsNotNone(seq_sequenced["value"].defined)
7283 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7284 seq_inner = seq_sequenced["value"].defined[1]
7285 self.assertIsNotNone(seq_inner["valueInner"].defined)
7286 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7287 pairs_got = seq_inner["valueInner"].defined[1]
7288 for pair_input, pair_got in zip(pairs_input, pairs_got):
7289 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7290 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7292 list(seq_sequenced.pps())
7293 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7295 @given(oid_strategy(), integers())
7296 def test_simple(self, oid, tgt):
7297 class Inner(Sequence):
7299 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7300 ObjectIdentifier(oid): Integer(),
7304 class Outer(Sequence):
7307 ("tgt", OctetString()),
7311 inner["oid"] = ObjectIdentifier(oid)
7313 outer["inner"] = inner
7314 outer["tgt"] = OctetString(Integer(tgt).encode())
7315 decoded, _ = Outer().decode(outer.encode())
7316 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7318 def test_remaining_data(self):
7319 oid = ObjectIdentifier("1.2.3")
7320 class Seq(Sequence):
7322 ("oid", ObjectIdentifier(defines=((("tgt",), {
7325 ("tgt", OctetString()),
7330 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7332 with assertRaisesRegex(self, DecodeError, "remaining data"):
7333 Seq().decode(seq.encode())
7335 def test_remaining_data_seqof(self):
7336 oid = ObjectIdentifier("1.2.3")
7338 schema = OctetString()
7340 class Seq(Sequence):
7342 ("oid", ObjectIdentifier(defines=((("tgt",), {
7350 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7352 with assertRaisesRegex(self, DecodeError, "remaining data"):
7353 Seq().decode(seq.encode())
7356 class TestAbsDecodePath(TestCase):
7358 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7359 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7361 def test_concat(self, decode_path, rel_path):
7362 dp = abs_decode_path(decode_path, rel_path)
7363 self.assertSequenceEqual(dp, decode_path + rel_path)
7367 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7368 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7370 def test_abs(self, decode_path, rel_path):
7371 self.assertSequenceEqual(
7372 abs_decode_path(decode_path, ("/",) + rel_path),
7377 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7378 integers(min_value=1, max_value=3),
7379 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7381 def test_dots(self, decode_path, number_of_dots, rel_path):
7382 self.assertSequenceEqual(
7383 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7384 decode_path[:-number_of_dots] + rel_path,
7388 class TestStrictDefaultExistence(TestCase):
7389 @given(data_strategy())
7390 def runTest(self, d):
7391 count = d.draw(integers(min_value=1, max_value=10))
7392 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7394 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7395 for i in range(count)
7397 for klass in (Sequence, Set):
7401 for i in range(count):
7402 seq["int%d" % i] = Integer(123)
7404 chosen_choice = "int%d" % chosen
7405 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7406 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
7408 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7409 self.assertTrue(decoded.ber_encoded)
7410 self.assertTrue(decoded.bered)
7411 decoded = copy(decoded)
7412 self.assertTrue(decoded.ber_encoded)
7413 self.assertTrue(decoded.bered)
7414 decoded, _ = seq.decode(raw, ctx={"bered": True})
7415 self.assertTrue(decoded.ber_encoded)
7416 self.assertTrue(decoded.bered)
7417 decoded = copy(decoded)
7418 self.assertTrue(decoded.ber_encoded)
7419 self.assertTrue(decoded.bered)
7422 class TestX690PrefixedType(TestCase):
7424 self.assertSequenceEqual(
7425 VisibleString("Jones").encode(),
7426 hexdec("1A054A6F6E6573"),
7428 self.assertSequenceEqual(
7431 impl=tag_encode(3, klass=TagClassApplication),
7433 hexdec("43054A6F6E6573"),
7435 self.assertSequenceEqual(
7439 impl=tag_encode(3, klass=TagClassApplication),
7443 hexdec("A20743054A6F6E6573"),
7445 self.assertSequenceEqual(
7449 impl=tag_encode(3, klass=TagClassApplication),
7451 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7453 hexdec("670743054A6F6E6573"),
7455 self.assertSequenceEqual(
7456 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7457 hexdec("82054A6F6E6573"),
7461 class TestExplOOB(TestCase):
7463 expl = tag_ctxc(123)
7464 raw = Integer(123).encode() + Integer(234).encode()
7465 raw = b"".join((expl, len_encode(len(raw)), raw))
7466 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
7467 Integer(expl=expl).decode(raw)
7468 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7471 class TestPickleDifferentVersion(TestCase):
7473 pickled = pickle_dumps(Integer(123), pickle_proto)
7475 version_orig = pyderasn.__version__
7476 pyderasn.__version__ += "different"
7477 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
7478 pickle_loads(pickled)
7479 pyderasn.__version__ = version_orig
7480 pickle_loads(pickled)