2 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures
3 # Copyright (C) 2017-2021 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 io import BytesIO
24 from operator import attrgetter
25 from os import environ
26 from os import urandom
27 from random import random
28 from string import ascii_letters
29 from string import digits
30 from string import printable
31 from string import whitespace
32 from time import mktime
34 from unittest import TestCase
36 from dateutil.tz import UTC
37 from hypothesis import assume
38 from hypothesis import given
39 from hypothesis import settings
40 from hypothesis.strategies import binary
41 from hypothesis.strategies import booleans
42 from hypothesis.strategies import composite
43 from hypothesis.strategies import data as data_strategy
44 from hypothesis.strategies import datetimes
45 from hypothesis.strategies import dictionaries
46 from hypothesis.strategies import integers
47 from hypothesis.strategies import just
48 from hypothesis.strategies import lists
49 from hypothesis.strategies import none
50 from hypothesis.strategies import one_of
51 from hypothesis.strategies import permutations
52 from hypothesis.strategies import sampled_from
53 from hypothesis.strategies import sets
54 from hypothesis.strategies import text
55 from hypothesis.strategies import tuples
56 from pickle import dumps as pickle_dumps
57 from pickle import HIGHEST_PROTOCOL as pickle_proto
58 from pickle import loads as pickle_loads
60 from pyderasn import _pp
61 from pyderasn import abs_decode_path
62 from pyderasn import Any
63 from pyderasn import BitString
64 from pyderasn import BMPString
65 from pyderasn import Boolean
66 from pyderasn import BoundsError
67 from pyderasn import Choice
68 from pyderasn import DecodeError
69 from pyderasn import DecodePathDefBy
70 from pyderasn import encode2pass
71 from pyderasn import encode_cer
72 from pyderasn import Enumerated
73 from pyderasn import EOC
74 from pyderasn import EOC_LEN
75 from pyderasn import ExceedingData
76 from pyderasn import GeneralizedTime
77 from pyderasn import GeneralString
78 from pyderasn import GraphicString
79 from pyderasn import hexdec
80 from pyderasn import hexenc
81 from pyderasn import IA5String
82 from pyderasn import Integer
83 from pyderasn import InvalidLength
84 from pyderasn import InvalidOID
85 from pyderasn import InvalidValueType
86 from pyderasn import len_decode
87 from pyderasn import len_encode
88 from pyderasn import LEN_YYMMDDHHMMSSZ
89 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
90 from pyderasn import LEN_YYYYMMDDHHMMSSZ
91 from pyderasn import LENINDEF
92 from pyderasn import LenIndefForm
93 from pyderasn import NotEnoughData
94 from pyderasn import Null
95 from pyderasn import NumericString
96 from pyderasn import ObjectIdentifier
97 from pyderasn import ObjNotReady
98 from pyderasn import ObjUnknown
99 from pyderasn import OctetString
100 from pyderasn import pp_console_row
101 from pyderasn import pprint
102 from pyderasn import PrintableString
103 from pyderasn import Sequence
104 from pyderasn import SequenceOf
105 from pyderasn import Set
106 from pyderasn import SetOf
107 from pyderasn import tag_ctxc
108 from pyderasn import tag_ctxp
109 from pyderasn import tag_decode
110 from pyderasn import tag_encode
111 from pyderasn import tag_strip
112 from pyderasn import TagClassApplication
113 from pyderasn import TagClassContext
114 from pyderasn import TagClassPrivate
115 from pyderasn import TagClassUniversal
116 from pyderasn import TagFormConstructed
117 from pyderasn import TagFormPrimitive
118 from pyderasn import TagMismatch
119 from pyderasn import TeletexString
120 from pyderasn import UniversalString
121 from pyderasn import UTCTime
122 from pyderasn import UTF8String
123 from pyderasn import VideotexString
124 from pyderasn import VisibleString
127 max_examples = environ.get("MAX_EXAMPLES")
128 settings.register_profile("local", settings(
130 **({"max_examples": int(max_examples)} if max_examples else {})
132 settings.load_profile("local")
133 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
135 tag_classes = sampled_from((
141 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
142 decode_path_strat = lists(integers(), max_size=3).map(
143 lambda decode_path: tuple(str(dp) for dp in decode_path)
145 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
148 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
150 self_module = import_module(__name__)
153 def register_class(klass):
154 klassname = klass.__name__ + str(time()).replace(".", "")
155 klass.__name__ = klassname
156 klass.__qualname__ = klassname
157 setattr(self_module, klassname, klass)
160 def assert_exceeding_data(self, call, junk):
163 with self.assertRaisesRegex(ExceedingData, "%d trailing bytes" % len(junk)) as err:
168 class TestHex(TestCase):
170 def test_symmetric(self, data):
171 self.assertEqual(hexdec(hexenc(data)), data)
174 class TestTagCoder(TestCase):
175 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
179 integers(min_value=0, max_value=30),
182 def test_short(self, klass, form, num, junk):
183 raw = tag_encode(klass=klass, form=form, num=num)
184 self.assertEqual(tag_decode(raw), (klass, form, num))
185 self.assertEqual(len(raw), 1)
187 tag_encode(klass=klass, form=form, num=0)[0],
188 raw[0] & (1 << 7 | 1 << 6 | 1 << 5),
190 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
191 self.assertSequenceEqual(stripped.tobytes(), raw)
192 self.assertEqual(tlen, len(raw))
193 self.assertSequenceEqual(tail, junk)
195 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
199 integers(min_value=31),
202 def test_long(self, klass, form, num, junk):
203 raw = tag_encode(klass=klass, form=form, num=num)
204 self.assertEqual(tag_decode(raw), (klass, form, num))
205 self.assertGreater(len(raw), 1)
207 tag_encode(klass=klass, form=form, num=0)[0] | 31,
210 self.assertEqual(raw[-1] & 0x80, 0)
211 self.assertTrue(all(b & 0x80 > 0 for b in raw[1:-1]))
212 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
213 self.assertSequenceEqual(stripped.tobytes(), raw)
214 self.assertEqual(tlen, len(raw))
215 self.assertSequenceEqual(tail, junk)
217 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
218 @given(integers(min_value=31))
219 def test_unfinished_tag(self, num):
220 raw = bytearray(tag_encode(num=num))
221 for i in range(1, len(raw)):
223 with self.assertRaisesRegex(DecodeError, "unfinished tag"):
224 tag_strip(bytes(raw))
226 def test_go_vectors_valid(self):
227 for data, (eklass, etag, elen, eform) in (
228 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
229 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
230 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
231 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
232 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
233 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
234 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
235 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
236 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
237 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
239 tag, _, len_encoded = tag_strip(memoryview(data))
240 klass, form, num = tag_decode(tag)
241 _len, _, tail = len_decode(len_encoded)
242 self.assertSequenceEqual(tail, b"")
243 self.assertEqual(klass, eklass)
244 self.assertEqual(num, etag)
245 self.assertEqual(_len, elen)
246 self.assertEqual(form, eform)
248 def test_go_vectors_invalid(self):
256 with self.assertRaises(DecodeError):
257 _, _, len_encoded = tag_strip(memoryview(data))
258 len_decode(len_encoded)
261 integers(min_value=0, max_value=127),
262 integers(min_value=0, max_value=2),
264 def test_long_instead_of_short(self, l, dummy_num):
265 octets = (b"\x00" * dummy_num) + bytes([l])
266 octets = bytes([(dummy_num + 1) | 0x80]) + octets
267 with self.assertRaises(DecodeError):
270 @given(tag_classes, tag_forms, integers(min_value=31))
271 def test_leading_zero_byte(self, klass, form, num):
272 raw = tag_encode(klass=klass, form=form, num=num)
273 raw = b"".join((raw[:1], b"\x80", raw[1:]))
274 with self.assertRaisesRegex(DecodeError, "leading zero byte"):
277 @given(tag_classes, tag_forms, integers(max_value=30, min_value=0))
278 def test_unexpected_long_form(self, klass, form, num):
279 raw = bytes([klass | form | 31, num])
280 with self.assertRaisesRegex(DecodeError, "unexpected long form"):
284 class TestLenCoder(TestCase):
285 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
287 integers(min_value=0, max_value=127),
290 def test_short(self, l, junk):
291 raw = len_encode(l) + junk
292 decoded, llen, tail = len_decode(memoryview(raw))
293 self.assertEqual(decoded, l)
294 self.assertEqual(llen, 1)
295 self.assertEqual(len(raw), 1 + len(junk))
296 self.assertEqual(tail.tobytes(), junk)
298 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
300 integers(min_value=128),
303 def test_long(self, l, junk):
304 raw = len_encode(l) + junk
305 decoded, llen, tail = len_decode(memoryview(raw))
306 self.assertEqual(decoded, l)
307 self.assertEqual((llen - 1) | 0x80, raw[0])
308 self.assertEqual(llen, len(raw) - len(junk))
309 self.assertNotEqual(raw[1], 0)
310 self.assertSequenceEqual(tail.tobytes(), junk)
312 def test_empty(self):
313 with self.assertRaises(NotEnoughData):
316 @given(integers(min_value=128))
317 def test_stripped(self, _len):
318 with self.assertRaises(NotEnoughData):
319 len_decode(len_encode(_len)[:-1])
322 text_printable = text(alphabet=printable, min_size=1)
326 def text_letters(draw):
327 result = draw(text(alphabet=ascii_letters, min_size=1))
331 class CommonMixin(object):
332 def test_tag_default(self):
333 obj = self.base_klass()
334 self.assertEqual(obj.tag, obj.tag_default)
336 def test_simultaneous_impl_expl(self):
337 with self.assertRaises(ValueError):
338 self.base_klass(impl=b"whatever", expl=b"whenever")
340 @given(binary(min_size=1), integers(), integers(), integers())
341 def test_decoded(self, impl, offset, llen, vlen):
342 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
343 self.assertEqual(obj.offset, offset)
344 self.assertEqual(obj.llen, llen)
345 self.assertEqual(obj.vlen, vlen)
346 self.assertEqual(obj.tlen, len(impl))
347 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
349 @given(binary(min_size=1))
350 def test_impl_inherited(self, impl_tag):
351 class Inherited(self.base_klass):
354 self.assertSequenceEqual(obj.impl, impl_tag)
355 self.assertFalse(obj.expled)
357 tag_class, _, tag_num = tag_decode(impl_tag)
358 self.assertEqual(obj.tag_order, (tag_class, tag_num))
360 @given(binary(min_size=1))
361 def test_expl_inherited(self, expl_tag):
362 class Inherited(self.base_klass):
365 self.assertSequenceEqual(obj.expl, expl_tag)
366 self.assertTrue(obj.expled)
368 tag_class, _, tag_num = tag_decode(expl_tag)
369 self.assertEqual(obj.tag_order, (tag_class, tag_num))
371 def assert_copied_basic_fields(self, obj, obj_copied):
372 self.assertEqual(obj, obj_copied)
373 self.assertSequenceEqual(obj.tag, obj_copied.tag)
374 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
375 self.assertEqual(obj.default, obj_copied.default)
376 self.assertEqual(obj.optional, obj_copied.optional)
377 self.assertEqual(obj.offset, obj_copied.offset)
378 self.assertEqual(obj.llen, obj_copied.llen)
379 self.assertEqual(obj.vlen, obj_copied.vlen)
381 self.assertEqual(obj.tag_order, obj_copied.tag_order)
385 def boolean_values_strategy(draw, do_expl=False):
386 value = draw(one_of(none(), booleans()))
390 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
392 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
393 default = draw(one_of(none(), booleans()))
394 optional = draw(one_of(none(), booleans()))
396 draw(integers(min_value=0)),
397 draw(integers(min_value=0)),
398 draw(integers(min_value=0)),
400 return (value, impl, expl, default, optional, _decoded)
403 class BooleanInherited(Boolean):
407 class TestBoolean(CommonMixin, TestCase):
410 def test_invalid_value_type(self):
411 with self.assertRaises(InvalidValueType) as err:
416 def test_optional(self, optional):
417 obj = Boolean(default=Boolean(False), optional=optional)
418 self.assertTrue(obj.optional)
421 def test_ready(self, value):
423 self.assertFalse(obj.ready)
426 pprint(obj, big_blobs=True, with_decode_path=True)
427 with self.assertRaises(ObjNotReady) as err:
429 with self.assertRaises(ObjNotReady) as err:
433 self.assertTrue(obj.ready)
436 pprint(obj, big_blobs=True, with_decode_path=True)
438 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
439 def test_comparison(self, value1, value2, tag1, tag2):
440 for klass in (Boolean, BooleanInherited):
443 self.assertEqual(obj1 == obj2, value1 == value2)
444 self.assertEqual(obj1 != obj2, value1 != value2)
445 self.assertEqual(obj1 == bool(obj2), value1 == value2)
446 obj1 = klass(value1, impl=tag1)
447 obj2 = klass(value1, impl=tag2)
448 self.assertEqual(obj1 == obj2, tag1 == tag2)
449 self.assertEqual(obj1 != obj2, tag1 != tag2)
451 @given(data_strategy())
452 def test_call(self, d):
453 for klass in (Boolean, BooleanInherited):
461 ) = d.draw(boolean_values_strategy())
467 optional_initial or False,
477 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
478 obj = obj_initial(value, impl, expl, default, optional)
480 value_expected = default if value is None else value
482 default_initial if value_expected is None
485 self.assertEqual(obj, value_expected)
486 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
487 self.assertEqual(obj.expl_tag, expl or expl_initial)
490 default_initial if default is None else default,
492 if obj.default is None:
493 optional = optional_initial if optional is None else optional
494 optional = False if optional is None else optional
497 self.assertEqual(obj.optional, optional)
499 @given(boolean_values_strategy())
500 def test_copy(self, values):
501 for klass in (Boolean, BooleanInherited):
503 for copy_func in copy_funcs:
504 obj_copied = copy_func(obj)
505 self.assert_copied_basic_fields(obj, obj_copied)
509 integers(min_value=1).map(tag_encode),
511 def test_stripped(self, value, tag_impl):
512 obj = Boolean(value, impl=tag_impl)
513 with self.assertRaises(NotEnoughData):
514 obj.decode(obj.encode()[:-1])
515 with self.assertRaises(NotEnoughData):
516 obj.decode(encode2pass(obj)[:-1])
520 integers(min_value=1).map(tag_ctxc),
522 def test_stripped_expl(self, value, tag_expl):
523 obj = Boolean(value, expl=tag_expl)
524 with self.assertRaises(NotEnoughData):
525 obj.decode(obj.encode()[:-1])
526 with self.assertRaises(NotEnoughData):
527 obj.decode(encode2pass(obj)[:-1])
530 integers(min_value=31),
531 integers(min_value=0),
534 def test_bad_tag(self, tag, offset, decode_path):
535 with self.assertRaises(DecodeError) as err:
537 tag_encode(tag)[:-1],
539 decode_path=decode_path,
542 self.assertEqual(err.exception.offset, offset)
543 self.assertEqual(err.exception.decode_path, decode_path)
546 integers(min_value=31),
547 integers(min_value=0),
550 def test_bad_expl_tag(self, tag, offset, decode_path):
551 with self.assertRaises(DecodeError) as err:
552 Boolean(expl=Boolean.tag_default).decode(
553 tag_encode(tag)[:-1],
555 decode_path=decode_path,
558 self.assertEqual(err.exception.offset, offset)
559 self.assertEqual(err.exception.decode_path, decode_path)
562 integers(min_value=128),
563 integers(min_value=0),
566 def test_bad_len(self, l, offset, decode_path):
567 with self.assertRaises(DecodeError) as err:
569 Boolean.tag_default + len_encode(l)[:-1],
571 decode_path=decode_path,
574 self.assertEqual(err.exception.offset, offset)
575 self.assertEqual(err.exception.decode_path, decode_path)
578 integers(min_value=128),
579 integers(min_value=0),
582 def test_bad_expl_len(self, l, offset, decode_path):
583 with self.assertRaises(DecodeError) as err:
584 Boolean(expl=Boolean.tag_default).decode(
585 Boolean.tag_default + len_encode(l)[:-1],
587 decode_path=decode_path,
590 self.assertEqual(err.exception.offset, offset)
591 self.assertEqual(err.exception.decode_path, decode_path)
593 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
595 boolean_values_strategy(),
597 integers(min_value=1).map(tag_ctxc),
598 integers(min_value=0),
602 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
603 for klass in (Boolean, BooleanInherited):
604 _, _, _, default, optional, _decoded = values
613 pprint(obj, big_blobs=True, with_decode_path=True)
614 self.assertFalse(obj.expled)
615 obj_encoded = obj.encode()
616 self.assertEqual(encode2pass(obj), obj_encoded)
617 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
618 obj_expled = obj(value, expl=tag_expl)
619 self.assertTrue(obj_expled.expled)
621 list(obj_expled.pps())
622 pprint(obj_expled, big_blobs=True, with_decode_path=True)
623 obj_expled_cer = encode_cer(obj_expled)
624 self.assertNotEqual(obj_expled_cer, obj_encoded)
625 self.assertSequenceEqual(
626 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
629 obj_expled_hex_encoded = obj_expled.hexencode()
630 ctx_copied = deepcopy(ctx_dummy)
631 obj_decoded, tail = obj_expled.hexdecode(
632 obj_expled_hex_encoded + hexenc(tail_junk),
636 self.assertDictEqual(ctx_copied, ctx_dummy)
638 list(obj_decoded.pps())
639 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
640 self.assertEqual(tail, tail_junk)
641 self.assertEqual(obj_decoded, obj_expled)
642 self.assertNotEqual(obj_decoded, obj)
643 self.assertEqual(bool(obj_decoded), bool(obj_expled))
644 self.assertEqual(bool(obj_decoded), bool(obj))
645 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
646 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
647 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
649 obj_decoded.expl_llen,
650 len(len_encode(len(obj_encoded))),
652 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
653 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
656 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
658 self.assertEqual(obj_decoded.expl_offset, offset)
659 assert_exceeding_data(
661 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
665 evgens = list(obj_expled.decode_evgen(
666 hexdec(obj_expled_hex_encoded) + tail_junk,
668 decode_path=decode_path,
671 self.assertEqual(len(evgens), 1)
672 _decode_path, obj, tail = evgens[0]
673 self.assertSequenceEqual(tail, tail_junk)
674 self.assertEqual(_decode_path, decode_path)
675 self.assertEqual(obj, obj_decoded)
676 self.assertEqual(obj.expl_offset, offset)
680 @given(integers(min_value=2))
681 def test_invalid_len(self, l):
682 with self.assertRaises(InvalidLength):
683 Boolean().decode(b"".join((
689 @given(integers(min_value=0 + 1, max_value=255 - 1))
690 def test_ber_value(self, value):
691 with self.assertRaisesRegex(DecodeError, "unacceptable Boolean value"):
692 Boolean().decode(b"".join((
697 encoded = b"".join((Boolean.tag_default, len_encode(1), bytes([value])))
698 obj, _ = Boolean().decode(encoded, ctx={"bered": True})
699 list(Boolean().decode_evgen(encoded, ctx={"bered": True}))
700 self.assertTrue(bool(obj))
701 self.assertTrue(obj.ber_encoded)
702 self.assertFalse(obj.lenindef)
703 self.assertTrue(obj.bered)
705 self.assertTrue(obj.ber_encoded)
706 self.assertFalse(obj.lenindef)
707 self.assertTrue(obj.bered)
710 integers(min_value=1).map(tag_ctxc),
711 binary().filter(lambda x: not x.startswith(EOC)),
713 def test_ber_expl_no_eoc(self, expl, junk):
714 encoded = expl + LENINDEF + Boolean(False).encode()
715 with self.assertRaises(LenIndefForm):
716 Boolean(expl=expl).decode(encoded + junk)
717 with self.assertRaisesRegex(DecodeError, "no EOC"):
718 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
719 obj, tail = Boolean(expl=expl).decode(
720 encoded + EOC + junk,
723 self.assertTrue(obj.expl_lenindef)
724 self.assertFalse(obj.lenindef)
725 self.assertFalse(obj.ber_encoded)
726 self.assertTrue(obj.bered)
728 self.assertTrue(obj.expl_lenindef)
729 self.assertFalse(obj.lenindef)
730 self.assertFalse(obj.ber_encoded)
731 self.assertTrue(obj.bered)
732 self.assertSequenceEqual(tail, junk)
735 pprint(obj, big_blobs=True, with_decode_path=True)
738 integers(min_value=1).map(tag_ctxc),
745 def test_ber_expl(self, expl, values):
751 Boolean(value).encode() +
754 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
756 class SeqOf(SequenceOf):
757 schema = Boolean(expl=expl)
758 with self.assertRaises(LenIndefForm):
759 SeqOf().decode(encoded)
760 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
761 list(SeqOf().decode_evgen(encoded, ctx={"bered": True}))
762 self.assertSequenceEqual(tail, b"")
763 self.assertSequenceEqual([bool(v) for v in seqof], values)
779 len(expl) + 1 + 3 + EOC_LEN,
790 pprint(seqof, big_blobs=True, with_decode_path=True)
794 def integer_values_strategy(draw, do_expl=False):
795 bound_min, value, default, bound_max = sorted(draw(sets(
804 _specs = draw(sets(text_letters()))
807 min_size=len(_specs),
808 max_size=len(_specs),
810 _specs = list(zip(_specs, values))
813 bounds = (bound_min, bound_max)
817 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
819 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
822 optional = draw(one_of(none(), booleans()))
824 draw(integers(min_value=0)),
825 draw(integers(min_value=0)),
826 draw(integers(min_value=0)),
828 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
831 class IntegerInherited(Integer):
835 class TestInteger(CommonMixin, TestCase):
838 def test_invalid_value_type(self):
839 with self.assertRaises(InvalidValueType) as err:
843 @given(sets(text_letters(), min_size=2))
844 def test_unknown_name(self, names_input):
845 missing = names_input.pop()
848 schema = [(n, 123) for n in names_input]
849 with self.assertRaises(ObjUnknown) as err:
853 @given(sets(text_letters(), min_size=2))
854 def test_known_name(self, names_input):
856 schema = [(n, 123) for n in names_input]
857 Int(names_input.pop())
860 def test_optional(self, optional):
861 obj = Integer(default=Integer(0), optional=optional)
862 self.assertTrue(obj.optional)
865 def test_ready(self, value):
867 self.assertFalse(obj.ready)
870 pprint(obj, big_blobs=True, with_decode_path=True)
871 with self.assertRaises(ObjNotReady) as err:
873 with self.assertRaises(ObjNotReady) as err:
877 self.assertTrue(obj.ready)
880 pprint(obj, big_blobs=True, with_decode_path=True)
883 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
884 def test_comparison(self, value1, value2, tag1, tag2):
885 for klass in (Integer, IntegerInherited):
888 self.assertEqual(obj1 == obj2, value1 == value2)
889 self.assertEqual(obj1 != obj2, value1 != value2)
890 self.assertEqual(obj1 == int(obj2), value1 == value2)
891 obj1 = klass(value1, impl=tag1)
892 obj2 = klass(value1, impl=tag2)
893 self.assertEqual(obj1 == obj2, tag1 == tag2)
894 self.assertEqual(obj1 != obj2, tag1 != tag2)
896 @given(lists(integers()))
897 def test_sorted_works(self, values):
898 self.assertSequenceEqual(
899 [int(v) for v in sorted(Integer(v) for v in values)],
903 @given(data_strategy())
904 def test_named(self, d):
905 names_input = list(d.draw(sets(text_letters(), min_size=1)))
906 values_input = list(d.draw(sets(
908 min_size=len(names_input),
909 max_size=len(names_input),
911 chosen_name = d.draw(sampled_from(names_input))
912 names_input = dict(zip(names_input, values_input))
916 _int = Int(chosen_name)
917 self.assertEqual(_int.named, chosen_name)
918 self.assertEqual(int(_int), names_input[chosen_name])
920 @given(integers(), integers(min_value=0), integers(min_value=0))
921 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
922 value = bound_min + value_delta
923 bound_max = value + bound_delta
924 Integer(value=value, bounds=(bound_min, bound_max))
926 @given(sets(integers(), min_size=3, max_size=3))
927 def test_bounds_unsatisfied(self, values):
928 values = sorted(values)
929 with self.assertRaises(BoundsError) as err:
930 Integer(value=values[0], bounds=(values[1], values[2]))
932 with self.assertRaisesRegex(DecodeError, "bounds") as err:
933 Integer(bounds=(values[1], values[2])).decode(
934 Integer(values[0]).encode()
937 with self.assertRaisesRegex(DecodeError, "bounds") as err:
938 Integer(bounds=(values[1], values[2])).decode(
939 encode2pass(Integer(values[0]))
941 with self.assertRaises(BoundsError) as err:
942 Integer(value=values[2], bounds=(values[0], values[1]))
944 with self.assertRaisesRegex(DecodeError, "bounds") as err:
945 Integer(bounds=(values[0], values[1])).decode(
946 Integer(values[2]).encode()
949 with self.assertRaisesRegex(DecodeError, "bounds") as err:
950 Integer(bounds=(values[0], values[1])).decode(
951 encode2pass(Integer(values[2]))
954 @given(data_strategy())
955 def test_call(self, d):
956 for klass in (Integer, IntegerInherited):
966 ) = d.draw(integer_values_strategy())
973 optional_initial or False,
986 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
987 if (default is None) and (obj_initial.default is not None):
991 (value is not None) and
992 (bounds_initial is not None) and
993 not (bounds_initial[0] <= value <= bounds_initial[1])
998 (default is not None) and
999 (bounds_initial is not None) and
1000 not (bounds_initial[0] <= default <= bounds_initial[1])
1003 obj = obj_initial(value, bounds, impl, expl, default, optional)
1005 value_expected = default if value is None else value
1007 default_initial if value_expected is None
1010 self.assertEqual(obj, value_expected)
1011 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1012 self.assertEqual(obj.expl_tag, expl or expl_initial)
1015 default_initial if default is None else default,
1017 if obj.default is None:
1018 optional = optional_initial if optional is None else optional
1019 optional = False if optional is None else optional
1022 self.assertEqual(obj.optional, optional)
1024 (obj._bound_min, obj._bound_max),
1025 bounds or bounds_initial or (float("-inf"), float("+inf")),
1029 {} if _specs_initial is None else dict(_specs_initial),
1032 @given(integer_values_strategy())
1033 def test_copy(self, values):
1034 for klass in (Integer, IntegerInherited):
1035 obj = klass(*values)
1036 for copy_func in copy_funcs:
1037 obj_copied = copy_func(obj)
1038 self.assert_copied_basic_fields(obj, obj_copied)
1039 self.assertEqual(obj.specs, obj_copied.specs)
1040 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1041 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1042 self.assertEqual(obj._value, obj_copied._value)
1046 integers(min_value=1).map(tag_encode),
1048 def test_stripped(self, value, tag_impl):
1049 obj = Integer(value, impl=tag_impl)
1050 with self.assertRaises(NotEnoughData):
1051 obj.decode(obj.encode()[:-1])
1055 integers(min_value=1).map(tag_ctxc),
1057 def test_stripped_expl(self, value, tag_expl):
1058 obj = Integer(value, expl=tag_expl)
1059 with self.assertRaises(NotEnoughData):
1060 obj.decode(obj.encode()[:-1])
1062 def test_zero_len(self):
1063 with self.assertRaises(NotEnoughData):
1064 Integer().decode(b"".join((
1065 Integer.tag_default,
1070 integers(min_value=31),
1071 integers(min_value=0),
1074 def test_bad_tag(self, tag, offset, decode_path):
1075 with self.assertRaises(DecodeError) as err:
1077 tag_encode(tag)[:-1],
1079 decode_path=decode_path,
1082 self.assertEqual(err.exception.offset, offset)
1083 self.assertEqual(err.exception.decode_path, decode_path)
1086 integers(min_value=128),
1087 integers(min_value=0),
1090 def test_bad_len(self, l, offset, decode_path):
1091 with self.assertRaises(DecodeError) as err:
1093 Integer.tag_default + len_encode(l)[:-1],
1095 decode_path=decode_path,
1098 self.assertEqual(err.exception.offset, offset)
1099 self.assertEqual(err.exception.decode_path, decode_path)
1102 sets(integers(), min_size=2, max_size=2),
1103 integers(min_value=0),
1106 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1107 value, bound_min = list(sorted(ints))
1110 bounds = (bound_min, bound_min)
1111 with self.assertRaises(DecodeError) as err:
1113 Integer(value).encode(),
1115 decode_path=decode_path,
1118 self.assertEqual(err.exception.offset, offset)
1119 self.assertEqual(err.exception.decode_path, decode_path)
1121 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1123 integer_values_strategy(),
1125 integers(min_value=1).map(tag_ctxc),
1126 integers(min_value=0),
1130 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
1131 for klass in (Integer, IntegerInherited):
1132 _, _, _, _, default, optional, _, _decoded = values
1141 pprint(obj, big_blobs=True, with_decode_path=True)
1142 self.assertFalse(obj.expled)
1143 obj_encoded = obj.encode()
1144 self.assertEqual(encode2pass(obj), obj_encoded)
1145 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1146 obj_expled = obj(value, expl=tag_expl)
1147 self.assertTrue(obj_expled.expled)
1149 list(obj_expled.pps())
1150 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1151 obj_expled_encoded = obj_expled.encode()
1152 obj_expled_cer = encode_cer(obj_expled)
1153 self.assertNotEqual(obj_expled_cer, obj_encoded)
1154 self.assertSequenceEqual(
1155 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1158 ctx_copied = deepcopy(ctx_dummy)
1159 obj_decoded, tail = obj_expled.decode(
1160 obj_expled_encoded + tail_junk,
1164 self.assertDictEqual(ctx_copied, ctx_dummy)
1166 list(obj_decoded.pps())
1167 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1168 self.assertEqual(tail, tail_junk)
1169 self.assertEqual(obj_decoded, obj_expled)
1170 self.assertNotEqual(obj_decoded, obj)
1171 self.assertEqual(int(obj_decoded), int(obj_expled))
1172 self.assertEqual(int(obj_decoded), int(obj))
1173 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1174 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1175 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1177 obj_decoded.expl_llen,
1178 len(len_encode(len(obj_encoded))),
1180 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1181 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1184 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1186 self.assertEqual(obj_decoded.expl_offset, offset)
1187 assert_exceeding_data(
1189 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1193 evgens = list(obj_expled.decode_evgen(
1194 obj_expled_encoded + tail_junk,
1196 decode_path=decode_path,
1199 self.assertEqual(len(evgens), 1)
1200 _decode_path, obj, tail = evgens[0]
1201 self.assertSequenceEqual(tail, tail_junk)
1202 self.assertEqual(_decode_path, decode_path)
1203 self.assertEqual(obj, obj_decoded)
1204 self.assertEqual(obj.expl_offset, offset)
1208 def test_go_vectors_valid(self):
1209 for data, expect in ((
1213 (b"\xff\x7f", -129),
1217 (b"\xff\x00", -256),
1221 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1222 (b"\x80\x00\x00\x00", -2147483648),
1225 Integer().decode(b"".join((
1226 Integer.tag_default,
1227 len_encode(len(data)),
1233 def test_go_vectors_invalid(self):
1238 with self.assertRaises(DecodeError):
1239 Integer().decode(b"".join((
1240 Integer.tag_default,
1241 len_encode(len(data)),
1247 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1250 if draw(booleans()):
1251 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1253 integers(min_value=0, max_value=255),
1254 min_size=len(schema),
1255 max_size=len(schema),
1257 schema = list(zip(schema, bits))
1259 def _value(value_required):
1260 if not value_required and draw(booleans()):
1262 generation_choice = 0
1264 generation_choice = draw(sampled_from((1, 2, 3)))
1265 if generation_choice == 1 or draw(booleans()):
1266 return "'%s'B" % "".join(draw(lists(
1267 sampled_from(("0", "1")),
1268 max_size=len(schema),
1270 if generation_choice == 2 or draw(booleans()):
1271 return draw(binary(max_size=len(schema) // 8))
1272 if generation_choice == 3 or draw(booleans()):
1273 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1275 value = _value(value_required)
1276 default = _value(value_required=False)
1280 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1282 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1283 optional = draw(one_of(none(), booleans()))
1285 draw(integers(min_value=0)),
1286 draw(integers(min_value=0)),
1287 draw(integers(min_value=0)),
1289 return (schema, value, impl, expl, default, optional, _decoded)
1292 class BitStringInherited(BitString):
1296 class TestBitString(CommonMixin, TestCase):
1297 base_klass = BitString
1299 @given(lists(booleans()))
1300 def test_b_encoding(self, bits):
1301 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1302 self.assertEqual(obj.bit_len, len(bits))
1303 self.assertSequenceEqual(list(obj), bits)
1304 for i, bit in enumerate(bits):
1305 self.assertEqual(obj[i], bit)
1307 @given(lists(booleans()))
1308 def test_out_of_bounds_bits(self, bits):
1309 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1310 for i in range(len(bits), len(bits) * 2):
1311 self.assertFalse(obj[i])
1313 def test_bad_b_encoding(self):
1314 with self.assertRaises(ValueError):
1315 BitString("'010120101'B")
1318 integers(min_value=1, max_value=255),
1319 integers(min_value=1, max_value=255),
1321 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1322 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1323 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1324 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1326 class BS(BitString):
1327 schema = (("whatever", 0),)
1328 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1329 self.assertEqual(obj.bit_len, leading_zeros + 1)
1330 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1332 def test_zero_len(self):
1333 with self.assertRaises(NotEnoughData):
1334 BitString().decode(b"".join((
1335 BitString.tag_default,
1339 def test_invalid_value_type(self):
1340 with self.assertRaises(InvalidValueType) as err:
1343 with self.assertRaises(InvalidValueType) as err:
1347 def test_obj_unknown(self):
1348 with self.assertRaises(ObjUnknown) as err:
1349 BitString(b"whatever")["whenever"]
1352 def test_get_invalid_type(self):
1353 with self.assertRaises(InvalidValueType) as err:
1354 BitString(b"whatever")[(1, 2, 3)]
1357 @given(data_strategy())
1358 def test_unknown_name(self, d):
1359 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1360 missing = _schema.pop()
1362 class BS(BitString):
1363 schema = [(n, i) for i, n in enumerate(_schema)]
1364 with self.assertRaises(ObjUnknown) as err:
1369 def test_optional(self, optional):
1370 obj = BitString(default=BitString(b""), optional=optional)
1371 self.assertTrue(obj.optional)
1374 def test_ready(self, value):
1376 self.assertFalse(obj.ready)
1379 pprint(obj, big_blobs=True, with_decode_path=True)
1380 with self.assertRaises(ObjNotReady) as err:
1383 with self.assertRaises(ObjNotReady) as err:
1385 obj = BitString(value)
1386 self.assertTrue(obj.ready)
1389 pprint(obj, big_blobs=True, with_decode_path=True)
1392 tuples(integers(min_value=0), binary()),
1393 tuples(integers(min_value=0), binary()),
1397 def test_comparison(self, value1, value2, tag1, tag2):
1398 for klass in (BitString, BitStringInherited):
1399 obj1 = klass(value1)
1400 obj2 = klass(value2)
1401 self.assertEqual(obj1 == obj2, value1 == value2)
1402 self.assertEqual(obj1 != obj2, value1 != value2)
1403 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1404 obj1 = klass(value1, impl=tag1)
1405 obj2 = klass(value1, impl=tag2)
1406 self.assertEqual(obj1 == obj2, tag1 == tag2)
1407 self.assertEqual(obj1 != obj2, tag1 != tag2)
1409 @given(data_strategy())
1410 def test_call(self, d):
1411 for klass in (BitString, BitStringInherited):
1420 ) = d.draw(bit_string_values_strategy())
1423 schema = schema_initial
1425 value=value_initial,
1428 default=default_initial,
1429 optional=optional_initial or False,
1430 _decoded=_decoded_initial,
1440 ) = d.draw(bit_string_values_strategy(
1441 schema=schema_initial,
1442 do_expl=impl_initial is None,
1451 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1452 self.assertEqual(obj.expl_tag, expl or expl_initial)
1453 if obj.default is None:
1454 optional = optional_initial if optional is None else optional
1455 optional = False if optional is None else optional
1458 self.assertEqual(obj.optional, optional)
1459 self.assertEqual(obj.specs, obj_initial.specs)
1461 @given(bit_string_values_strategy())
1462 def test_copy(self, values):
1463 for klass in (BitString, BitStringInherited):
1464 _schema, value, impl, expl, default, optional, _decoded = values
1474 optional=optional or False,
1477 for copy_func in copy_funcs:
1478 obj_copied = copy_func(obj)
1479 self.assert_copied_basic_fields(obj, obj_copied)
1480 self.assertEqual(obj.specs, obj_copied.specs)
1481 self.assertEqual(obj._value, obj_copied._value)
1485 integers(min_value=1).map(tag_encode),
1487 def test_stripped(self, value, tag_impl):
1488 obj = BitString(value, impl=tag_impl)
1489 with self.assertRaises(NotEnoughData):
1490 obj.decode(obj.encode()[:-1])
1494 integers(min_value=1).map(tag_ctxc),
1496 def test_stripped_expl(self, value, tag_expl):
1497 obj = BitString(value, expl=tag_expl)
1498 with self.assertRaises(NotEnoughData):
1499 obj.decode(obj.encode()[:-1])
1502 integers(min_value=31),
1503 integers(min_value=0),
1506 def test_bad_tag(self, tag, offset, decode_path):
1507 with self.assertRaises(DecodeError) as err:
1509 tag_encode(tag)[:-1],
1511 decode_path=decode_path,
1514 self.assertEqual(err.exception.offset, offset)
1515 self.assertEqual(err.exception.decode_path, decode_path)
1518 integers(min_value=128),
1519 integers(min_value=0),
1522 def test_bad_len(self, l, offset, decode_path):
1523 with self.assertRaises(DecodeError) as err:
1525 BitString.tag_default + len_encode(l)[:-1],
1527 decode_path=decode_path,
1530 self.assertEqual(err.exception.offset, offset)
1531 self.assertEqual(err.exception.decode_path, decode_path)
1533 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1534 @given(data_strategy())
1535 def test_symmetric(self, d):
1544 ) = d.draw(bit_string_values_strategy(value_required=True))
1545 tail_junk = d.draw(binary(max_size=5))
1546 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1547 offset = d.draw(integers(min_value=0))
1548 decode_path = d.draw(decode_path_strat)
1549 for klass in (BitString, BitStringInherited):
1560 pprint(obj, big_blobs=True, with_decode_path=True)
1561 self.assertFalse(obj.expled)
1562 obj_encoded = obj.encode()
1563 self.assertEqual(encode2pass(obj), obj_encoded)
1564 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1565 obj_expled = obj(value, expl=tag_expl)
1566 self.assertTrue(obj_expled.expled)
1568 list(obj_expled.pps())
1569 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1570 obj_expled_encoded = obj_expled.encode()
1571 obj_expled_cer = encode_cer(obj_expled)
1572 self.assertNotEqual(obj_expled_cer, obj_encoded)
1573 self.assertSequenceEqual(
1574 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1577 ctx_copied = deepcopy(ctx_dummy)
1578 obj_decoded, tail = obj_expled.decode(
1579 obj_expled_encoded + tail_junk,
1583 self.assertDictEqual(ctx_copied, ctx_dummy)
1585 list(obj_decoded.pps())
1586 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1587 self.assertEqual(tail, tail_junk)
1588 self.assertEqual(obj_decoded, obj_expled)
1589 self.assertNotEqual(obj_decoded, obj)
1590 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1591 self.assertEqual(bytes(obj_decoded), bytes(obj))
1592 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1593 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1594 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1596 obj_decoded.expl_llen,
1597 len(len_encode(len(obj_encoded))),
1599 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1600 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1603 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1605 self.assertEqual(obj_decoded.expl_offset, offset)
1606 if isinstance(value, tuple):
1607 self.assertSetEqual(set(value), set(obj_decoded.named))
1610 assert_exceeding_data(
1612 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1616 evgens = list(obj_expled.decode_evgen(
1617 obj_expled_encoded + tail_junk,
1619 decode_path=decode_path,
1622 self.assertEqual(len(evgens), 1)
1623 _decode_path, obj, tail = evgens[0]
1624 self.assertSequenceEqual(tail, tail_junk)
1625 self.assertEqual(_decode_path, decode_path)
1626 self.assertEqual(obj.expl_offset, offset)
1630 @given(integers(min_value=1, max_value=255))
1631 def test_bad_zero_value(self, pad_size):
1632 with self.assertRaises(DecodeError):
1633 BitString().decode(b"".join((
1634 BitString.tag_default,
1639 def test_go_vectors_invalid(self):
1645 with self.assertRaises(DecodeError):
1646 BitString().decode(b"".join((
1647 BitString.tag_default,
1652 def test_go_vectors_valid(self):
1653 obj, _ = BitString().decode(b"".join((
1654 BitString.tag_default,
1658 self.assertEqual(bytes(obj), b"")
1659 self.assertEqual(obj.bit_len, 0)
1661 obj, _ = BitString().decode(b"".join((
1662 BitString.tag_default,
1666 self.assertEqual(bytes(obj), b"\x00")
1667 self.assertEqual(obj.bit_len, 1)
1669 obj = BitString((16, b"\x82\x40"))
1670 self.assertTrue(obj[0])
1671 self.assertFalse(obj[1])
1672 self.assertTrue(obj[6])
1673 self.assertTrue(obj[9])
1674 self.assertFalse(obj[17])
1676 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1678 integers(min_value=1, max_value=30),
1681 binary(min_size=1, max_size=5),
1683 binary(min_size=1, max_size=5),
1691 lists(booleans(), min_size=1),
1695 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk, decode_path):
1696 def chunk_constructed(contents):
1698 tag_encode(form=TagFormConstructed, num=3) +
1700 b"".join(BitString(content).encode() for content in contents) +
1704 chunks_len_expected = []
1705 payload_expected = b""
1706 bit_len_expected = 0
1707 for chunk_input in chunk_inputs:
1708 if isinstance(chunk_input, bytes):
1709 chunks.append(BitString(chunk_input).encode())
1710 payload_expected += chunk_input
1711 bit_len_expected += len(chunk_input) * 8
1712 chunks_len_expected.append(len(chunk_input) + 1)
1714 chunks.append(chunk_constructed(chunk_input))
1715 payload = b"".join(chunk_input)
1716 payload_expected += payload
1717 bit_len_expected += len(payload) * 8
1718 for c in chunk_input:
1719 chunks_len_expected.append(len(c) + 1)
1720 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
1721 chunk_last = BitString("'%s'B" % "".join(
1722 "1" if bit else "0" for bit in chunk_last_bits
1724 chunks_len_expected.append(BitString().decod(chunk_last.encode()).vlen)
1725 payload_expected += bytes(chunk_last)
1726 bit_len_expected += chunk_last.bit_len
1727 encoded_indefinite = (
1728 tag_encode(form=TagFormConstructed, num=impl) +
1731 chunk_last.encode() +
1734 encoded_definite = (
1735 tag_encode(form=TagFormConstructed, num=impl) +
1736 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1740 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
1741 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1742 for lenindef_expected, encoded in (
1743 (True, encoded_indefinite),
1744 (False, encoded_definite),
1746 obj, tail = BitString(impl=tag_encode(impl)).decode(
1748 ctx={"bered": True},
1750 self.assertSequenceEqual(tail, junk)
1751 self.assertEqual(obj.bit_len, bit_len_expected)
1752 self.assertSequenceEqual(bytes(obj), payload_expected)
1753 self.assertTrue(obj.ber_encoded)
1754 self.assertEqual(obj.lenindef, lenindef_expected)
1755 self.assertTrue(obj.bered)
1757 self.assertTrue(obj.ber_encoded)
1758 self.assertEqual(obj.lenindef, lenindef_expected)
1759 self.assertTrue(obj.bered)
1760 self.assertEqual(len(encoded), obj.tlvlen)
1763 pprint(obj, big_blobs=True, with_decode_path=True)
1765 evgens = list(BitString(impl=tag_encode(impl)).decode_evgen(
1767 decode_path=decode_path,
1768 ctx={"bered": True},
1770 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
1771 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
1772 self.assertGreater(len(dp), len(decode_path))
1773 self.assertEqual(obj.vlen, chunk_len_expected)
1776 integers(min_value=0),
1779 def test_ber_definite_too_short(self, offset, decode_path):
1780 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
1782 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1784 decode_path=decode_path,
1785 ctx={"bered": True},
1787 self.assertEqual(err.exception.decode_path, decode_path)
1788 self.assertEqual(err.exception.offset, offset)
1791 integers(min_value=0),
1794 def test_ber_definite_no_data(self, offset, decode_path):
1795 with self.assertRaisesRegex(DecodeError, "zero length") as err:
1797 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1799 decode_path=decode_path,
1800 ctx={"bered": True},
1802 self.assertEqual(err.exception.decode_path, decode_path)
1803 self.assertEqual(err.exception.offset, offset)
1806 integers(min_value=0),
1808 integers(min_value=1, max_value=3),
1810 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1811 bs = BitString(b"data").encode()
1812 with self.assertRaises(NotEnoughData) as err:
1814 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1816 decode_path=decode_path,
1817 ctx={"bered": True},
1819 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1820 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1823 integers(min_value=0),
1825 integers(min_value=1, max_value=3),
1827 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1828 bs = BitString(b"data").encode()
1829 bs_longer = BitString(b"data-longer").encode()
1830 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
1833 tag_encode(3, form=TagFormConstructed) +
1834 len_encode((chunks + 1) * len(bs)) +
1839 decode_path=decode_path,
1840 ctx={"bered": True},
1842 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1843 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1846 integers(min_value=0),
1849 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1850 with self.assertRaisesRegex(DecodeError, "no chunks") as err:
1852 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1854 decode_path=decode_path,
1855 ctx={"bered": True},
1857 self.assertEqual(err.exception.decode_path, decode_path)
1858 self.assertEqual(err.exception.offset, offset)
1860 @given(data_strategy())
1861 def test_ber_indefinite_not_multiple(self, d):
1862 bs_short = BitString("'A'H").encode()
1863 bs_full = BitString("'AA'H").encode()
1864 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1865 chunks.append(bs_short)
1866 d.draw(permutations(chunks))
1867 chunks.append(bs_short)
1868 offset = d.draw(integers(min_value=0))
1869 decode_path = d.draw(decode_path_strat)
1870 with self.assertRaisesRegex(DecodeError, "multiple of 8 bits") as err:
1873 tag_encode(3, form=TagFormConstructed) +
1879 decode_path=decode_path,
1880 ctx={"bered": True},
1883 err.exception.decode_path,
1884 decode_path + (str(chunks.index(bs_short)),),
1887 err.exception.offset,
1888 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1891 def test_x690_vector(self):
1892 vector = BitString("'0A3B5F291CD'H")
1893 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1894 self.assertSequenceEqual(tail, b"")
1895 self.assertEqual(obj, vector)
1896 obj, tail = BitString().decode(
1897 hexdec("23800303000A3B0305045F291CD00000"),
1898 ctx={"bered": True},
1900 self.assertSequenceEqual(tail, b"")
1901 self.assertEqual(obj, vector)
1902 self.assertTrue(obj.ber_encoded)
1903 self.assertTrue(obj.lenindef)
1904 self.assertTrue(obj.bered)
1906 self.assertTrue(obj.ber_encoded)
1907 self.assertTrue(obj.lenindef)
1908 self.assertTrue(obj.bered)
1910 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1911 @given(integers(min_value=1000, max_value=3000))
1912 def test_cer(self, data_len):
1913 data = urandom(data_len)
1914 encoded = encode_cer(BitString(data))
1915 ctx = {"bered": True}
1916 self.assertSequenceEqual(bytes(BitString().decod(encoded, ctx=ctx)), data)
1917 evgens = list(BitString().decode_evgen(encoded, ctx=ctx))
1918 evgens_expected = data_len // 999
1919 if evgens_expected * 999 != data_len:
1920 evgens_expected += 1
1921 evgens_expected += 1
1922 self.assertEqual(len(evgens), evgens_expected)
1923 for (_, obj, _) in evgens[:-2]:
1924 self.assertEqual(obj.vlen, 1000)
1925 _, obj, _ = evgens[-2]
1926 self.assertEqual(obj.vlen, 1 + data_len - len(evgens[:-2]) * 999)
1930 def octet_string_values_strategy(draw, do_expl=False):
1931 bound_min, bound_max = sorted(draw(sets(
1932 integers(min_value=0, max_value=1 << 7),
1936 value = draw(one_of(
1938 binary(min_size=bound_min, max_size=bound_max),
1940 default = draw(one_of(
1942 binary(min_size=bound_min, max_size=bound_max),
1945 if draw(booleans()):
1946 bounds = (bound_min, bound_max)
1950 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1952 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1953 optional = draw(one_of(none(), booleans()))
1955 draw(integers(min_value=0)),
1956 draw(integers(min_value=0)),
1957 draw(integers(min_value=0)),
1959 return (value, bounds, impl, expl, default, optional, _decoded)
1962 class OctetStringInherited(OctetString):
1966 class TestOctetString(CommonMixin, TestCase):
1967 base_klass = OctetString
1969 def test_invalid_value_type(self):
1970 with self.assertRaises(InvalidValueType) as err:
1971 OctetString(str(123))
1975 def test_optional(self, optional):
1976 obj = OctetString(default=OctetString(b""), optional=optional)
1977 self.assertTrue(obj.optional)
1980 def test_ready(self, value):
1982 self.assertFalse(obj.ready)
1985 pprint(obj, big_blobs=True, with_decode_path=True)
1986 with self.assertRaises(ObjNotReady) as err:
1989 with self.assertRaises(ObjNotReady) as err:
1991 obj = OctetString(value)
1992 self.assertTrue(obj.ready)
1995 pprint(obj, big_blobs=True, with_decode_path=True)
1997 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1998 def test_comparison(self, value1, value2, tag1, tag2):
1999 for klass in (OctetString, OctetStringInherited):
2000 obj1 = klass(value1)
2001 obj2 = klass(value2)
2002 self.assertEqual(obj1 == obj2, value1 == value2)
2003 self.assertEqual(obj1 != obj2, value1 != value2)
2004 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2005 obj1 = klass(value1, impl=tag1)
2006 obj2 = klass(value1, impl=tag2)
2007 self.assertEqual(obj1 == obj2, tag1 == tag2)
2008 self.assertEqual(obj1 != obj2, tag1 != tag2)
2010 @given(lists(binary()))
2011 def test_sorted_works(self, values):
2012 self.assertSequenceEqual(
2013 [bytes(v) for v in sorted(OctetString(v) for v in values)],
2017 @given(data_strategy())
2018 def test_bounds_satisfied(self, d):
2019 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2020 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2021 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
2022 OctetString(value=value, bounds=(bound_min, bound_max))
2024 @given(data_strategy())
2025 def test_bounds_unsatisfied(self, d):
2026 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2027 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2028 value = d.draw(binary(max_size=bound_min - 1))
2029 with self.assertRaises(BoundsError) as err:
2030 OctetString(value=value, bounds=(bound_min, bound_max))
2032 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2033 OctetString(bounds=(bound_min, bound_max)).decode(
2034 OctetString(value).encode()
2037 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2038 OctetString(bounds=(bound_min, bound_max)).decode(
2039 encode2pass(OctetString(value))
2041 value = d.draw(binary(min_size=bound_max + 1))
2042 with self.assertRaises(BoundsError) as err:
2043 OctetString(value=value, bounds=(bound_min, bound_max))
2045 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2046 OctetString(bounds=(bound_min, bound_max)).decode(
2047 OctetString(value).encode()
2050 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2051 OctetString(bounds=(bound_min, bound_max)).decode(
2052 encode2pass(OctetString(value))
2055 @given(data_strategy())
2056 def test_call(self, d):
2057 for klass in (OctetString, OctetStringInherited):
2066 ) = d.draw(octet_string_values_strategy())
2067 obj_initial = klass(
2073 optional_initial or False,
2084 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
2085 if (default is None) and (obj_initial.default is not None):
2088 (bounds is None) and
2089 (value is not None) and
2090 (bounds_initial is not None) and
2091 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2095 (bounds is None) and
2096 (default is not None) and
2097 (bounds_initial is not None) and
2098 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2101 obj = obj_initial(value, bounds, impl, expl, default, optional)
2103 value_expected = default if value is None else value
2105 default_initial if value_expected is None
2108 self.assertEqual(obj, value_expected)
2109 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2110 self.assertEqual(obj.expl_tag, expl or expl_initial)
2113 default_initial if default is None else default,
2115 if obj.default is None:
2116 optional = optional_initial if optional is None else optional
2117 optional = False if optional is None else optional
2120 self.assertEqual(obj.optional, optional)
2122 (obj._bound_min, obj._bound_max),
2123 bounds or bounds_initial or (0, float("+inf")),
2126 @given(octet_string_values_strategy())
2127 def test_copy(self, values):
2128 for klass in (OctetString, OctetStringInherited):
2129 obj = klass(*values)
2130 for copy_func in copy_funcs:
2131 obj_copied = copy_func(obj)
2132 self.assert_copied_basic_fields(obj, obj_copied)
2133 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2134 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2135 self.assertEqual(obj._value, obj_copied._value)
2139 integers(min_value=1).map(tag_encode),
2141 def test_stripped(self, value, tag_impl):
2142 obj = OctetString(value, impl=tag_impl)
2143 with self.assertRaises(NotEnoughData):
2144 obj.decode(obj.encode()[:-1])
2148 integers(min_value=1).map(tag_ctxc),
2150 def test_stripped_expl(self, value, tag_expl):
2151 obj = OctetString(value, expl=tag_expl)
2152 with self.assertRaises(NotEnoughData):
2153 obj.decode(obj.encode()[:-1])
2156 integers(min_value=31),
2157 integers(min_value=0),
2160 def test_bad_tag(self, tag, offset, decode_path):
2161 with self.assertRaises(DecodeError) as err:
2162 OctetString().decode(
2163 tag_encode(tag)[:-1],
2165 decode_path=decode_path,
2168 self.assertEqual(err.exception.offset, offset)
2169 self.assertEqual(err.exception.decode_path, decode_path)
2172 integers(min_value=128),
2173 integers(min_value=0),
2176 def test_bad_len(self, l, offset, decode_path):
2177 with self.assertRaises(DecodeError) as err:
2178 OctetString().decode(
2179 OctetString.tag_default + len_encode(l)[:-1],
2181 decode_path=decode_path,
2184 self.assertEqual(err.exception.offset, offset)
2185 self.assertEqual(err.exception.decode_path, decode_path)
2188 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2189 integers(min_value=0),
2192 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2193 value, bound_min = list(sorted(ints))
2195 class String(OctetString):
2196 bounds = (bound_min, bound_min)
2197 with self.assertRaises(DecodeError) as err:
2199 OctetString(b"\x00" * value).encode(),
2201 decode_path=decode_path,
2204 self.assertEqual(err.exception.offset, offset)
2205 self.assertEqual(err.exception.decode_path, decode_path)
2207 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2209 octet_string_values_strategy(),
2211 integers(min_value=1).map(tag_ctxc),
2212 integers(min_value=0),
2216 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2217 for klass in (OctetString, OctetStringInherited):
2218 _, _, _, _, default, optional, _decoded = values
2227 pprint(obj, big_blobs=True, with_decode_path=True)
2228 self.assertFalse(obj.expled)
2229 obj_encoded = obj.encode()
2230 self.assertEqual(encode2pass(obj), obj_encoded)
2231 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2232 obj_expled = obj(value, expl=tag_expl)
2233 self.assertTrue(obj_expled.expled)
2235 list(obj_expled.pps())
2236 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2237 obj_expled_encoded = obj_expled.encode()
2238 obj_expled_cer = encode_cer(obj_expled)
2239 self.assertNotEqual(obj_expled_cer, obj_encoded)
2240 self.assertSequenceEqual(
2241 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2244 ctx_copied = deepcopy(ctx_dummy)
2245 obj_decoded, tail = obj_expled.decode(
2246 obj_expled_encoded + tail_junk,
2250 self.assertDictEqual(ctx_copied, ctx_dummy)
2252 list(obj_decoded.pps())
2253 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2254 self.assertEqual(tail, tail_junk)
2255 self.assertEqual(obj_decoded, obj_expled)
2256 self.assertNotEqual(obj_decoded, obj)
2257 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2258 self.assertEqual(bytes(obj_decoded), bytes(obj))
2259 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2260 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2261 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2263 obj_decoded.expl_llen,
2264 len(len_encode(len(obj_encoded))),
2266 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2267 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2270 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2272 self.assertEqual(obj_decoded.expl_offset, offset)
2273 assert_exceeding_data(
2275 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2279 evgens = list(obj_expled.decode_evgen(
2280 obj_expled_encoded + tail_junk,
2282 decode_path=decode_path,
2285 self.assertEqual(len(evgens), 1)
2286 _decode_path, obj, tail = evgens[0]
2287 self.assertSequenceEqual(tail, tail_junk)
2288 self.assertEqual(_decode_path, decode_path)
2289 self.assertEqual(obj.expl_offset, offset)
2293 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2295 integers(min_value=1, max_value=30),
2298 binary(min_size=1, max_size=5),
2300 binary(min_size=1, max_size=5),
2311 def test_constructed(self, impl, chunk_inputs, junk, decode_path):
2312 def chunk_constructed(contents):
2314 tag_encode(form=TagFormConstructed, num=4) +
2316 b"".join(OctetString(content).encode() for content in contents) +
2320 chunks_len_expected = []
2321 payload_expected = b""
2322 for chunk_input in chunk_inputs:
2323 if isinstance(chunk_input, bytes):
2324 chunks.append(OctetString(chunk_input).encode())
2325 payload_expected += chunk_input
2326 chunks_len_expected.append(len(chunk_input))
2328 chunks.append(chunk_constructed(chunk_input))
2329 payload = b"".join(chunk_input)
2330 payload_expected += payload
2331 for c in chunk_input:
2332 chunks_len_expected.append(len(c))
2333 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
2334 encoded_indefinite = (
2335 tag_encode(form=TagFormConstructed, num=impl) +
2340 encoded_definite = (
2341 tag_encode(form=TagFormConstructed, num=impl) +
2342 len_encode(len(b"".join(chunks))) +
2345 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
2346 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2347 for lenindef_expected, encoded in (
2348 (True, encoded_indefinite),
2349 (False, encoded_definite),
2351 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2353 ctx={"bered": True},
2355 self.assertSequenceEqual(tail, junk)
2356 self.assertSequenceEqual(bytes(obj), payload_expected)
2357 self.assertTrue(obj.ber_encoded)
2358 self.assertEqual(obj.lenindef, lenindef_expected)
2359 self.assertTrue(obj.bered)
2361 self.assertTrue(obj.ber_encoded)
2362 self.assertEqual(obj.lenindef, lenindef_expected)
2363 self.assertTrue(obj.bered)
2364 self.assertEqual(len(encoded), obj.tlvlen)
2367 pprint(obj, big_blobs=True, with_decode_path=True)
2369 evgens = list(OctetString(impl=tag_encode(impl)).decode_evgen(
2371 decode_path=decode_path,
2372 ctx={"bered": True},
2374 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
2375 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
2376 self.assertGreater(len(dp), len(decode_path))
2377 self.assertEqual(obj.vlen, chunk_len_expected)
2380 integers(min_value=0),
2383 def test_ber_definite_too_short(self, offset, decode_path):
2384 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
2385 OctetString().decode(
2386 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2388 decode_path=decode_path,
2389 ctx={"bered": True},
2391 self.assertEqual(err.exception.decode_path, decode_path)
2392 self.assertEqual(err.exception.offset, offset)
2395 integers(min_value=0),
2397 integers(min_value=1, max_value=3),
2399 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2400 bs = OctetString(b"data").encode()
2401 with self.assertRaises(NotEnoughData) as err:
2402 OctetString().decode(
2403 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2405 decode_path=decode_path,
2406 ctx={"bered": True},
2408 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2409 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2412 integers(min_value=0),
2414 integers(min_value=1, max_value=3),
2416 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2417 bs = OctetString(b"data").encode()
2418 bs_longer = OctetString(b"data-longer").encode()
2419 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
2420 OctetString().decode(
2422 tag_encode(4, form=TagFormConstructed) +
2423 len_encode((chunks + 1) * len(bs)) +
2428 decode_path=decode_path,
2429 ctx={"bered": True},
2431 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2432 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2434 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2435 @given(integers(min_value=1001, max_value=3000))
2436 def test_cer(self, data_len):
2437 data = urandom(data_len)
2438 encoded = encode_cer(OctetString(data))
2439 ctx = {"bered": True}
2440 self.assertSequenceEqual(bytes(OctetString().decod(encoded, ctx=ctx)), data)
2441 evgens = list(OctetString().decode_evgen(encoded, ctx=ctx))
2442 evgens_expected = data_len // 1000
2443 if evgens_expected * 1000 != data_len:
2444 evgens_expected += 1
2445 evgens_expected += 1
2446 self.assertEqual(len(evgens), evgens_expected)
2447 for (_, obj, _) in evgens[:-2]:
2448 self.assertEqual(obj.vlen, 1000)
2449 _, obj, _ = evgens[-2]
2450 self.assertEqual(obj.vlen, data_len - len(evgens[:-2]) * 1000)
2454 def null_values_strategy(draw, do_expl=False):
2458 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2460 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2461 optional = draw(one_of(none(), booleans()))
2463 draw(integers(min_value=0)),
2464 draw(integers(min_value=0)),
2465 draw(integers(min_value=0)),
2467 return (impl, expl, optional, _decoded)
2470 class NullInherited(Null):
2474 class TestNull(CommonMixin, TestCase):
2477 def test_ready(self):
2479 self.assertTrue(obj.ready)
2482 pprint(obj, big_blobs=True, with_decode_path=True)
2484 @given(binary(min_size=1), binary(min_size=1))
2485 def test_comparison(self, tag1, tag2):
2486 for klass in (Null, NullInherited):
2487 obj1 = klass(impl=tag1)
2488 obj2 = klass(impl=tag2)
2489 self.assertEqual(obj1 == obj2, tag1 == tag2)
2490 self.assertEqual(obj1 != obj2, tag1 != tag2)
2491 self.assertNotEqual(obj1, tag2)
2493 @given(data_strategy())
2494 def test_call(self, d):
2495 for klass in (Null, NullInherited):
2501 ) = d.draw(null_values_strategy())
2502 obj_initial = klass(
2505 optional=optional_initial or False,
2506 _decoded=_decoded_initial,
2513 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2514 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2515 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2516 self.assertEqual(obj.expl_tag, expl or expl_initial)
2517 optional = optional_initial if optional is None else optional
2518 optional = False if optional is None else optional
2519 self.assertEqual(obj.optional, optional)
2521 @given(null_values_strategy())
2522 def test_copy(self, values):
2523 for klass in (Null, NullInherited):
2524 impl, expl, optional, _decoded = values
2528 optional=optional or False,
2531 for copy_func in copy_funcs:
2532 obj_copied = copy_func(obj)
2533 self.assert_copied_basic_fields(obj, obj_copied)
2535 @given(integers(min_value=1).map(tag_encode))
2536 def test_stripped(self, tag_impl):
2537 obj = Null(impl=tag_impl)
2538 with self.assertRaises(NotEnoughData):
2539 obj.decode(obj.encode()[:-1])
2541 @given(integers(min_value=1).map(tag_ctxc))
2542 def test_stripped_expl(self, tag_expl):
2543 obj = Null(expl=tag_expl)
2544 with self.assertRaises(NotEnoughData):
2545 obj.decode(obj.encode()[:-1])
2548 integers(min_value=31),
2549 integers(min_value=0),
2552 def test_bad_tag(self, tag, offset, decode_path):
2553 with self.assertRaises(DecodeError) as err:
2555 tag_encode(tag)[:-1],
2557 decode_path=decode_path,
2560 self.assertEqual(err.exception.offset, offset)
2561 self.assertEqual(err.exception.decode_path, decode_path)
2564 integers(min_value=128),
2565 integers(min_value=0),
2568 def test_bad_len(self, l, offset, decode_path):
2569 with self.assertRaises(DecodeError) as err:
2571 Null.tag_default + len_encode(l)[:-1],
2573 decode_path=decode_path,
2576 self.assertEqual(err.exception.offset, offset)
2577 self.assertEqual(err.exception.decode_path, decode_path)
2579 @given(binary(min_size=1))
2580 def test_tag_mismatch(self, impl):
2581 assume(impl != Null.tag_default)
2582 with self.assertRaises(TagMismatch):
2583 Null(impl=impl).decode(Null().encode())
2586 null_values_strategy(),
2587 integers(min_value=1).map(tag_ctxc),
2588 integers(min_value=0),
2592 def test_symmetric(self, values, tag_expl, offset, tail_junk, decode_path):
2593 for klass in (Null, NullInherited):
2594 _, _, optional, _decoded = values
2595 obj = klass(optional=optional, _decoded=_decoded)
2598 pprint(obj, big_blobs=True, with_decode_path=True)
2599 self.assertFalse(obj.expled)
2600 obj_encoded = obj.encode()
2601 self.assertEqual(encode2pass(obj), obj_encoded)
2602 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2603 obj_expled = obj(expl=tag_expl)
2604 self.assertTrue(obj_expled.expled)
2606 list(obj_expled.pps())
2607 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2608 obj_expled_encoded = obj_expled.encode()
2609 obj_expled_cer = encode_cer(obj_expled)
2610 self.assertNotEqual(obj_expled_cer, obj_encoded)
2611 self.assertSequenceEqual(
2612 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2615 ctx_copied = deepcopy(ctx_dummy)
2616 obj_decoded, tail = obj_expled.decode(
2617 obj_expled_encoded + tail_junk,
2621 self.assertDictEqual(ctx_copied, ctx_dummy)
2623 list(obj_decoded.pps())
2624 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2625 self.assertEqual(tail, tail_junk)
2626 self.assertEqual(obj_decoded, obj_expled)
2627 self.assertNotEqual(obj_decoded, obj)
2628 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2629 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2630 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2632 obj_decoded.expl_llen,
2633 len(len_encode(len(obj_encoded))),
2635 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2636 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2639 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2641 self.assertEqual(obj_decoded.expl_offset, offset)
2642 assert_exceeding_data(
2644 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2648 evgens = list(obj_expled.decode_evgen(
2649 obj_expled_encoded + tail_junk,
2651 decode_path=decode_path,
2654 self.assertEqual(len(evgens), 1)
2655 _decode_path, obj, tail = evgens[0]
2656 self.assertSequenceEqual(tail, tail_junk)
2657 self.assertEqual(_decode_path, decode_path)
2658 self.assertEqual(obj, obj_decoded)
2659 self.assertEqual(obj.expl_offset, offset)
2663 @given(integers(min_value=1))
2664 def test_invalid_len(self, l):
2665 with self.assertRaises(InvalidLength):
2666 Null().decode(b"".join((
2673 def oid_strategy(draw):
2674 first_arc = draw(integers(min_value=0, max_value=2))
2676 if first_arc in (0, 1):
2677 second_arc = draw(integers(min_value=0, max_value=39))
2679 second_arc = draw(integers(min_value=0))
2680 other_arcs = draw(lists(integers(min_value=0)))
2681 return tuple([first_arc, second_arc] + other_arcs)
2685 def oid_values_strategy(draw, do_expl=False):
2686 value = draw(one_of(none(), oid_strategy()))
2690 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2692 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2693 default = draw(one_of(none(), oid_strategy()))
2694 optional = draw(one_of(none(), booleans()))
2696 draw(integers(min_value=0)),
2697 draw(integers(min_value=0)),
2698 draw(integers(min_value=0)),
2700 return (value, impl, expl, default, optional, _decoded)
2703 class ObjectIdentifierInherited(ObjectIdentifier):
2707 class TestObjectIdentifier(CommonMixin, TestCase):
2708 base_klass = ObjectIdentifier
2710 def test_invalid_value_type(self):
2711 with self.assertRaises(InvalidValueType) as err:
2712 ObjectIdentifier(123)
2716 def test_optional(self, optional):
2717 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2718 self.assertTrue(obj.optional)
2720 @given(oid_strategy())
2721 def test_ready(self, value):
2722 obj = ObjectIdentifier()
2723 self.assertFalse(obj.ready)
2726 pprint(obj, big_blobs=True, with_decode_path=True)
2727 with self.assertRaises(ObjNotReady) as err:
2730 with self.assertRaises(ObjNotReady) as err:
2732 obj = ObjectIdentifier(value)
2733 self.assertTrue(obj.ready)
2734 self.assertFalse(obj.ber_encoded)
2737 pprint(obj, big_blobs=True, with_decode_path=True)
2740 @given(oid_strategy(), oid_strategy(), binary(min_size=1), binary(min_size=1))
2741 def test_comparison(self, value1, value2, tag1, tag2):
2742 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2743 obj1 = klass(value1)
2744 obj2 = klass(value2)
2745 self.assertEqual(obj1 == obj2, value1 == value2)
2746 self.assertEqual(obj1 != obj2, value1 != value2)
2747 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2748 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2749 obj1 = klass(value1, impl=tag1)
2750 obj2 = klass(value1, impl=tag2)
2751 self.assertEqual(obj1 == obj2, tag1 == tag2)
2752 self.assertEqual(obj1 != obj2, tag1 != tag2)
2754 @given(lists(oid_strategy()))
2755 def test_sorted_works(self, values):
2756 self.assertSequenceEqual(
2757 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2761 @given(data_strategy())
2762 def test_call(self, d):
2763 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2771 ) = d.draw(oid_values_strategy())
2772 obj_initial = klass(
2773 value=value_initial,
2776 default=default_initial,
2777 optional=optional_initial or False,
2778 _decoded=_decoded_initial,
2787 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2796 value_expected = default if value is None else value
2798 default_initial if value_expected is None
2801 self.assertEqual(obj, value_expected)
2802 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2803 self.assertEqual(obj.expl_tag, expl or expl_initial)
2806 default_initial if default is None else default,
2808 if obj.default is None:
2809 optional = optional_initial if optional is None else optional
2810 optional = False if optional is None else optional
2813 self.assertEqual(obj.optional, optional)
2815 @given(oid_values_strategy())
2816 def test_copy(self, values):
2817 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2834 for copy_func in copy_funcs:
2835 obj_copied = copy_func(obj)
2836 self.assert_copied_basic_fields(obj, obj_copied)
2837 self.assertEqual(obj._value, obj_copied._value)
2839 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2842 integers(min_value=1).map(tag_encode),
2844 def test_stripped(self, value, tag_impl):
2845 obj = ObjectIdentifier(value, impl=tag_impl)
2846 with self.assertRaises(NotEnoughData):
2847 obj.decode(obj.encode()[:-1])
2851 integers(min_value=1).map(tag_ctxc),
2853 def test_stripped_expl(self, value, tag_expl):
2854 obj = ObjectIdentifier(value, expl=tag_expl)
2855 with self.assertRaises(NotEnoughData):
2856 obj.decode(obj.encode()[:-1])
2859 integers(min_value=31),
2860 integers(min_value=0),
2863 def test_bad_tag(self, tag, offset, decode_path):
2864 with self.assertRaises(DecodeError) as err:
2865 ObjectIdentifier().decode(
2866 tag_encode(tag)[:-1],
2868 decode_path=decode_path,
2871 self.assertEqual(err.exception.offset, offset)
2872 self.assertEqual(err.exception.decode_path, decode_path)
2875 integers(min_value=128),
2876 integers(min_value=0),
2879 def test_bad_len(self, l, offset, decode_path):
2880 with self.assertRaises(DecodeError) as err:
2881 ObjectIdentifier().decode(
2882 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2884 decode_path=decode_path,
2887 self.assertEqual(err.exception.offset, offset)
2888 self.assertEqual(err.exception.decode_path, decode_path)
2890 def test_zero_oid(self):
2891 with self.assertRaises(NotEnoughData):
2892 ObjectIdentifier().decode(
2893 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2896 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2897 @given(oid_strategy())
2898 def test_unfinished_oid(self, value):
2899 assume(list(value)[-1] > 255)
2900 obj_encoded = ObjectIdentifier(value).encode()
2901 obj, _ = ObjectIdentifier().decode(obj_encoded)
2902 data = obj_encoded[obj.tlen + obj.llen:-1]
2904 ObjectIdentifier.tag_default,
2905 len_encode(len(data)),
2908 with self.assertRaisesRegex(DecodeError, "unfinished OID"):
2911 @given(integers(min_value=0))
2912 def test_invalid_short(self, value):
2913 with self.assertRaises(InvalidOID):
2914 ObjectIdentifier((value,))
2915 with self.assertRaises(InvalidOID):
2916 ObjectIdentifier("%d" % value)
2918 @given(integers(min_value=3), integers(min_value=0))
2919 def test_invalid_first_arc(self, first_arc, second_arc):
2920 with self.assertRaises(InvalidOID):
2921 ObjectIdentifier((first_arc, second_arc))
2922 with self.assertRaises(InvalidOID):
2923 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2925 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2926 def test_invalid_second_arc(self, first_arc, second_arc):
2927 with self.assertRaises(InvalidOID):
2928 ObjectIdentifier((first_arc, second_arc))
2929 with self.assertRaises(InvalidOID):
2930 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2932 @given(text(alphabet=ascii_letters + ".", min_size=1))
2933 def test_junk(self, oid):
2934 with self.assertRaises(InvalidOID):
2935 ObjectIdentifier(oid)
2937 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2938 @given(oid_strategy())
2939 def test_validness(self, oid):
2940 obj = ObjectIdentifier(oid)
2941 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2944 pprint(obj, big_blobs=True, with_decode_path=True)
2946 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2948 oid_values_strategy(),
2950 integers(min_value=1).map(tag_ctxc),
2951 integers(min_value=0),
2955 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2956 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2957 _, _, _, default, optional, _decoded = values
2966 pprint(obj, big_blobs=True, with_decode_path=True)
2967 self.assertFalse(obj.expled)
2968 obj_encoded = obj.encode()
2969 self.assertEqual(encode2pass(obj), obj_encoded)
2970 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2971 obj_expled = obj(value, expl=tag_expl)
2972 self.assertTrue(obj_expled.expled)
2974 list(obj_expled.pps())
2975 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2976 obj_expled_encoded = obj_expled.encode()
2977 obj_expled_cer = encode_cer(obj_expled)
2978 self.assertNotEqual(obj_expled_cer, obj_encoded)
2979 self.assertSequenceEqual(
2980 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2983 ctx_copied = deepcopy(ctx_dummy)
2984 obj_decoded, tail = obj_expled.decode(
2985 obj_expled_encoded + tail_junk,
2989 self.assertDictEqual(ctx_copied, ctx_dummy)
2991 list(obj_decoded.pps())
2992 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2993 self.assertEqual(tail, tail_junk)
2994 self.assertEqual(obj_decoded, obj_expled)
2995 self.assertNotEqual(obj_decoded, obj)
2996 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2997 self.assertEqual(tuple(obj_decoded), tuple(obj))
2998 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2999 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3000 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3002 obj_decoded.expl_llen,
3003 len(len_encode(len(obj_encoded))),
3005 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3006 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3009 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3011 self.assertEqual(obj_decoded.expl_offset, offset)
3012 assert_exceeding_data(
3014 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3018 evgens = list(obj_expled.decode_evgen(
3019 obj_expled_encoded + tail_junk,
3021 decode_path=decode_path,
3024 self.assertEqual(len(evgens), 1)
3025 _decode_path, obj, tail = evgens[0]
3026 self.assertSequenceEqual(tail, tail_junk)
3027 self.assertEqual(_decode_path, decode_path)
3028 self.assertEqual(obj, obj_decoded)
3029 self.assertEqual(obj.expl_offset, offset)
3034 oid_strategy().map(ObjectIdentifier),
3035 oid_strategy().map(ObjectIdentifier),
3037 def test_add(self, oid1, oid2):
3038 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
3039 for oid_to_add in (oid2, tuple(oid2)):
3040 self.assertEqual(oid1 + oid_to_add, oid_expect)
3041 with self.assertRaises(InvalidValueType):
3044 def test_go_vectors_valid(self):
3045 for data, expect in (
3047 (b"\x55\x02", (2, 5, 2)),
3048 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
3049 (b"\x81\x34\x03", (2, 100, 3)),
3052 ObjectIdentifier().decode(b"".join((
3053 ObjectIdentifier.tag_default,
3054 len_encode(len(data)),
3060 def test_go_vectors_invalid(self):
3061 data = b"\x55\x02\xc0\x80\x80\x80\x80"
3062 with self.assertRaises(DecodeError):
3063 ObjectIdentifier().decode(b"".join((
3064 Integer.tag_default,
3065 len_encode(len(data)),
3069 def test_go_non_minimal_encoding(self):
3070 with self.assertRaises(DecodeError):
3071 ObjectIdentifier().decode(hexdec("060a2a80864886f70d01010b"))
3073 def test_x690_vector(self):
3075 ObjectIdentifier().decode(hexdec("0603883703"))[0],
3076 ObjectIdentifier((2, 999, 3)),
3079 def test_nonnormalized_first_arc(self):
3081 ObjectIdentifier.tag_default +
3084 ObjectIdentifier((1, 0)).encode()[-1:]
3086 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3087 self.assertTrue(obj.ber_encoded)
3088 self.assertTrue(obj.bered)
3090 self.assertTrue(obj.ber_encoded)
3091 self.assertTrue(obj.bered)
3092 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3093 ObjectIdentifier().decode(tampered)
3095 @given(data_strategy())
3096 def test_negative_arcs(self, d):
3097 oid = list(d.draw(oid_strategy()))
3100 idx = d.draw(integers(min_value=3, max_value=len(oid)))
3102 if oid[idx - 1] == 0:
3104 with self.assertRaises(InvalidOID):
3105 ObjectIdentifier(tuple(oid))
3106 with self.assertRaises(InvalidOID):
3107 ObjectIdentifier(".".join(str(i) for i in oid))
3109 @given(data_strategy())
3110 def test_plused_arcs(self, d):
3111 oid = [str(arc) for arc in d.draw(oid_strategy())]
3112 idx = d.draw(integers(min_value=0, max_value=len(oid)))
3113 oid[idx - 1] = "+" + oid[idx - 1]
3114 with self.assertRaises(InvalidOID):
3115 ObjectIdentifier(".".join(str(i) for i in oid))
3117 @given(data_strategy())
3118 def test_nonnormalized_arcs(self, d):
3119 arcs = d.draw(lists(
3120 integers(min_value=0, max_value=100),
3124 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
3125 _, _, lv = tag_strip(dered)
3126 _, _, v = len_decode(lv)
3127 v_no_first_arc = v[1:]
3128 idx_for_tamper = d.draw(integers(
3130 max_value=len(v_no_first_arc) - 1,
3132 tampered = list(bytearray(v_no_first_arc))
3133 for _ in range(d.draw(integers(min_value=1, max_value=3))):
3134 tampered.insert(idx_for_tamper, 0x80)
3135 tampered = bytes(bytearray(tampered))
3137 ObjectIdentifier.tag_default +
3138 len_encode(len(tampered)) +
3141 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3142 self.assertTrue(obj.ber_encoded)
3143 self.assertTrue(obj.bered)
3145 self.assertTrue(obj.ber_encoded)
3146 self.assertTrue(obj.bered)
3147 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3148 ObjectIdentifier().decode(tampered)
3152 def enumerated_values_strategy(draw, schema=None, do_expl=False):
3154 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
3155 values = list(draw(sets(
3157 min_size=len(schema),
3158 max_size=len(schema),
3160 schema = list(zip(schema, values))
3161 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
3165 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3167 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3168 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
3169 optional = draw(one_of(none(), booleans()))
3171 draw(integers(min_value=0)),
3172 draw(integers(min_value=0)),
3173 draw(integers(min_value=0)),
3175 return (schema, value, impl, expl, default, optional, _decoded)
3178 class TestEnumerated(CommonMixin, TestCase):
3179 class EWhatever(Enumerated):
3180 schema = (("whatever", 0),)
3182 base_klass = EWhatever
3184 def test_schema_required(self):
3185 with self.assertRaisesRegex(ValueError, "schema must be specified"):
3188 def test_invalid_value_type(self):
3189 with self.assertRaises(InvalidValueType) as err:
3190 self.base_klass((1, 2))
3193 @given(sets(text_letters(), min_size=2))
3194 def test_unknown_name(self, schema_input):
3195 missing = schema_input.pop()
3197 class E(Enumerated):
3198 schema = [(n, 123) for n in schema_input]
3199 with self.assertRaises(ObjUnknown) as err:
3204 sets(text_letters(), min_size=2),
3205 sets(integers(), min_size=2),
3207 def test_unknown_value(self, schema_input, values_input):
3209 missing_value = values_input.pop()
3210 _input = list(zip(schema_input, values_input))
3212 class E(Enumerated):
3214 with self.assertRaises(DecodeError) as err:
3219 def test_optional(self, optional):
3220 obj = self.base_klass(default="whatever", optional=optional)
3221 self.assertTrue(obj.optional)
3223 def test_ready(self):
3224 obj = self.base_klass()
3225 self.assertFalse(obj.ready)
3228 pprint(obj, big_blobs=True, with_decode_path=True)
3229 with self.assertRaises(ObjNotReady) as err:
3232 obj = self.base_klass("whatever")
3233 self.assertTrue(obj.ready)
3236 pprint(obj, big_blobs=True, with_decode_path=True)
3238 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
3239 def test_comparison(self, value1, value2, tag1, tag2):
3240 class E(Enumerated):
3242 ("whatever0", value1),
3243 ("whatever1", value2),
3246 class EInherited(E):
3248 for klass in (E, EInherited):
3249 obj1 = klass(value1)
3250 obj2 = klass(value2)
3251 self.assertEqual(obj1 == obj2, value1 == value2)
3252 self.assertEqual(obj1 != obj2, value1 != value2)
3253 self.assertEqual(obj1 == int(obj2), value1 == value2)
3254 obj1 = klass(value1, impl=tag1)
3255 obj2 = klass(value1, impl=tag2)
3256 self.assertEqual(obj1 == obj2, tag1 == tag2)
3257 self.assertEqual(obj1 != obj2, tag1 != tag2)
3259 @given(data_strategy())
3260 def test_call(self, d):
3269 ) = d.draw(enumerated_values_strategy())
3271 class E(Enumerated):
3272 schema = schema_initial
3274 value=value_initial,
3277 default=default_initial,
3278 optional=optional_initial or False,
3279 _decoded=_decoded_initial,
3289 ) = d.draw(enumerated_values_strategy(
3290 schema=schema_initial,
3291 do_expl=impl_initial is None,
3301 value_expected = default if value is None else value
3303 default_initial if value_expected is None
3308 dict(schema_initial).get(value_expected, value_expected),
3310 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3311 self.assertEqual(obj.expl_tag, expl or expl_initial)
3314 default_initial if default is None else default,
3316 if obj.default is None:
3317 optional = optional_initial if optional is None else optional
3318 optional = False if optional is None else optional
3321 self.assertEqual(obj.optional, optional)
3322 self.assertEqual(obj.specs, dict(schema_initial))
3324 @given(enumerated_values_strategy())
3325 def test_copy(self, values):
3326 schema_input, value, impl, expl, default, optional, _decoded = values
3328 class E(Enumerated):
3329 schema = schema_input
3339 for copy_func in copy_funcs:
3340 obj_copied = copy_func(obj)
3341 self.assert_copied_basic_fields(obj, obj_copied)
3342 self.assertEqual(obj.specs, obj_copied.specs)
3344 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3345 @given(data_strategy())
3346 def test_symmetric(self, d):
3347 schema_input, _, _, _, default, optional, _decoded = d.draw(
3348 enumerated_values_strategy(),
3350 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3351 offset = d.draw(integers(min_value=0))
3352 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3353 tail_junk = d.draw(binary(max_size=5))
3354 decode_path = d.draw(decode_path_strat)
3356 class E(Enumerated):
3357 schema = schema_input
3366 pprint(obj, big_blobs=True, with_decode_path=True)
3367 self.assertFalse(obj.expled)
3368 obj_encoded = obj.encode()
3369 self.assertEqual(encode2pass(obj), obj_encoded)
3370 obj_expled = obj(value, expl=tag_expl)
3371 self.assertTrue(obj_expled.expled)
3373 list(obj_expled.pps())
3374 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3375 obj_expled_encoded = obj_expled.encode()
3376 ctx_copied = deepcopy(ctx_dummy)
3377 obj_decoded, tail = obj_expled.decode(
3378 obj_expled_encoded + tail_junk,
3382 self.assertDictEqual(ctx_copied, ctx_dummy)
3384 list(obj_decoded.pps())
3385 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3386 self.assertEqual(tail, tail_junk)
3387 self.assertEqual(obj_decoded, obj_expled)
3388 self.assertNotEqual(obj_decoded, obj)
3389 self.assertEqual(int(obj_decoded), int(obj_expled))
3390 self.assertEqual(int(obj_decoded), int(obj))
3391 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3392 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3393 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3395 obj_decoded.expl_llen,
3396 len(len_encode(len(obj_encoded))),
3398 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3399 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3402 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3404 self.assertEqual(obj_decoded.expl_offset, offset)
3405 assert_exceeding_data(
3407 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3411 evgens = list(obj_expled.decode_evgen(
3412 obj_expled_encoded + tail_junk,
3414 decode_path=decode_path,
3417 self.assertEqual(len(evgens), 1)
3418 _decode_path, obj, tail = evgens[0]
3419 self.assertSequenceEqual(tail, tail_junk)
3420 self.assertEqual(_decode_path, decode_path)
3421 self.assertEqual(obj, obj_decoded)
3422 self.assertEqual(obj.expl_offset, offset)
3428 def string_values_strategy(draw, alphabet, do_expl=False):
3429 bound_min, bound_max = sorted(draw(sets(
3430 integers(min_value=0, max_value=1 << 7),
3434 value = draw(one_of(
3436 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3438 default = draw(one_of(
3440 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3443 if draw(booleans()):
3444 bounds = (bound_min, bound_max)
3448 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3450 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3451 optional = draw(one_of(none(), booleans()))
3453 draw(integers(min_value=0)),
3454 draw(integers(min_value=0)),
3455 draw(integers(min_value=0)),
3457 return (value, bounds, impl, expl, default, optional, _decoded)
3460 class StringMixin(object):
3461 def test_invalid_value_type(self):
3462 with self.assertRaises(InvalidValueType) as err:
3463 self.base_klass((1, 2))
3466 def text_alphabet(self):
3467 return "".join(chr(c) for c in range(256))
3470 def test_optional(self, optional):
3471 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3472 self.assertTrue(obj.optional)
3474 @given(data_strategy())
3475 def test_ready(self, d):
3476 obj = self.base_klass()
3477 self.assertFalse(obj.ready)
3480 pprint(obj, big_blobs=True, with_decode_path=True)
3482 with self.assertRaises(ObjNotReady) as err:
3485 with self.assertRaises(ObjNotReady) as err:
3487 value = d.draw(text(alphabet=self.text_alphabet()))
3488 obj = self.base_klass(value)
3489 self.assertTrue(obj.ready)
3492 pprint(obj, big_blobs=True, with_decode_path=True)
3495 @given(data_strategy())
3496 def test_comparison(self, d):
3497 value1 = d.draw(text(alphabet=self.text_alphabet()))
3498 value2 = d.draw(text(alphabet=self.text_alphabet()))
3499 tag1 = d.draw(binary(min_size=1))
3500 tag2 = d.draw(binary(min_size=1))
3501 obj1 = self.base_klass(value1)
3502 obj2 = self.base_klass(value2)
3503 self.assertEqual(obj1 == obj2, value1 == value2)
3504 self.assertEqual(obj1 != obj2, value1 != value2)
3505 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3506 self.assertEqual(obj1 == str(obj2), value1 == value2)
3507 obj1 = self.base_klass(value1, impl=tag1)
3508 obj2 = self.base_klass(value1, impl=tag2)
3509 self.assertEqual(obj1 == obj2, tag1 == tag2)
3510 self.assertEqual(obj1 != obj2, tag1 != tag2)
3512 @given(data_strategy())
3513 def test_bounds_satisfied(self, d):
3514 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3515 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3516 value = d.draw(text(
3517 alphabet=self.text_alphabet(),
3521 self.base_klass(value=value, bounds=(bound_min, bound_max))
3523 @given(data_strategy())
3524 def test_bounds_unsatisfied(self, d):
3525 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3526 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3527 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3528 with self.assertRaises(BoundsError) as err:
3529 self.base_klass(value=value, bounds=(bound_min, bound_max))
3531 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3532 self.base_klass(bounds=(bound_min, bound_max)).decode(
3533 self.base_klass(value).encode()
3536 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3537 self.base_klass(bounds=(bound_min, bound_max)).decode(
3538 encode2pass(self.base_klass(value))
3540 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3541 with self.assertRaises(BoundsError) as err:
3542 self.base_klass(value=value, bounds=(bound_min, bound_max))
3544 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3545 self.base_klass(bounds=(bound_min, bound_max)).decode(
3546 self.base_klass(value).encode()
3549 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3550 self.base_klass(bounds=(bound_min, bound_max)).decode(
3551 encode2pass(self.base_klass(value))
3554 @given(data_strategy())
3555 def test_call(self, d):
3564 ) = d.draw(string_values_strategy(self.text_alphabet()))
3565 obj_initial = self.base_klass(
3571 optional_initial or False,
3582 ) = d.draw(string_values_strategy(
3583 self.text_alphabet(),
3584 do_expl=impl_initial is None,
3586 if (default is None) and (obj_initial.default is not None):
3589 (bounds is None) and
3590 (value is not None) and
3591 (bounds_initial is not None) and
3592 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3596 (bounds is None) and
3597 (default is not None) and
3598 (bounds_initial is not None) and
3599 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3602 obj = obj_initial(value, bounds, impl, expl, default, optional)
3604 value_expected = default if value is None else value
3606 default_initial if value_expected is None
3609 self.assertEqual(obj, value_expected)
3610 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3611 self.assertEqual(obj.expl_tag, expl or expl_initial)
3614 default_initial if default is None else default,
3616 if obj.default is None:
3617 optional = optional_initial if optional is None else optional
3618 optional = False if optional is None else optional
3621 self.assertEqual(obj.optional, optional)
3623 (obj._bound_min, obj._bound_max),
3624 bounds or bounds_initial or (0, float("+inf")),
3627 @given(data_strategy())
3628 def test_copy(self, d):
3629 values = d.draw(string_values_strategy(self.text_alphabet()))
3630 obj = self.base_klass(*values)
3631 for copy_func in copy_funcs:
3632 obj_copied = copy_func(obj)
3633 self.assert_copied_basic_fields(obj, obj_copied)
3634 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3635 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3636 self.assertEqual(obj._value, obj_copied._value)
3638 @given(data_strategy())
3639 def test_stripped(self, d):
3640 value = d.draw(text(alphabet=self.text_alphabet()))
3641 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3642 obj = self.base_klass(value, impl=tag_impl)
3643 with self.assertRaises(NotEnoughData):
3644 obj.decode(obj.encode()[:-1])
3646 @given(data_strategy())
3647 def test_stripped_expl(self, d):
3648 value = d.draw(text(alphabet=self.text_alphabet()))
3649 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3650 obj = self.base_klass(value, expl=tag_expl)
3651 with self.assertRaises(NotEnoughData):
3652 obj.decode(obj.encode()[:-1])
3655 integers(min_value=31),
3656 integers(min_value=0),
3659 def test_bad_tag(self, tag, offset, decode_path):
3660 with self.assertRaises(DecodeError) as err:
3661 self.base_klass().decode(
3662 tag_encode(tag)[:-1],
3664 decode_path=decode_path,
3667 self.assertEqual(err.exception.offset, offset)
3668 self.assertEqual(err.exception.decode_path, decode_path)
3671 integers(min_value=128),
3672 integers(min_value=0),
3675 def test_bad_len(self, l, offset, decode_path):
3676 with self.assertRaises(DecodeError) as err:
3677 self.base_klass().decode(
3678 self.base_klass.tag_default + len_encode(l)[:-1],
3680 decode_path=decode_path,
3683 self.assertEqual(err.exception.offset, offset)
3684 self.assertEqual(err.exception.decode_path, decode_path)
3687 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3688 integers(min_value=0),
3691 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3692 value, bound_min = list(sorted(ints))
3694 class String(self.base_klass):
3695 # Multiply this value by four, to satisfy UTF-32 bounds
3696 # (4 bytes per character) validation
3697 bounds = (bound_min * 4, bound_min * 4)
3698 with self.assertRaises(DecodeError) as err:
3700 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3702 decode_path=decode_path,
3705 self.assertEqual(err.exception.offset, offset)
3706 self.assertEqual(err.exception.decode_path, decode_path)
3708 @given(data_strategy())
3709 def test_symmetric(self, d):
3710 values = d.draw(string_values_strategy(self.text_alphabet()))
3711 value = d.draw(text(alphabet=self.text_alphabet()))
3712 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3713 offset = d.draw(integers(min_value=0))
3714 tail_junk = d.draw(binary(max_size=5))
3715 decode_path = d.draw(decode_path_strat)
3716 _, _, _, _, default, optional, _decoded = values
3717 obj = self.base_klass(
3725 pprint(obj, big_blobs=True, with_decode_path=True)
3726 self.assertFalse(obj.expled)
3727 obj_encoded = obj.encode()
3728 self.assertEqual(encode2pass(obj), obj_encoded)
3729 obj_expled = obj(value, expl=tag_expl)
3730 self.assertTrue(obj_expled.expled)
3732 list(obj_expled.pps())
3733 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3734 obj_expled_encoded = obj_expled.encode()
3735 ctx_copied = deepcopy(ctx_dummy)
3736 obj_decoded, tail = obj_expled.decode(
3737 obj_expled_encoded + tail_junk,
3741 self.assertDictEqual(ctx_copied, ctx_dummy)
3743 list(obj_decoded.pps())
3744 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3745 self.assertEqual(tail, tail_junk)
3746 self.assertEqual(obj_decoded, obj_expled)
3747 self.assertNotEqual(obj_decoded, obj)
3748 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3749 self.assertEqual(bytes(obj_decoded), bytes(obj))
3750 self.assertEqual(str(obj_decoded), str(obj_expled))
3751 self.assertEqual(str(obj_decoded), str(obj))
3752 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3753 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3754 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3756 obj_decoded.expl_llen,
3757 len(len_encode(len(obj_encoded))),
3759 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3760 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3763 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3765 self.assertEqual(obj_decoded.expl_offset, offset)
3766 assert_exceeding_data(
3768 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3772 evgens = list(obj_expled.decode_evgen(
3773 obj_expled_encoded + tail_junk,
3775 decode_path=decode_path,
3778 self.assertEqual(len(evgens), 1)
3779 _decode_path, obj, tail = evgens[0]
3780 self.assertSequenceEqual(tail, tail_junk)
3781 self.assertEqual(_decode_path, decode_path)
3782 if not getattr(self, "evgen_mode_skip_value", True):
3783 self.assertEqual(obj, obj_decoded)
3784 self.assertEqual(obj.expl_offset, offset)
3789 cyrillic_letters = text(
3790 alphabet="".join(chr(i) for i in list(range(0x0410, 0x044f + 1))),
3796 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3797 base_klass = UTF8String
3799 @given(cyrillic_letters)
3800 def test_byte_per_primitive(self, chars):
3802 char_raw = char.encode("utf-8")
3803 encoded = b"".join((
3804 self.base_klass().tag_constructed,
3806 OctetString(char_raw[:1]).encode(),
3807 OctetString(char_raw[1:2]).encode(),
3811 self.base_klass().decod(encoded, ctx={"bered": True}),
3816 class UnicodeDecodeErrorMixin(object):
3817 @given(cyrillic_letters)
3818 def test_unicode_decode_error(self, cyrillic_text):
3819 with self.assertRaises(DecodeError):
3820 self.base_klass(cyrillic_text)
3823 class TestNumericString(StringMixin, CommonMixin, TestCase):
3824 base_klass = NumericString
3826 def text_alphabet(self):
3829 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3830 def test_non_numeric(self, non_numeric_text):
3831 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3832 self.base_klass(non_numeric_text)
3835 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3836 integers(min_value=0),
3839 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3840 value, bound_min = list(sorted(ints))
3842 class String(self.base_klass):
3843 bounds = (bound_min, bound_min)
3844 with self.assertRaises(DecodeError) as err:
3846 self.base_klass(b"1" * value).encode(),
3848 decode_path=decode_path,
3851 self.assertEqual(err.exception.offset, offset)
3852 self.assertEqual(err.exception.decode_path, decode_path)
3854 def test_byte_per_primitive(self):
3855 encoded = b"".join((
3856 self.base_klass().tag_constructed,
3858 OctetString(b"1").encode(),
3859 OctetString(b"2").encode(),
3863 self.base_klass().decod(encoded, ctx={"bered": True}),
3868 class TestPrintableString(
3869 UnicodeDecodeErrorMixin,
3874 base_klass = PrintableString
3876 def text_alphabet(self):
3877 return ascii_letters + digits + " '()+,-./:=?"
3879 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3880 def test_non_printable(self, non_printable_text):
3881 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3882 self.base_klass(non_printable_text)
3885 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3886 integers(min_value=0),
3889 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3890 value, bound_min = list(sorted(ints))
3892 class String(self.base_klass):
3893 bounds = (bound_min, bound_min)
3894 with self.assertRaises(DecodeError) as err:
3896 self.base_klass(b"1" * value).encode(),
3898 decode_path=decode_path,
3901 self.assertEqual(err.exception.offset, offset)
3902 self.assertEqual(err.exception.decode_path, decode_path)
3904 def test_allowable_invalid_chars(self):
3906 ("*", {"allow_asterisk": True}),
3907 ("&", {"allow_ampersand": True}),
3908 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3911 obj = self.base_klass(s)
3912 for prop in kwargs.keys():
3913 self.assertFalse(getattr(obj, prop))
3915 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3917 self.base_klass(s, **kwargs)
3918 klass = self.base_klass(**kwargs)
3920 for prop in kwargs.keys():
3921 self.assertTrue(getattr(obj, prop))
3924 for prop in kwargs.keys():
3925 self.assertTrue(getattr(obj, prop))
3928 class TestTeletexString(
3929 UnicodeDecodeErrorMixin,
3934 base_klass = TeletexString
3937 class TestVideotexString(
3938 UnicodeDecodeErrorMixin,
3943 base_klass = VideotexString
3946 class TestIA5String(
3947 UnicodeDecodeErrorMixin,
3952 base_klass = IA5String
3954 def text_alphabet(self):
3955 return "".join(chr(c) for c in range(128))
3957 @given(integers(min_value=128, max_value=255))
3958 def test_alphabet_bad(self, code):
3959 with self.assertRaises(DecodeError):
3960 self.base_klass().decod(
3961 self.base_klass.tag_default +
3963 bytes(bytearray([code])),
3967 class TestGraphicString(
3968 UnicodeDecodeErrorMixin,
3973 base_klass = GraphicString
3976 class TestVisibleString(
3977 UnicodeDecodeErrorMixin,
3982 base_klass = VisibleString
3984 def text_alphabet(self):
3985 return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
3987 def test_x690_vector(self):
3988 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3989 self.assertSequenceEqual(tail, b"")
3990 self.assertEqual(str(obj), "Jones")
3991 self.assertFalse(obj.ber_encoded)
3992 self.assertFalse(obj.lenindef)
3993 self.assertFalse(obj.bered)
3995 obj, tail = VisibleString().decode(
3996 hexdec("3A0904034A6F6E04026573"),
3997 ctx={"bered": True},
3999 self.assertSequenceEqual(tail, b"")
4000 self.assertEqual(str(obj), "Jones")
4001 self.assertTrue(obj.ber_encoded)
4002 self.assertFalse(obj.lenindef)
4003 self.assertTrue(obj.bered)
4005 self.assertTrue(obj.ber_encoded)
4006 self.assertFalse(obj.lenindef)
4007 self.assertTrue(obj.bered)
4009 obj, tail = VisibleString().decode(
4010 hexdec("3A8004034A6F6E040265730000"),
4011 ctx={"bered": True},
4013 self.assertSequenceEqual(tail, b"")
4014 self.assertEqual(str(obj), "Jones")
4015 self.assertTrue(obj.ber_encoded)
4016 self.assertTrue(obj.lenindef)
4017 self.assertTrue(obj.bered)
4019 self.assertTrue(obj.ber_encoded)
4020 self.assertTrue(obj.lenindef)
4021 self.assertTrue(obj.bered)
4024 integers(min_value=0, max_value=ord(" ") - 1),
4025 integers(min_value=ord("~") + 1, max_value=255),
4027 def test_alphabet_bad(self, code):
4028 with self.assertRaises(DecodeError):
4029 self.base_klass().decod(
4030 self.base_klass.tag_default +
4032 bytes(bytearray([code])),
4036 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
4037 integers(min_value=0),
4040 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
4041 value, bound_min = list(sorted(ints))
4043 class String(self.base_klass):
4044 bounds = (bound_min, bound_min)
4045 with self.assertRaises(DecodeError) as err:
4047 self.base_klass(b"1" * value).encode(),
4049 decode_path=decode_path,
4052 self.assertEqual(err.exception.offset, offset)
4053 self.assertEqual(err.exception.decode_path, decode_path)
4056 class TestGeneralString(
4057 UnicodeDecodeErrorMixin,
4062 base_klass = GeneralString
4065 class TestUniversalString(StringMixin, CommonMixin, TestCase):
4066 base_klass = UniversalString
4069 class TestBMPString(StringMixin, CommonMixin, TestCase):
4070 base_klass = BMPString
4074 def generalized_time_values_strategy(
4082 if draw(booleans()):
4083 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4085 value = value.replace(microsecond=0)
4087 if draw(booleans()):
4088 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4090 default = default.replace(microsecond=0)
4094 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4096 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4097 optional = draw(one_of(none(), booleans()))
4099 draw(integers(min_value=0)),
4100 draw(integers(min_value=0)),
4101 draw(integers(min_value=0)),
4103 return (value, impl, expl, default, optional, _decoded)
4106 class TimeMixin(object):
4107 def test_invalid_value_type(self):
4108 with self.assertRaises(InvalidValueType) as err:
4109 self.base_klass(datetime.now().timetuple())
4112 @given(data_strategy())
4113 def test_optional(self, d):
4114 default = d.draw(datetimes(
4115 min_value=self.min_datetime,
4116 max_value=self.max_datetime,
4118 optional = d.draw(booleans())
4119 obj = self.base_klass(default=default, optional=optional)
4120 self.assertTrue(obj.optional)
4122 @given(data_strategy())
4123 def test_ready(self, d):
4124 obj = self.base_klass()
4125 self.assertFalse(obj.ready)
4128 pprint(obj, big_blobs=True, with_decode_path=True)
4129 with self.assertRaises(ObjNotReady) as err:
4132 with self.assertRaises(ObjNotReady) as err:
4134 value = d.draw(datetimes(
4135 min_value=self.min_datetime,
4136 max_value=self.max_datetime,
4138 obj = self.base_klass(value)
4139 self.assertTrue(obj.ready)
4142 pprint(obj, big_blobs=True, with_decode_path=True)
4144 @given(data_strategy())
4145 def test_comparison(self, d):
4146 value1 = d.draw(datetimes(
4147 min_value=self.min_datetime,
4148 max_value=self.max_datetime,
4150 value2 = d.draw(datetimes(
4151 min_value=self.min_datetime,
4152 max_value=self.max_datetime,
4154 tag1 = d.draw(binary(min_size=1))
4155 tag2 = d.draw(binary(min_size=1))
4157 value1 = value1.replace(microsecond=0)
4158 value2 = value2.replace(microsecond=0)
4159 obj1 = self.base_klass(value1)
4160 obj2 = self.base_klass(value2)
4161 self.assertEqual(obj1 == obj2, value1 == value2)
4162 self.assertEqual(obj1 != obj2, value1 != value2)
4163 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
4164 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4165 obj1 = self.base_klass(value1, impl=tag1)
4166 obj2 = self.base_klass(value1, impl=tag2)
4167 self.assertEqual(obj1 == obj2, tag1 == tag2)
4168 self.assertEqual(obj1 != obj2, tag1 != tag2)
4170 @given(data_strategy())
4171 def test_call(self, d):
4179 ) = d.draw(generalized_time_values_strategy(
4180 min_datetime=self.min_datetime,
4181 max_datetime=self.max_datetime,
4182 omit_ms=self.omit_ms,
4184 obj_initial = self.base_klass(
4185 value=value_initial,
4188 default=default_initial,
4189 optional=optional_initial or False,
4190 _decoded=_decoded_initial,
4199 ) = d.draw(generalized_time_values_strategy(
4200 min_datetime=self.min_datetime,
4201 max_datetime=self.max_datetime,
4202 omit_ms=self.omit_ms,
4203 do_expl=impl_initial is None,
4213 value_expected = default if value is None else value
4215 default_initial if value_expected is None
4218 self.assertEqual(obj, value_expected)
4219 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4220 self.assertEqual(obj.expl_tag, expl or expl_initial)
4223 default_initial if default is None else default,
4225 if obj.default is None:
4226 optional = optional_initial if optional is None else optional
4227 optional = False if optional is None else optional
4230 self.assertEqual(obj.optional, optional)
4232 @given(data_strategy())
4233 def test_copy(self, d):
4234 values = d.draw(generalized_time_values_strategy(
4235 min_datetime=self.min_datetime,
4236 max_datetime=self.max_datetime,
4238 obj = self.base_klass(*values)
4239 for copy_func in copy_funcs:
4240 obj_copied = copy_func(obj)
4241 self.assert_copied_basic_fields(obj, obj_copied)
4242 self.assertEqual(obj._value, obj_copied._value)
4244 @given(data_strategy())
4245 def test_stripped(self, d):
4246 value = d.draw(datetimes(
4247 min_value=self.min_datetime,
4248 max_value=self.max_datetime,
4250 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4251 obj = self.base_klass(value, impl=tag_impl)
4252 with self.assertRaises(NotEnoughData):
4253 obj.decode(obj.encode()[:-1])
4255 @given(data_strategy())
4256 def test_stripped_expl(self, d):
4257 value = d.draw(datetimes(
4258 min_value=self.min_datetime,
4259 max_value=self.max_datetime,
4261 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4262 obj = self.base_klass(value, expl=tag_expl)
4263 with self.assertRaises(NotEnoughData):
4264 obj.decode(obj.encode()[:-1])
4266 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4267 @given(data_strategy())
4268 def test_symmetric(self, d):
4269 values = d.draw(generalized_time_values_strategy(
4270 min_datetime=self.min_datetime,
4271 max_datetime=self.max_datetime,
4273 value = d.draw(datetimes(
4274 min_value=self.min_datetime,
4275 max_value=self.max_datetime,
4277 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4278 offset = d.draw(integers(min_value=0))
4279 tail_junk = d.draw(binary(max_size=5))
4280 _, _, _, default, optional, _decoded = values
4281 obj = self.base_klass(
4289 pprint(obj, big_blobs=True, with_decode_path=True)
4290 self.assertFalse(obj.expled)
4291 obj_encoded = obj.encode()
4292 self.assertEqual(encode2pass(obj), obj_encoded)
4293 self.additional_symmetric_check(value, obj_encoded)
4294 obj_expled = obj(value, expl=tag_expl)
4295 self.assertTrue(obj_expled.expled)
4297 list(obj_expled.pps())
4298 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4299 obj_expled_encoded = obj_expled.encode()
4300 ctx_copied = deepcopy(ctx_dummy)
4301 obj_decoded, tail = obj_expled.decode(
4302 obj_expled_encoded + tail_junk,
4306 self.assertDictEqual(ctx_copied, ctx_dummy)
4308 list(obj_decoded.pps())
4309 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4310 self.assertEqual(tail, tail_junk)
4311 self.assertEqual(obj_decoded, obj_expled)
4312 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
4313 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
4314 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4315 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4316 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4318 obj_decoded.expl_llen,
4319 len(len_encode(len(obj_encoded))),
4321 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4322 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4325 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4327 self.assertEqual(obj_decoded.expl_offset, offset)
4328 assert_exceeding_data(
4330 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4335 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
4336 base_klass = GeneralizedTime
4338 min_datetime = datetime(1900, 1, 1)
4339 max_datetime = datetime(9999, 12, 31)
4340 evgen_mode_skip_value = False
4342 def additional_symmetric_check(self, value, obj_encoded):
4343 if value.microsecond > 0:
4344 self.assertFalse(obj_encoded.endswith(b"0Z"))
4346 def test_repr_not_ready(self):
4347 str(GeneralizedTime())
4348 repr(GeneralizedTime())
4350 def test_x690_vector_valid(self):
4354 b"19920722132100.3Z",
4356 GeneralizedTime(data)
4358 def test_x690_vector_invalid(self):
4361 b"19920622123421.0Z",
4362 b"19920722132100.30Z",
4364 with self.assertRaises(DecodeError) as err:
4365 GeneralizedTime(data)
4368 def test_go_vectors_invalid(self):
4380 b"-20100102030410Z",
4381 b"2010-0102030410Z",
4382 b"2010-0002030410Z",
4383 b"201001-02030410Z",
4384 b"20100102-030410Z",
4385 b"2010010203-0410Z",
4386 b"201001020304-10Z",
4387 # These ones are INVALID in *DER*, but accepted
4388 # by Go's encoding/asn1
4389 b"20100102030405+0607",
4390 b"20100102030405-0607",
4392 with self.assertRaises(DecodeError) as err:
4393 GeneralizedTime(data)
4396 def test_go_vectors_valid(self):
4398 GeneralizedTime(b"20100102030405Z").todatetime(),
4399 datetime(2010, 1, 2, 3, 4, 5, 0),
4402 def test_go_vectors_valid_ber(self):
4404 b"20100102030405+0607",
4405 b"20100102030405-0607",
4407 GeneralizedTime(data, ctx={"bered": True})
4409 def test_utc_offsets(self):
4410 """Some know equal UTC offsets
4413 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4417 "200101011130-0700",
4418 "200101011500-03:30",
4421 self.assertEqual(dts[0], dts[1])
4422 self.assertEqual(dts[0], dts[2])
4423 self.assertEqual(dts[0], dts[3])
4425 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4426 @given(data_strategy())
4427 def test_valid_ber(self, d):
4428 year = d.draw(integers(min_value=2, max_value=9999))
4429 month = d.draw(integers(min_value=1, max_value=12))
4430 day = d.draw(integers(min_value=1, max_value=28))
4431 hours = d.draw(integers(min_value=0, max_value=23))
4432 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4433 dt = datetime(year, month, day, hours)
4434 fractions_sign = d.draw(sampled_from(" ,."))
4436 if fractions_sign != " ":
4437 fractions = random()
4438 if d.draw(booleans()):
4439 minutes = d.draw(integers(min_value=0, max_value=59))
4440 data += "%02d" % minutes
4441 dt += timedelta(seconds=60 * minutes)
4442 if d.draw(booleans()):
4443 seconds = d.draw(integers(min_value=0, max_value=59))
4444 data += "%02d" % seconds
4445 dt += timedelta(seconds=seconds)
4446 if fractions is not None:
4447 dt += timedelta(microseconds=10**6 * fractions)
4448 elif fractions is not None:
4449 dt += timedelta(seconds=60 * fractions)
4450 elif fractions is not None:
4451 dt += timedelta(seconds=3600 * fractions)
4452 if fractions is not None:
4453 data += fractions_sign + str(fractions)[2:]
4454 if d.draw(booleans()):
4456 elif d.draw(booleans()):
4457 offset_hour = d.draw(integers(min_value=0, max_value=13))
4459 if d.draw(booleans()):
4464 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4465 data += "%02d" % offset_hour
4466 minutes_separator = d.draw(sampled_from((None, "", ":")))
4467 if minutes_separator is not None:
4468 offset_minute = d.draw(integers(min_value=0, max_value=59))
4469 dt -= timedelta(seconds=sign * 60 * offset_minute)
4470 data += "%s%02d" % (minutes_separator, offset_minute)
4471 data = data.encode("ascii")
4472 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4474 GeneralizedTime().decod(data_der)
4479 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4482 mktime(obj.todatetime().timetuple()),
4483 mktime(dt.timetuple()),
4487 obj.todatetime().timestamp()
4491 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4492 self.assertEqual(obj.ber_encoded, not dered)
4493 self.assertEqual(obj.bered, not dered)
4494 self.assertEqual(obj.ber_raw, None if dered else data)
4495 self.assertEqual(obj.encode() == data_der, dered)
4500 def test_invalid_ber(self):
4502 # "00010203040506.07",
4503 "-0010203040506.07",
4504 "0001-203040506.07",
4505 "000102-3040506.07",
4506 "00010203-40506.07",
4507 "0001020304-506.07",
4508 "000102030405-6.07",
4509 "00010203040506.-7",
4510 "+0010203040506.07",
4511 "0001+203040506.07",
4512 "000102+3040506.07",
4513 "00010203+40506.07",
4514 "0001020304+506.07",
4515 "000102030405+6.07",
4516 "00010203040506.+7",
4517 " 0010203040506.07",
4518 "0001 203040506.07",
4519 "000102 3040506.07",
4520 "00010203 40506.07",
4521 "0001020304 506.07",
4522 "000102030405 6.07",
4523 "00010203040506. 7",
4524 "001 0203040506.07",
4525 "00012 03040506.07",
4526 "0001023 040506.07",
4527 "000102034 0506.07",
4528 "00010203045 06.07",
4529 "0001020304056 .07",
4530 "00010203040506.7 ",
4610 "00010203040506.07+15",
4611 "00010203040506.07-15",
4612 "00010203040506.07+14:60",
4613 "00010203040506.07+1460",
4614 "00010203040506.07-1460",
4615 "00010203040506.07+00:60",
4616 "00010203040506.07-00:60",
4618 "00010203040506+15",
4619 "00010203040506-15",
4620 "00010203040506+14:60",
4621 "00010203040506+1460",
4622 "00010203040506-1460",
4623 "00010203040506+00:60",
4624 "00010203040506-00:60",
4633 with self.assertRaises(DecodeError):
4634 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4635 data = data.replace(".", ",")
4636 with self.assertRaises(DecodeError):
4637 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4641 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4642 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4644 binary(min_size=1, max_size=1),
4646 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4647 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4650 def test_junk(self, part0, part1, part2):
4651 junk = part0 + part1 + part2
4652 assume(not (set(junk) <= set(digits.encode("ascii"))))
4653 with self.assertRaises(DecodeError):
4654 GeneralizedTime().decode(
4655 GeneralizedTime.tag_default +
4656 len_encode(len(junk)) +
4662 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4663 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4665 binary(min_size=1, max_size=1),
4667 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4668 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4671 def test_junk_dm(self, part0, part1, part2):
4672 junk = part0 + part1 + part2
4673 assume(not (set(junk) <= set(digits.encode("ascii"))))
4674 with self.assertRaises(DecodeError):
4675 GeneralizedTime().decode(
4676 GeneralizedTime.tag_default +
4677 len_encode(len(junk)) +
4681 def test_ns_fractions(self):
4682 GeneralizedTime(b"20010101000000.000001Z")
4683 with self.assertRaisesRegex(DecodeError, "only microsecond fractions"):
4684 GeneralizedTime(b"20010101000000.0000001Z")
4686 def test_non_pure_integers(self):
4688 # b"20000102030405Z,
4695 b"20000102030405.+6Z",
4696 b"20000102030405.-6Z",
4703 b"20000102030405._6Z",
4704 b"20000102030405.6_Z",
4711 b"20000102030405. 6Z",
4718 b"20000102030405.6 Z",
4720 with self.assertRaises(DecodeError):
4721 GeneralizedTime(data)
4723 def test_aware(self):
4724 with self.assertRaisesRegex(ValueError, "only naive"):
4725 GeneralizedTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
4728 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4729 base_klass = UTCTime
4731 min_datetime = datetime(2000, 1, 1)
4732 max_datetime = datetime(2049, 12, 31)
4733 evgen_mode_skip_value = False
4735 def additional_symmetric_check(self, value, obj_encoded):
4738 def test_repr_not_ready(self):
4739 str(GeneralizedTime())
4742 def test_x690_vector_valid(self):
4750 def test_x690_vector_invalid(self):
4755 with self.assertRaises(DecodeError) as err:
4759 def test_go_vectors_invalid(self):
4785 # These ones are INVALID in *DER*, but accepted
4786 # by Go's encoding/asn1
4787 b"910506164540-0700",
4788 b"910506164540+0730",
4792 with self.assertRaises(DecodeError) as err:
4796 def test_go_vectors_valid(self):
4798 UTCTime(b"910506234540Z").todatetime(),
4799 datetime(1991, 5, 6, 23, 45, 40, 0),
4802 def test_non_pure_integers(self):
4831 with self.assertRaises(DecodeError):
4834 def test_x680_vector_valid_ber(self):
4836 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4837 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4838 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4839 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4841 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4842 obj = UTCTime().decod(data_der, ctx={"bered": True})
4843 self.assertEqual(obj, dt)
4844 self.assertEqual(obj.todatetime(), dt)
4845 self.assertTrue(obj.ber_encoded)
4846 self.assertTrue(obj.bered)
4847 self.assertEqual(obj.ber_raw, data)
4848 self.assertNotEqual(obj.encode(), data_der)
4851 def test_go_vectors_valid_ber(self):
4853 b"910506164540-0700",
4854 b"910506164540+0730",
4858 data = UTCTime.tag_default + len_encode(len(data)) + data
4859 obj = UTCTime().decod(data, ctx={"bered": True})
4860 self.assertTrue(obj.ber_encoded)
4861 self.assertTrue(obj.bered)
4862 self.assertNotEqual(obj.encode(), data)
4865 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4866 @given(data_strategy())
4867 def test_valid_ber(self, d):
4868 year = d.draw(integers(min_value=0, max_value=99))
4869 month = d.draw(integers(min_value=1, max_value=12))
4870 day = d.draw(integers(min_value=1, max_value=28))
4871 hours = d.draw(integers(min_value=0, max_value=23))
4872 minute = d.draw(integers(min_value=0, max_value=59))
4873 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4875 year + (2000 if year < 50 else 1900),
4882 if d.draw(booleans()):
4884 seconds = d.draw(integers(min_value=0, max_value=59))
4885 data += "%02d" % seconds
4886 dt += timedelta(seconds=seconds)
4887 if d.draw(booleans()):
4891 offset_hour = d.draw(integers(min_value=0, max_value=13))
4892 offset_minute = d.draw(integers(min_value=0, max_value=59))
4893 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4894 if d.draw(booleans()):
4900 data += "%02d%02d" % (offset_hour, offset_minute)
4901 data = data.encode("ascii")
4902 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4903 obj = UTCTime().decod(data_der, ctx={"bered": True})
4904 self.assertEqual(obj, dt)
4905 self.assertEqual(obj.todatetime(), dt)
4906 self.assertEqual(obj.ber_encoded, not dered)
4907 self.assertEqual(obj.bered, not dered)
4908 self.assertEqual(obj.ber_raw, None if dered else data)
4909 self.assertEqual(obj.encode() == data_der, dered)
4914 def test_invalid_ber(self):
4955 b"0001020304+0000Z",
4964 with self.assertRaises(DecodeError):
4965 UTCTime(data, ctx={"bered": True})
4966 data = data[:8] + data[8+2:]
4967 with self.assertRaises(DecodeError):
4968 UTCTime(data, ctx={"bered": True})
5013 b"000102030405+000",
5014 b"000102030405+000Z",
5015 b"000102030405+0000Z",
5016 b"000102030405+-101",
5017 b"000102030405+01-1",
5018 b"000102030405+0060",
5019 b"000102030405+1401",
5020 b"500101000002+0003",
5022 with self.assertRaises(DecodeError):
5023 UTCTime(data, ctx={"bered": True})
5025 @given(integers(min_value=0, max_value=49))
5026 def test_pre50(self, year):
5028 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5032 @given(integers(min_value=50, max_value=99))
5033 def test_post50(self, year):
5035 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5041 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5042 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5044 binary(min_size=1, max_size=1),
5046 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5047 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5050 def test_junk(self, part0, part1, part2):
5051 junk = part0 + part1 + part2
5052 assume(not (set(junk) <= set(digits.encode("ascii"))))
5053 with self.assertRaises(DecodeError):
5055 UTCTime.tag_default +
5056 len_encode(len(junk)) +
5060 def test_aware(self):
5061 with self.assertRaisesRegex(ValueError, "only naive"):
5062 UTCTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
5066 def tlv_value_strategy(draw):
5067 tag_num = draw(integers(min_value=1))
5068 data = draw(binary())
5069 return b"".join((tag_encode(tag_num), len_encode(len(data)), data))
5073 def any_values_strategy(draw, do_expl=False):
5074 value = draw(one_of(none(), tlv_value_strategy()))
5077 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5078 optional = draw(one_of(none(), booleans()))
5080 draw(integers(min_value=0)),
5081 draw(integers(min_value=0)),
5082 draw(integers(min_value=0)),
5084 return (value, expl, optional, _decoded)
5087 class AnyInherited(Any):
5091 class TestAny(CommonMixin, TestCase):
5094 def test_invalid_value_type(self):
5095 with self.assertRaises(InvalidValueType) as err:
5100 def test_optional(self, optional):
5101 obj = Any(optional=optional)
5102 self.assertEqual(obj.optional, optional)
5104 @given(tlv_value_strategy())
5105 def test_ready(self, value):
5107 self.assertFalse(obj.ready)
5110 pprint(obj, big_blobs=True, with_decode_path=True)
5111 with self.assertRaises(ObjNotReady) as err:
5114 with self.assertRaises(ObjNotReady) as err:
5117 self.assertTrue(obj.ready)
5120 pprint(obj, big_blobs=True, with_decode_path=True)
5123 def test_basic(self, value):
5124 integer_encoded = Integer(value).encode()
5126 Any(integer_encoded),
5127 Any(Integer(value)),
5128 Any(Any(Integer(value))),
5130 self.assertSequenceEqual(bytes(obj), integer_encoded)
5132 obj.decode(obj.encode())[0].vlen,
5133 len(integer_encoded),
5137 pprint(obj, big_blobs=True, with_decode_path=True)
5138 self.assertSequenceEqual(obj.encode(), integer_encoded)
5140 @given(tlv_value_strategy(), tlv_value_strategy())
5141 def test_comparison(self, value1, value2):
5142 for klass in (Any, AnyInherited):
5143 obj1 = klass(value1)
5144 obj2 = klass(value2)
5145 self.assertEqual(obj1 == obj2, value1 == value2)
5146 self.assertEqual(obj1 != obj2, value1 != value2)
5147 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
5149 @given(data_strategy())
5150 def test_call(self, d):
5151 for klass in (Any, AnyInherited):
5157 ) = d.draw(any_values_strategy())
5158 obj_initial = klass(
5161 optional_initial or False,
5169 ) = d.draw(any_values_strategy(do_expl=True))
5170 obj = obj_initial(value, expl, optional)
5172 value_expected = None if value is None else value
5173 self.assertEqual(obj, value_expected)
5174 self.assertEqual(obj.expl_tag, expl or expl_initial)
5175 if obj.default is None:
5176 optional = optional_initial if optional is None else optional
5177 optional = False if optional is None else optional
5178 self.assertEqual(obj.optional, optional)
5180 def test_simultaneous_impl_expl(self):
5181 # override it, as Any does not have implicit tag
5184 def test_decoded(self):
5185 # override it, as Any does not have implicit tag
5188 @given(any_values_strategy())
5189 def test_copy(self, values):
5190 for klass in (Any, AnyInherited):
5191 obj = klass(*values)
5192 for copy_func in copy_funcs:
5193 obj_copied = copy_func(obj)
5194 self.assert_copied_basic_fields(obj, obj_copied)
5195 self.assertEqual(obj._value, obj_copied._value)
5197 @given(binary().map(OctetString))
5198 def test_stripped(self, value):
5200 with self.assertRaises(NotEnoughData):
5201 obj.decode(obj.encode()[:-1])
5204 tlv_value_strategy(),
5205 integers(min_value=1).map(tag_ctxc),
5207 def test_stripped_expl(self, value, tag_expl):
5208 obj = Any(value, expl=tag_expl)
5209 with self.assertRaises(NotEnoughData):
5210 obj.decode(obj.encode()[:-1])
5213 integers(min_value=31),
5214 integers(min_value=0),
5217 def test_bad_tag(self, tag, offset, decode_path):
5218 with self.assertRaises(DecodeError) as err:
5220 tag_encode(tag)[:-1],
5222 decode_path=decode_path,
5225 self.assertEqual(err.exception.offset, offset)
5226 self.assertEqual(err.exception.decode_path, decode_path)
5229 integers(min_value=128),
5230 integers(min_value=0),
5233 def test_bad_len(self, l, offset, decode_path):
5234 with self.assertRaises(DecodeError) as err:
5236 Any.tag_default + len_encode(l)[:-1],
5238 decode_path=decode_path,
5241 self.assertEqual(err.exception.offset, offset)
5242 self.assertEqual(err.exception.decode_path, decode_path)
5244 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5246 any_values_strategy(),
5247 integers().map(lambda x: Integer(x).encode()),
5248 integers(min_value=1).map(tag_ctxc),
5249 integers(min_value=0),
5253 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
5254 for klass in (Any, AnyInherited):
5255 _, _, optional, _decoded = values
5256 obj = klass(value=value, optional=optional, _decoded=_decoded)
5259 pprint(obj, big_blobs=True, with_decode_path=True)
5260 self.assertFalse(obj.expled)
5261 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5262 self.assertEqual(obj.tag_order, (tag_class, tag_num))
5263 obj_encoded = obj.encode()
5264 self.assertEqual(encode2pass(obj), obj_encoded)
5265 obj_expled = obj(value, expl=tag_expl)
5266 self.assertTrue(obj_expled.expled)
5267 tag_class, _, tag_num = tag_decode(tag_expl)
5268 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5270 list(obj_expled.pps())
5271 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5272 obj_expled_encoded = obj_expled.encode()
5273 ctx_copied = deepcopy(ctx_dummy)
5274 obj_decoded, tail = obj_expled.decode(
5275 obj_expled_encoded + tail_junk,
5279 self.assertDictEqual(ctx_copied, ctx_dummy)
5281 list(obj_decoded.pps())
5282 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5283 self.assertEqual(tail, tail_junk)
5284 self.assertEqual(obj_decoded, obj_expled)
5285 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
5286 self.assertEqual(bytes(obj_decoded), bytes(obj))
5287 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5288 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5289 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5291 obj_decoded.expl_llen,
5292 len(len_encode(len(obj_encoded))),
5294 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5295 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5298 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5300 self.assertEqual(obj_decoded.expl_offset, offset)
5301 self.assertEqual(obj_decoded.tlen, 0)
5302 self.assertEqual(obj_decoded.llen, 0)
5303 self.assertEqual(obj_decoded.vlen, len(value))
5304 assert_exceeding_data(
5306 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5310 evgens = list(obj_expled.decode_evgen(
5311 obj_expled_encoded + tail_junk,
5313 decode_path=decode_path,
5316 self.assertEqual(len(evgens), 1)
5317 _decode_path, obj, tail = evgens[0]
5318 self.assertSequenceEqual(tail, tail_junk)
5319 self.assertEqual(_decode_path, decode_path)
5320 self.assertEqual(obj.expl_offset, offset)
5325 integers(min_value=1).map(tag_ctxc),
5326 integers(min_value=0, max_value=3),
5327 integers(min_value=0),
5331 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
5332 chunk = Boolean(False, expl=expl).encode()
5334 OctetString.tag_default +
5336 b"".join([chunk] * chunks) +
5339 with self.assertRaises(LenIndefForm):
5343 decode_path=decode_path,
5345 obj, tail = Any().decode(
5348 decode_path=decode_path,
5349 ctx={"bered": True},
5351 self.assertSequenceEqual(tail, junk)
5352 self.assertEqual(obj.offset, offset)
5353 self.assertEqual(obj.tlvlen, len(encoded))
5354 self.assertTrue(obj.lenindef)
5355 self.assertFalse(obj.ber_encoded)
5356 self.assertTrue(obj.bered)
5358 self.assertTrue(obj.lenindef)
5359 self.assertFalse(obj.ber_encoded)
5360 self.assertTrue(obj.bered)
5363 pprint(obj, big_blobs=True, with_decode_path=True)
5364 with self.assertRaises(NotEnoughData) as err:
5368 decode_path=decode_path,
5369 ctx={"bered": True},
5371 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
5372 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
5374 class SeqOf(SequenceOf):
5375 schema = Boolean(expl=expl)
5377 class Seq(Sequence):
5379 ("type", ObjectIdentifier(defines=((("value",), {
5380 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
5385 ("type", ObjectIdentifier("1.2.3")),
5386 ("value", Any(encoded)),
5388 seq_encoded = seq.encode()
5389 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5390 self.assertIsNotNone(seq_decoded["value"].defined)
5392 list(seq_decoded.pps())
5393 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5394 self.assertTrue(seq_decoded.bered)
5395 self.assertFalse(seq_decoded["type"].bered)
5396 self.assertTrue(seq_decoded["value"].bered)
5398 chunk = chunk[:-1] + b"\x01"
5399 chunks = b"".join([chunk] * (chunks + 1))
5400 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
5402 ("type", ObjectIdentifier("1.2.3")),
5403 ("value", Any(encoded)),
5405 seq_encoded = seq.encode()
5406 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5407 self.assertIsNotNone(seq_decoded["value"].defined)
5409 list(seq_decoded.pps())
5410 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5411 self.assertTrue(seq_decoded.bered)
5412 self.assertFalse(seq_decoded["type"].bered)
5413 self.assertTrue(seq_decoded["value"].bered)
5417 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
5419 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
5420 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
5422 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
5423 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
5425 min_size=len(names),
5426 max_size=len(names),
5429 (name, Integer(**tag_kwargs))
5430 for name, tag_kwargs in zip(names, tags)
5433 if value_required or draw(booleans()):
5434 value = draw(tuples(
5435 sampled_from([name for name, _ in schema]),
5436 integers().map(Integer),
5440 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5441 default = draw(one_of(
5443 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5445 optional = draw(one_of(none(), booleans()))
5447 draw(integers(min_value=0)),
5448 draw(integers(min_value=0)),
5449 draw(integers(min_value=0)),
5451 return (schema, value, expl, default, optional, _decoded)
5454 class ChoiceInherited(Choice):
5458 class TestChoice(CommonMixin, TestCase):
5460 schema = (("whatever", Boolean()),)
5463 def test_schema_required(self):
5464 with self.assertRaisesRegex(ValueError, "schema must be specified"):
5467 def test_impl_forbidden(self):
5468 with self.assertRaisesRegex(ValueError, "no implicit tag allowed"):
5469 Choice(impl=b"whatever")
5471 def test_invalid_value_type(self):
5472 with self.assertRaises(InvalidValueType) as err:
5473 self.base_klass(123)
5475 with self.assertRaises(ObjUnknown) as err:
5476 self.base_klass(("whenever", Boolean(False)))
5478 with self.assertRaises(InvalidValueType) as err:
5479 self.base_klass(("whatever", Integer(123)))
5483 def test_optional(self, optional):
5484 obj = self.base_klass(
5485 default=self.base_klass(("whatever", Boolean(False))),
5488 self.assertTrue(obj.optional)
5491 def test_ready(self, value):
5492 obj = self.base_klass()
5493 self.assertFalse(obj.ready)
5496 pprint(obj, big_blobs=True, with_decode_path=True)
5497 self.assertIsNone(obj["whatever"])
5498 with self.assertRaises(ObjNotReady) as err:
5501 with self.assertRaises(ObjNotReady) as err:
5503 obj["whatever"] = Boolean()
5504 self.assertFalse(obj.ready)
5507 pprint(obj, big_blobs=True, with_decode_path=True)
5508 obj["whatever"] = Boolean(value)
5509 self.assertTrue(obj.ready)
5512 pprint(obj, big_blobs=True, with_decode_path=True)
5514 @given(booleans(), booleans())
5515 def test_comparison(self, value1, value2):
5516 class WahlInherited(self.base_klass):
5518 for klass in (self.base_klass, WahlInherited):
5519 obj1 = klass(("whatever", Boolean(value1)))
5520 obj2 = klass(("whatever", Boolean(value2)))
5521 self.assertEqual(obj1 == obj2, value1 == value2)
5522 self.assertEqual(obj1 != obj2, value1 != value2)
5523 self.assertEqual(obj1 == obj2._value, value1 == value2)
5524 self.assertFalse(obj1 == obj2._value[1])
5526 @given(data_strategy())
5527 def test_call(self, d):
5528 for klass in (Choice, ChoiceInherited):
5536 ) = d.draw(choice_values_strategy())
5539 schema = schema_initial
5541 value=value_initial,
5543 default=default_initial,
5544 optional=optional_initial or False,
5545 _decoded=_decoded_initial,
5554 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5555 obj = obj_initial(value, expl, default, optional)
5557 value_expected = default if value is None else value
5559 default_initial if value_expected is None
5562 self.assertEqual(obj.choice, value_expected[0])
5563 self.assertEqual(obj.value, int(value_expected[1]))
5564 self.assertEqual(obj.expl_tag, expl or expl_initial)
5565 default_expect = default_initial if default is None else default
5566 if default_expect is not None:
5567 self.assertEqual(obj.default.choice, default_expect[0])
5568 self.assertEqual(obj.default.value, int(default_expect[1]))
5569 if obj.default is None:
5570 optional = optional_initial if optional is None else optional
5571 optional = False if optional is None else optional
5574 self.assertEqual(obj.optional, optional)
5575 self.assertEqual(obj.specs, obj_initial.specs)
5577 def test_simultaneous_impl_expl(self):
5578 # override it, as Any does not have implicit tag
5581 def test_decoded(self):
5582 # override it, as Any does not have implicit tag
5585 @given(choice_values_strategy())
5586 def test_copy(self, values):
5587 _schema, value, expl, default, optional, _decoded = values
5589 class Wahl(self.base_klass):
5591 register_class(Wahl)
5596 optional=optional or False,
5599 for copy_func in copy_funcs:
5600 obj_copied = copy_func(obj)
5601 self.assertIsNone(obj.tag)
5602 self.assertIsNone(obj_copied.tag)
5603 # hack for assert_copied_basic_fields
5604 obj.tag = "whatever"
5605 obj_copied.tag = "whatever"
5606 self.assert_copied_basic_fields(obj, obj_copied)
5608 self.assertEqual(obj._value, obj_copied._value)
5609 self.assertEqual(obj.specs, obj_copied.specs)
5612 def test_stripped(self, value):
5613 obj = self.base_klass(("whatever", Boolean(value)))
5614 with self.assertRaises(NotEnoughData):
5615 obj.decode(obj.encode()[:-1])
5619 integers(min_value=1).map(tag_ctxc),
5621 def test_stripped_expl(self, value, tag_expl):
5622 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5623 with self.assertRaises(NotEnoughData):
5624 obj.decode(obj.encode()[:-1])
5626 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5627 @given(data_strategy())
5628 def test_symmetric(self, d):
5629 _schema, value, _, default, optional, _decoded = d.draw(
5630 choice_values_strategy(value_required=True)
5632 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5633 offset = d.draw(integers(min_value=0))
5634 tail_junk = d.draw(binary(max_size=5))
5635 decode_path = d.draw(decode_path_strat)
5637 class Wahl(self.base_klass):
5647 pprint(obj, big_blobs=True, with_decode_path=True)
5648 self.assertFalse(obj.expled)
5649 self.assertEqual(obj.tag_order, obj.value.tag_order)
5650 obj_encoded = obj.encode()
5651 self.assertEqual(encode2pass(obj), obj_encoded)
5652 obj_expled = obj(value, expl=tag_expl)
5653 self.assertTrue(obj_expled.expled)
5654 tag_class, _, tag_num = tag_decode(tag_expl)
5655 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5657 list(obj_expled.pps())
5658 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5659 obj_expled_encoded = obj_expled.encode()
5660 ctx_copied = deepcopy(ctx_dummy)
5661 obj_decoded, tail = obj_expled.decode(
5662 obj_expled_encoded + tail_junk,
5666 self.assertDictEqual(ctx_copied, ctx_dummy)
5668 list(obj_decoded.pps())
5669 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5670 self.assertEqual(tail, tail_junk)
5671 self.assertEqual(obj_decoded, obj_expled)
5672 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5673 self.assertEqual(obj_decoded.value, obj_expled.value)
5674 self.assertEqual(obj_decoded.choice, obj.choice)
5675 self.assertEqual(obj_decoded.value, obj.value)
5676 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5677 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5678 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5680 obj_decoded.expl_llen,
5681 len(len_encode(len(obj_encoded))),
5683 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5684 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5687 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5689 self.assertEqual(obj_decoded.expl_offset, offset)
5690 self.assertSequenceEqual(
5692 obj_decoded.value.fulloffset - offset:
5693 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5697 assert_exceeding_data(
5699 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5703 evgens = list(obj_expled.decode_evgen(
5704 obj_expled_encoded + tail_junk,
5706 decode_path=decode_path,
5709 self.assertEqual(len(evgens), 2)
5710 _decode_path, obj, tail = evgens[0]
5711 self.assertEqual(_decode_path, decode_path + (obj_decoded.choice,))
5712 _decode_path, obj, tail = evgens[1]
5713 self.assertSequenceEqual(tail, tail_junk)
5714 self.assertEqual(_decode_path, decode_path)
5715 self.assertEqual(obj.expl_offset, offset)
5720 def test_set_get(self, value):
5723 ("erste", Boolean()),
5724 ("zweite", Integer()),
5727 with self.assertRaises(ObjUnknown) as err:
5728 obj["whatever"] = "whenever"
5729 with self.assertRaises(InvalidValueType) as err:
5730 obj["zweite"] = Boolean(False)
5731 obj["zweite"] = Integer(value)
5733 with self.assertRaises(ObjUnknown) as err:
5736 self.assertIsNone(obj["erste"])
5737 self.assertEqual(obj["zweite"], Integer(value))
5739 def test_tag_mismatch(self):
5742 ("erste", Boolean()),
5744 int_encoded = Integer(123).encode()
5745 bool_encoded = Boolean(False).encode()
5747 obj.decode(bool_encoded)
5748 with self.assertRaises(TagMismatch):
5749 obj.decode(int_encoded)
5751 def test_tag_mismatch_underlying(self):
5752 class SeqOfBoolean(SequenceOf):
5755 class SeqOfInteger(SequenceOf):
5760 ("erste", SeqOfBoolean()),
5763 int_encoded = SeqOfInteger((Integer(123),)).encode()
5764 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5766 obj.decode(bool_encoded)
5767 with self.assertRaises(TagMismatch) as err:
5768 obj.decode(int_encoded)
5769 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5773 def seq_values_strategy(draw, seq_klass, do_expl=False):
5775 if draw(booleans()):
5777 value._value = draw(dictionaries(
5780 booleans().map(Boolean),
5781 integers().map(Integer),
5785 if draw(booleans()):
5786 schema = list(draw(dictionaries(
5789 booleans().map(Boolean),
5790 integers().map(Integer),
5796 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5798 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5800 if draw(booleans()):
5801 default = seq_klass()
5802 default._value = draw(dictionaries(
5805 booleans().map(Boolean),
5806 integers().map(Integer),
5809 optional = draw(one_of(none(), booleans()))
5811 draw(integers(min_value=0)),
5812 draw(integers(min_value=0)),
5813 draw(integers(min_value=0)),
5815 return (value, schema, impl, expl, default, optional, _decoded)
5819 def sequence_strategy(draw, seq_klass):
5820 inputs = draw(lists(
5822 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5823 tuples(just(Integer), integers(), one_of(none(), integers())),
5828 integers(min_value=1),
5829 min_size=len(inputs),
5830 max_size=len(inputs),
5833 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5834 for tag, expled in zip(tags, draw(lists(
5836 min_size=len(inputs),
5837 max_size=len(inputs),
5841 for i, optional in enumerate(draw(lists(
5842 sampled_from(("required", "optional", "empty")),
5843 min_size=len(inputs),
5844 max_size=len(inputs),
5846 if optional in ("optional", "empty"):
5847 inits[i]["optional"] = True
5848 if optional == "empty":
5850 empties = set(empties)
5851 names = list(draw(sets(
5853 min_size=len(inputs),
5854 max_size=len(inputs),
5857 for i, (klass, value, default) in enumerate(inputs):
5858 schema.append((names[i], klass(default=default, **inits[i])))
5859 seq_name = draw(text_letters())
5860 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5863 for i, (klass, value, default) in enumerate(inputs):
5870 "default_value": None if spec.default is None else default,
5874 expect["optional"] = True
5876 expect["presented"] = True
5877 expect["value"] = value
5879 expect["optional"] = True
5880 if default is not None and default == value:
5881 expect["presented"] = False
5882 seq[name] = klass(value)
5883 expects.append(expect)
5888 def sequences_strategy(draw, seq_klass):
5889 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5891 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5892 for tag, expled in zip(tags, draw(lists(
5899 i for i, is_default in enumerate(draw(lists(
5905 names = list(draw(sets(
5910 seq_expectses = draw(lists(
5911 sequence_strategy(seq_klass=seq_klass),
5915 seqs = [seq for seq, _ in seq_expectses]
5917 for i, (name, seq) in enumerate(zip(names, seqs)):
5920 seq(default=(seq if i in defaulted else None), **inits[i]),
5922 seq_name = draw(text_letters())
5923 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5926 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5929 "expects": expects_inner,
5932 seq_outer[name] = seq_inner
5933 if seq_outer.specs[name].default is None:
5934 expect["presented"] = True
5935 expect_outers.append(expect)
5936 return seq_outer, expect_outers
5939 class SeqMixing(object):
5940 def test_invalid_value_type(self):
5941 with self.assertRaises(InvalidValueType) as err:
5942 self.base_klass(123)
5945 def test_invalid_value_type_set(self):
5946 class Seq(self.base_klass):
5947 schema = (("whatever", Boolean()),)
5949 with self.assertRaises(InvalidValueType) as err:
5950 seq["whatever"] = Integer(123)
5954 def test_optional(self, optional):
5955 obj = self.base_klass(default=self.base_klass(), optional=optional)
5956 self.assertTrue(obj.optional)
5958 @given(data_strategy())
5959 def test_ready(self, d):
5961 str(i): v for i, v in enumerate(d.draw(lists(
5968 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5975 for name in d.draw(permutations(
5976 list(ready.keys()) + list(non_ready.keys()),
5978 schema_input.append((name, Boolean()))
5980 class Seq(self.base_klass):
5981 schema = tuple(schema_input)
5983 for name in ready.keys():
5985 seq[name] = Boolean()
5986 self.assertFalse(seq.ready)
5989 pprint(seq, big_blobs=True, with_decode_path=True)
5990 for name, value in ready.items():
5991 seq[name] = Boolean(value)
5992 self.assertFalse(seq.ready)
5995 pprint(seq, big_blobs=True, with_decode_path=True)
5996 with self.assertRaises(ObjNotReady) as err:
5999 with self.assertRaises(ObjNotReady) as err:
6001 for name, value in non_ready.items():
6002 seq[name] = Boolean(value)
6003 self.assertTrue(seq.ready)
6006 pprint(seq, big_blobs=True, with_decode_path=True)
6008 @given(data_strategy())
6009 def test_call(self, d):
6010 class SeqInherited(self.base_klass):
6012 for klass in (self.base_klass, SeqInherited):
6021 ) = d.draw(seq_values_strategy(seq_klass=klass))
6022 obj_initial = klass(
6028 optional_initial or False,
6039 ) = d.draw(seq_values_strategy(
6041 do_expl=impl_initial is None,
6043 obj = obj_initial(value, impl, expl, default, optional)
6044 value_expected = default if value is None else value
6046 default_initial if value_expected is None
6049 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
6050 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6051 self.assertEqual(obj.expl_tag, expl or expl_initial)
6053 {} if obj.default is None else obj.default._value,
6054 getattr(default_initial if default is None else default, "_value", {}),
6056 if obj.default is None:
6057 optional = optional_initial if optional is None else optional
6058 optional = False if optional is None else optional
6061 self.assertEqual(list(obj.specs.items()), schema_initial or [])
6062 self.assertEqual(obj.optional, optional)
6064 @given(data_strategy())
6065 def test_copy(self, d):
6066 class SeqInherited(self.base_klass):
6068 register_class(SeqInherited)
6069 for klass in (self.base_klass, SeqInherited):
6070 values = d.draw(seq_values_strategy(seq_klass=klass))
6071 obj = klass(*values)
6072 for copy_func in copy_funcs:
6073 obj_copied = copy_func(obj)
6074 self.assert_copied_basic_fields(obj, obj_copied)
6075 self.assertEqual(obj.specs, obj_copied.specs)
6076 self.assertEqual(obj._value, obj_copied._value)
6078 @given(data_strategy())
6079 def test_stripped(self, d):
6080 value = d.draw(integers())
6081 tag_impl = tag_encode(d.draw(integers(min_value=1)))
6083 class Seq(self.base_klass):
6085 schema = (("whatever", Integer()),)
6087 seq["whatever"] = Integer(value)
6088 with self.assertRaises(NotEnoughData):
6089 seq.decode(seq.encode()[:-1])
6091 @given(data_strategy())
6092 def test_stripped_expl(self, d):
6093 value = d.draw(integers())
6094 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
6096 class Seq(self.base_klass):
6098 schema = (("whatever", Integer()),)
6100 seq["whatever"] = Integer(value)
6101 with self.assertRaises(NotEnoughData):
6102 seq.decode(seq.encode()[:-1])
6104 @given(integers(min_value=3), binary(min_size=2))
6105 def test_non_tag_mismatch_raised(self, junk_tag_num, junk):
6106 junk = tag_encode(junk_tag_num) + junk
6108 _, _, len_encoded = tag_strip(memoryview(junk))
6109 len_decode(len_encoded)
6115 class Seq(self.base_klass):
6117 ("whatever", Integer()),
6119 ("whenever", Integer()),
6122 seq["whatever"] = Integer(123)
6123 seq["junk"] = Any(junk)
6124 seq["whenever"] = Integer(123)
6125 with self.assertRaises(DecodeError):
6126 seq.decode(seq.encode())
6129 integers(min_value=31),
6130 integers(min_value=0),
6133 def test_bad_tag(self, tag, offset, decode_path):
6134 with self.assertRaises(DecodeError) as err:
6135 self.base_klass().decode(
6136 tag_encode(tag)[:-1],
6138 decode_path=decode_path,
6141 self.assertEqual(err.exception.offset, offset)
6142 self.assertEqual(err.exception.decode_path, decode_path)
6145 integers(min_value=128),
6146 integers(min_value=0),
6149 def test_bad_len(self, l, offset, decode_path):
6150 with self.assertRaises(DecodeError) as err:
6151 self.base_klass().decode(
6152 self.base_klass.tag_default + len_encode(l)[:-1],
6154 decode_path=decode_path,
6157 self.assertEqual(err.exception.offset, offset)
6158 self.assertEqual(err.exception.decode_path, decode_path)
6160 def _assert_expects(self, seq, expects):
6161 for expect in expects:
6163 seq.specs[expect["name"]].optional,
6166 if expect["default_value"] is not None:
6168 seq.specs[expect["name"]].default,
6169 expect["default_value"],
6171 if expect["presented"]:
6172 self.assertIn(expect["name"], seq)
6173 self.assertEqual(seq[expect["name"]], expect["value"])
6175 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6176 @given(data_strategy())
6177 def test_symmetric(self, d):
6178 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
6179 tail_junk = d.draw(binary(max_size=5))
6180 decode_path = d.draw(decode_path_strat)
6181 self.assertTrue(seq.ready)
6182 self.assertFalse(seq.decoded)
6183 self._assert_expects(seq, expects)
6186 pprint(seq, big_blobs=True, with_decode_path=True)
6187 self.assertTrue(seq.ready)
6188 seq_encoded = seq.encode()
6189 self.assertEqual(encode2pass(seq), seq_encoded)
6190 seq_encoded_cer = encode_cer(seq)
6191 self.assertNotEqual(seq_encoded_cer, seq_encoded)
6192 self.assertSequenceEqual(
6193 seq.decod(seq_encoded_cer, ctx={"bered": True}).encode(),
6196 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
6197 self.assertFalse(seq_decoded.lenindef)
6198 self.assertFalse(seq_decoded.ber_encoded)
6199 self.assertFalse(seq_decoded.bered)
6201 t, _, lv = tag_strip(seq_encoded)
6202 _, _, v = len_decode(lv)
6203 seq_encoded_lenindef = t + LENINDEF + v + EOC
6204 with self.assertRaises(DecodeError):
6205 seq.decode(seq_encoded_lenindef)
6206 ctx_copied = deepcopy(ctx_dummy)
6207 ctx_copied["bered"] = True
6208 seq_decoded_lenindef, tail_lenindef = seq.decode(
6209 seq_encoded_lenindef + tail_junk,
6212 del ctx_copied["bered"]
6213 self.assertDictEqual(ctx_copied, ctx_dummy)
6214 self.assertTrue(seq_decoded_lenindef.lenindef)
6215 self.assertTrue(seq_decoded_lenindef.bered)
6216 seq_decoded_lenindef = copy(seq_decoded_lenindef)
6217 self.assertTrue(seq_decoded_lenindef.lenindef)
6218 self.assertTrue(seq_decoded_lenindef.bered)
6219 with self.assertRaises(DecodeError):
6220 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
6221 with self.assertRaises(DecodeError):
6222 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
6223 repr(seq_decoded_lenindef)
6224 list(seq_decoded_lenindef.pps())
6225 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
6226 self.assertTrue(seq_decoded_lenindef.ready)
6228 for decoded, decoded_tail, encoded in (
6229 (seq_decoded, tail, seq_encoded),
6230 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
6232 self.assertEqual(decoded_tail, tail_junk)
6233 self._assert_expects(decoded, expects)
6234 self.assertEqual(seq, decoded)
6235 self.assertEqual(decoded.encode(), seq_encoded)
6236 self.assertEqual(decoded.tlvlen, len(encoded))
6237 for expect in expects:
6238 if not expect["presented"]:
6239 self.assertNotIn(expect["name"], decoded)
6241 self.assertIn(expect["name"], decoded)
6242 obj = decoded[expect["name"]]
6243 self.assertTrue(obj.decoded)
6244 offset = obj.expl_offset if obj.expled else obj.offset
6245 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6246 self.assertSequenceEqual(
6247 seq_encoded[offset:offset + tlvlen],
6251 evgens = list(seq.decode_evgen(
6252 encoded + decoded_tail,
6253 decode_path=decode_path,
6254 ctx={"bered": True},
6256 self.assertEqual(len(evgens), len(list(decoded._values_for_encoding())) + 1)
6257 for _decode_path, obj, _ in evgens[:-1]:
6258 self.assertEqual(_decode_path[:-1], decode_path)
6261 _decode_path, obj, tail = evgens[-1]
6262 self.assertEqual(_decode_path, decode_path)
6266 assert_exceeding_data(
6268 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
6272 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6273 @given(data_strategy())
6274 def test_symmetric_with_seq(self, d):
6275 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
6276 self.assertTrue(seq.ready)
6277 seq_encoded = seq.encode()
6278 self.assertEqual(encode2pass(seq), seq_encoded)
6279 seq_decoded, tail = seq.decode(seq_encoded)
6280 self.assertEqual(tail, b"")
6281 self.assertTrue(seq.ready)
6282 self.assertEqual(seq, seq_decoded)
6283 self.assertEqual(seq_decoded.encode(), seq_encoded)
6284 for expect_outer in expect_outers:
6285 if not expect_outer["presented"]:
6286 self.assertNotIn(expect_outer["name"], seq_decoded)
6288 self.assertIn(expect_outer["name"], seq_decoded)
6289 obj = seq_decoded[expect_outer["name"]]
6290 self.assertTrue(obj.decoded)
6291 offset = obj.expl_offset if obj.expled else obj.offset
6292 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6293 self.assertSequenceEqual(
6294 seq_encoded[offset:offset + tlvlen],
6297 self._assert_expects(obj, expect_outer["expects"])
6299 @given(data_strategy())
6300 def test_default_disappears(self, d):
6301 _schema = list(d.draw(dictionaries(
6303 sets(integers(), min_size=2, max_size=2),
6307 class Seq(self.base_klass):
6309 (n, Integer(default=d))
6310 for n, (_, d) in _schema
6313 for name, (value, _) in _schema:
6314 seq[name] = Integer(value)
6315 self.assertEqual(len(seq._value), len(_schema))
6316 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
6317 self.assertGreater(len(seq.encode()), len(empty_seq))
6318 for name, (_, default) in _schema:
6319 seq[name] = Integer(default)
6320 self.assertEqual(len(seq._value), 0)
6321 self.assertSequenceEqual(seq.encode(), empty_seq)
6323 @given(data_strategy())
6324 def test_encoded_default_not_accepted(self, d):
6325 _schema = list(d.draw(dictionaries(
6330 tags = [tag_encode(tag) for tag in d.draw(sets(
6331 integers(min_value=1),
6332 min_size=len(_schema),
6333 max_size=len(_schema),
6337 schema = (("int", Integer()),)
6339 class SeqWithoutDefault(self.base_klass):
6342 for (n, _), t in zip(_schema, tags)
6344 seq_without_default = SeqWithoutDefault()
6345 for name, value in _schema:
6346 seq_without_default[name] = Wahl(("int", Integer(value)))
6347 seq_encoded = seq_without_default.encode()
6348 seq_without_default.decode(seq_encoded)
6350 len(list(seq_without_default.decode_evgen(seq_encoded))),
6351 len(_schema) * 2 + 1,
6354 class SeqWithDefault(self.base_klass):
6356 (n, Wahl(default=Wahl(("int", Integer(v))), expl=t))
6357 for (n, v), t in zip(_schema, tags)
6359 seq_with_default = SeqWithDefault()
6360 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6361 seq_with_default.decode(seq_encoded)
6362 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6363 list(seq_with_default.decode_evgen(seq_encoded))
6364 for ctx in ({"bered": True}, {"allow_default_values": True}):
6365 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
6366 self.assertTrue(seq_decoded.ber_encoded)
6367 self.assertTrue(seq_decoded.bered)
6368 seq_decoded = copy(seq_decoded)
6369 self.assertTrue(seq_decoded.ber_encoded)
6370 self.assertTrue(seq_decoded.bered)
6371 for name, value in _schema:
6372 self.assertEqual(seq_decoded[name], seq_with_default[name])
6373 self.assertEqual(seq_decoded[name].value, value)
6375 len(list(seq_with_default.decode_evgen(seq_encoded, ctx=ctx))),
6379 seq_without_default = SeqWithoutDefault()
6380 for name, value in _schema:
6381 seq_without_default[name] = Wahl(("int", Integer(value + 1)))
6382 seq_encoded = seq_without_default.encode()
6383 seq_with_default.decode(seq_encoded)
6385 len(list(seq_with_default.decode_evgen(seq_encoded))),
6389 @given(data_strategy())
6390 def test_missing_from_spec(self, d):
6391 names = list(d.draw(sets(text_letters(), min_size=2)))
6392 tags = [tag_encode(tag) for tag in d.draw(sets(
6393 integers(min_value=1),
6394 min_size=len(names),
6395 max_size=len(names),
6397 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
6399 class SeqFull(self.base_klass):
6400 schema = [(n, Integer(impl=t)) for n, t in names_tags]
6401 seq_full = SeqFull()
6402 for i, name in enumerate(names):
6403 seq_full[name] = Integer(i)
6404 seq_encoded = seq_full.encode()
6405 altered = names_tags[:-2] + names_tags[-1:]
6407 class SeqMissing(self.base_klass):
6408 schema = [(n, Integer(impl=t)) for n, t in altered]
6409 seq_missing = SeqMissing()
6410 with self.assertRaises(TagMismatch):
6411 seq_missing.decode(seq_encoded)
6412 with self.assertRaises(TagMismatch):
6413 list(seq_missing.decode_evgen(seq_encoded))
6415 def test_bered(self):
6416 class Seq(self.base_klass):
6417 schema = (("underlying", Boolean()),)
6418 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
6419 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6420 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6421 self.assertFalse(decoded.ber_encoded)
6422 self.assertFalse(decoded.lenindef)
6423 self.assertTrue(decoded.bered)
6424 decoded = copy(decoded)
6425 self.assertFalse(decoded.ber_encoded)
6426 self.assertFalse(decoded.lenindef)
6427 self.assertTrue(decoded.bered)
6429 class Seq(self.base_klass):
6430 schema = (("underlying", OctetString()),)
6432 tag_encode(form=TagFormConstructed, num=4) +
6434 OctetString(b"whatever").encode() +
6437 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6438 with self.assertRaises(DecodeError):
6439 Seq().decode(encoded)
6440 with self.assertRaises(DecodeError):
6441 list(Seq().decode_evgen(encoded))
6442 list(Seq().decode_evgen(encoded, ctx={"bered": True}))
6443 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6444 self.assertFalse(decoded.ber_encoded)
6445 self.assertFalse(decoded.lenindef)
6446 self.assertTrue(decoded.bered)
6447 decoded = copy(decoded)
6448 self.assertFalse(decoded.ber_encoded)
6449 self.assertFalse(decoded.lenindef)
6450 self.assertTrue(decoded.bered)
6453 class TestSequence(SeqMixing, CommonMixin, TestCase):
6454 base_klass = Sequence
6460 def test_remaining(self, value, junk):
6461 class Seq(Sequence):
6463 ("whatever", Integer()),
6465 int_encoded = Integer(value).encode()
6467 Sequence.tag_default,
6468 len_encode(len(int_encoded + junk)),
6471 with self.assertRaisesRegex(DecodeError, "remaining"):
6472 Seq().decode(junked)
6474 @given(sets(text_letters(), min_size=2))
6475 def test_obj_unknown(self, names):
6476 missing = names.pop()
6478 class Seq(Sequence):
6479 schema = [(n, Boolean()) for n in names]
6481 with self.assertRaises(ObjUnknown) as err:
6484 with self.assertRaises(ObjUnknown) as err:
6485 seq[missing] = Boolean()
6488 def test_x690_vector(self):
6489 class Seq(Sequence):
6491 ("name", IA5String()),
6494 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
6495 self.assertEqual(seq["name"], "Smith")
6496 self.assertEqual(seq["ok"], True)
6499 class TestSet(SeqMixing, CommonMixin, TestCase):
6502 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6503 @given(data_strategy())
6504 def test_sorted(self, d):
6505 class DummySeq(Sequence):
6506 schema = (("null", Null()),)
6508 tag_nums = d.draw(sets(integers(min_value=1), min_size=1, max_size=50))
6509 _, _, dummy_seq_tag_num = tag_decode(DummySeq.tag_default)
6510 assume(any(i > dummy_seq_tag_num for i in tag_nums))
6511 tag_nums -= set([dummy_seq_tag_num])
6512 _schema = [(str(i), OctetString(impl=tag_encode(i))) for i in tag_nums]
6513 _schema.append(("seq", DummySeq()))
6516 schema = d.draw(permutations(_schema))
6518 for name, _ in _schema:
6520 seq[name] = OctetString(name.encode("ascii"))
6521 seq["seq"] = DummySeq((("null", Null()),))
6523 seq_encoded = seq.encode()
6524 seq_decoded, _ = seq.decode(seq_encoded)
6525 seq_encoded_expected = []
6526 for tag_num in sorted(tag_nums | set([dummy_seq_tag_num])):
6527 if tag_num == dummy_seq_tag_num:
6528 seq_encoded_expected.append(seq["seq"].encode())
6530 seq_encoded_expected.append(seq[str(tag_num)].encode())
6531 self.assertSequenceEqual(
6532 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6533 b"".join(seq_encoded_expected),
6536 encoded = b"".join(seq[str(i)].encode() for i in tag_nums)
6537 encoded += seq["seq"].encode()
6538 seq_encoded = b"".join((
6540 len_encode(len(encoded)),
6543 with self.assertRaisesRegex(DecodeError, "unordered SET"):
6544 seq.decode(seq_encoded)
6545 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6546 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6547 self.assertTrue(seq_decoded.ber_encoded)
6548 self.assertTrue(seq_decoded.bered)
6549 seq_decoded = copy(seq_decoded)
6550 self.assertTrue(seq_decoded.ber_encoded)
6551 self.assertTrue(seq_decoded.bered)
6553 def test_same_value_twice(self):
6556 ("bool", Boolean()),
6560 encoded = b"".join((
6561 Integer(123).encode(),
6562 Integer(234).encode(),
6563 Boolean(True).encode(),
6565 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6566 with self.assertRaises(TagMismatch):
6567 Seq().decod(encoded, ctx={"allow_unordered_set": True})
6571 def seqof_values_strategy(draw, schema=None, do_expl=False):
6573 schema = draw(sampled_from((Boolean(), Integer())))
6574 bound_min, bound_max = sorted(draw(sets(
6575 integers(min_value=0, max_value=10),
6579 if isinstance(schema, Boolean):
6580 values_generator = booleans().map(Boolean)
6581 elif isinstance(schema, Integer):
6582 values_generator = integers().map(Integer)
6583 values_generator = lists(
6588 values = draw(one_of(none(), values_generator))
6592 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6594 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6595 default = draw(one_of(none(), values_generator))
6596 optional = draw(one_of(none(), booleans()))
6598 draw(integers(min_value=0)),
6599 draw(integers(min_value=0)),
6600 draw(integers(min_value=0)),
6605 (bound_min, bound_max),
6614 class SeqOfMixing(object):
6615 def test_invalid_value_type(self):
6616 with self.assertRaises(InvalidValueType) as err:
6617 self.base_klass(123)
6620 def test_invalid_values_type(self):
6621 class SeqOf(self.base_klass):
6623 with self.assertRaises(InvalidValueType) as err:
6624 SeqOf([Integer(123), Boolean(False), Integer(234)])
6627 def test_schema_required(self):
6628 with self.assertRaisesRegex(ValueError, "schema must be specified"):
6629 self.base_klass.__mro__[1]()
6631 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6632 def test_comparison(self, value1, value2, tag1, tag2):
6633 class SeqOf(self.base_klass):
6635 obj1 = SeqOf([Boolean(value1)])
6636 obj2 = SeqOf([Boolean(value2)])
6637 self.assertEqual(obj1 == obj2, value1 == value2)
6638 self.assertEqual(obj1 != obj2, value1 != value2)
6639 self.assertEqual(obj1 == list(obj2), value1 == value2)
6640 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6641 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6642 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6643 self.assertEqual(obj1 == obj2, tag1 == tag2)
6644 self.assertEqual(obj1 != obj2, tag1 != tag2)
6646 @given(lists(booleans()))
6647 def test_iter(self, values):
6648 class SeqOf(self.base_klass):
6650 obj = SeqOf([Boolean(value) for value in values])
6651 self.assertEqual(len(obj), len(values))
6652 for i, value in enumerate(obj):
6653 self.assertEqual(value, values[i])
6655 @given(data_strategy())
6656 def test_ready(self, d):
6657 ready = [Integer(v) for v in d.draw(lists(
6664 range(d.draw(integers(min_value=1, max_value=5)))
6667 class SeqOf(self.base_klass):
6669 values = d.draw(permutations(ready + non_ready))
6671 for value in values:
6673 self.assertFalse(seqof.ready)
6676 pprint(seqof, big_blobs=True, with_decode_path=True)
6677 with self.assertRaises(ObjNotReady) as err:
6680 with self.assertRaises(ObjNotReady) as err:
6682 for i, value in enumerate(values):
6683 self.assertEqual(seqof[i], value)
6684 if not seqof[i].ready:
6685 seqof[i] = Integer(i)
6686 self.assertTrue(seqof.ready)
6689 pprint(seqof, big_blobs=True, with_decode_path=True)
6691 def test_spec_mismatch(self):
6692 class SeqOf(self.base_klass):
6695 seqof.append(Integer(123))
6696 with self.assertRaises(ValueError):
6697 seqof.append(Boolean(False))
6698 with self.assertRaises(ValueError):
6699 seqof[0] = Boolean(False)
6701 @given(data_strategy())
6702 def test_bounds_satisfied(self, d):
6703 class SeqOf(self.base_klass):
6705 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6706 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6707 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6708 SeqOf(value=value, bounds=(bound_min, bound_max))
6710 @given(data_strategy())
6711 def test_bounds_unsatisfied(self, d):
6712 class SeqOf(self.base_klass):
6714 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6715 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6716 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
6717 with self.assertRaises(BoundsError) as err:
6718 SeqOf(value=value, bounds=(bound_min, bound_max))
6720 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6721 SeqOf(bounds=(bound_min, bound_max)).decode(
6722 SeqOf(value).encode()
6725 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6726 SeqOf(bounds=(bound_min, bound_max)).decode(
6727 encode2pass(SeqOf(value))
6729 value = [Boolean(True)] * d.draw(integers(
6730 min_value=bound_max + 1,
6731 max_value=bound_max + 10,
6733 with self.assertRaises(BoundsError) as err:
6734 SeqOf(value=value, bounds=(bound_min, bound_max))
6736 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6737 SeqOf(bounds=(bound_min, bound_max)).decode(
6738 SeqOf(value).encode()
6741 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6742 SeqOf(bounds=(bound_min, bound_max)).decode(
6743 encode2pass(SeqOf(value))
6746 @given(integers(min_value=1, max_value=10))
6747 def test_out_of_bounds(self, bound_max):
6748 class SeqOf(self.base_klass):
6750 bounds = (0, bound_max)
6752 for _ in range(bound_max):
6753 seqof.append(Integer(123))
6754 with self.assertRaises(BoundsError):
6755 seqof.append(Integer(123))
6757 @given(data_strategy())
6758 def test_call(self, d):
6768 ) = d.draw(seqof_values_strategy())
6770 class SeqOf(self.base_klass):
6771 schema = schema_initial
6772 obj_initial = SeqOf(
6773 value=value_initial,
6774 bounds=bounds_initial,
6777 default=default_initial,
6778 optional=optional_initial or False,
6779 _decoded=_decoded_initial,
6790 ) = d.draw(seqof_values_strategy(
6791 schema=schema_initial,
6792 do_expl=impl_initial is None,
6794 if (default is None) and (obj_initial.default is not None):
6797 (bounds is None) and
6798 (value is not None) and
6799 (bounds_initial is not None) and
6800 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6804 (bounds is None) and
6805 (default is not None) and
6806 (bounds_initial is not None) and
6807 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6819 value_expected = default if value is None else value
6821 default_initial if value_expected is None
6824 value_expected = () if value_expected is None else value_expected
6825 self.assertEqual(obj, value_expected)
6826 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6827 self.assertEqual(obj.expl_tag, expl or expl_initial)
6830 default_initial if default is None else default,
6832 if obj.default is None:
6833 optional = optional_initial if optional is None else optional
6834 optional = False if optional is None else optional
6837 self.assertEqual(obj.optional, optional)
6839 (obj._bound_min, obj._bound_max),
6840 bounds or bounds_initial or (0, float("+inf")),
6843 @given(seqof_values_strategy())
6844 def test_copy(self, values):
6845 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6847 class SeqOf(self.base_klass):
6849 register_class(SeqOf)
6856 optional=optional or False,
6859 for copy_func in copy_funcs:
6860 obj_copied = copy_func(obj)
6861 self.assert_copied_basic_fields(obj, obj_copied)
6862 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6863 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6864 self.assertEqual(obj._value, obj_copied._value)
6868 integers(min_value=1).map(tag_encode),
6870 def test_stripped(self, values, tag_impl):
6871 class SeqOf(self.base_klass):
6872 schema = OctetString()
6873 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6874 with self.assertRaises(NotEnoughData):
6875 obj.decode(obj.encode()[:-1])
6879 integers(min_value=1).map(tag_ctxc),
6881 def test_stripped_expl(self, values, tag_expl):
6882 class SeqOf(self.base_klass):
6883 schema = OctetString()
6884 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6885 with self.assertRaises(NotEnoughData):
6886 obj.decode(obj.encode()[:-1])
6889 integers(min_value=31),
6890 integers(min_value=0),
6893 def test_bad_tag(self, tag, offset, decode_path):
6894 with self.assertRaises(DecodeError) as err:
6895 self.base_klass().decode(
6896 tag_encode(tag)[:-1],
6898 decode_path=decode_path,
6901 self.assertEqual(err.exception.offset, offset)
6902 self.assertEqual(err.exception.decode_path, decode_path)
6905 integers(min_value=128),
6906 integers(min_value=0),
6909 def test_bad_len(self, l, offset, decode_path):
6910 with self.assertRaises(DecodeError) as err:
6911 self.base_klass().decode(
6912 self.base_klass.tag_default + len_encode(l)[:-1],
6914 decode_path=decode_path,
6917 self.assertEqual(err.exception.offset, offset)
6918 self.assertEqual(err.exception.decode_path, decode_path)
6920 @given(binary(min_size=1))
6921 def test_tag_mismatch(self, impl):
6922 assume(impl != self.base_klass.tag_default)
6923 with self.assertRaises(TagMismatch):
6924 self.base_klass(impl=impl).decode(self.base_klass().encode())
6926 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6928 seqof_values_strategy(schema=Integer()),
6929 lists(integers().map(Integer)),
6930 integers(min_value=1).map(tag_ctxc),
6931 integers(min_value=0),
6935 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
6936 _, _, _, _, _, default, optional, _decoded = values
6938 class SeqOf(self.base_klass):
6948 pprint(obj, big_blobs=True, with_decode_path=True)
6949 self.assertFalse(obj.expled)
6950 obj_encoded = obj.encode()
6951 self.assertEqual(encode2pass(obj), obj_encoded)
6952 obj_encoded_cer = encode_cer(obj)
6953 self.assertNotEqual(obj_encoded_cer, obj_encoded)
6954 self.assertSequenceEqual(
6955 obj.decod(obj_encoded_cer, ctx={"bered": True}).encode(),
6958 obj_expled = obj(value, expl=tag_expl)
6959 self.assertTrue(obj_expled.expled)
6961 list(obj_expled.pps())
6962 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6963 obj_expled_encoded = obj_expled.encode()
6964 ctx_copied = deepcopy(ctx_dummy)
6965 obj_decoded, tail = obj_expled.decode(
6966 obj_expled_encoded + tail_junk,
6970 self.assertDictEqual(ctx_copied, ctx_dummy)
6972 list(obj_decoded.pps())
6973 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6974 self.assertEqual(tail, tail_junk)
6975 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6976 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6977 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6978 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6980 obj_decoded.expl_llen,
6981 len(len_encode(len(obj_encoded))),
6983 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
6984 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
6987 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
6989 self.assertEqual(obj_decoded.expl_offset, offset)
6990 for obj_inner in obj_decoded:
6991 self.assertIn(obj_inner, obj_decoded)
6992 self.assertSequenceEqual(
6995 obj_inner.offset - offset:
6996 obj_inner.offset + obj_inner.tlvlen - offset
7000 t, _, lv = tag_strip(obj_encoded)
7001 _, _, v = len_decode(lv)
7002 obj_encoded_lenindef = t + LENINDEF + v + EOC
7003 with self.assertRaises(DecodeError):
7004 obj.decode(obj_encoded_lenindef)
7005 obj_decoded_lenindef, tail_lenindef = obj.decode(
7006 obj_encoded_lenindef + tail_junk,
7007 ctx={"bered": True},
7009 self.assertTrue(obj_decoded_lenindef.lenindef)
7010 self.assertTrue(obj_decoded_lenindef.bered)
7011 obj_decoded_lenindef = copy(obj_decoded_lenindef)
7012 self.assertTrue(obj_decoded_lenindef.lenindef)
7013 self.assertTrue(obj_decoded_lenindef.bered)
7014 repr(obj_decoded_lenindef)
7015 list(obj_decoded_lenindef.pps())
7016 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
7017 self.assertEqual(tail_lenindef, tail_junk)
7018 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
7019 with self.assertRaises(DecodeError):
7020 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
7021 with self.assertRaises(DecodeError):
7022 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
7024 evgens = list(obj.decode_evgen(
7025 obj_encoded_lenindef + tail_junk,
7026 decode_path=decode_path,
7027 ctx={"bered": True},
7029 self.assertEqual(len(evgens), len(obj_decoded_lenindef) + 1)
7030 for i, (_decode_path, obj, _) in enumerate(evgens[:-1]):
7031 self.assertEqual(_decode_path, decode_path + (str(i),))
7034 _decode_path, obj, tail = evgens[-1]
7035 self.assertEqual(_decode_path, decode_path)
7039 assert_exceeding_data(
7041 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
7045 def test_bered(self):
7046 class SeqOf(self.base_klass):
7048 encoded = Boolean(False).encode()
7049 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
7050 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7051 with self.assertRaises(DecodeError):
7052 SeqOf().decode(encoded)
7053 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7054 self.assertFalse(decoded.ber_encoded)
7055 self.assertFalse(decoded.lenindef)
7056 self.assertTrue(decoded.bered)
7057 decoded = copy(decoded)
7058 self.assertFalse(decoded.ber_encoded)
7059 self.assertFalse(decoded.lenindef)
7060 self.assertTrue(decoded.bered)
7062 class SeqOf(self.base_klass):
7063 schema = OctetString()
7064 encoded = OctetString(b"whatever").encode()
7066 tag_encode(form=TagFormConstructed, num=4) +
7068 OctetString(b"whatever").encode() +
7071 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7072 with self.assertRaises(DecodeError):
7073 SeqOf().decode(encoded)
7074 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7075 self.assertFalse(decoded.ber_encoded)
7076 self.assertFalse(decoded.lenindef)
7077 self.assertTrue(decoded.bered)
7078 decoded = copy(decoded)
7079 self.assertFalse(decoded.ber_encoded)
7080 self.assertFalse(decoded.lenindef)
7081 self.assertTrue(decoded.bered)
7084 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
7085 class SeqOf(SequenceOf):
7089 def _test_symmetric_compare_objs(self, obj1, obj2):
7090 self.assertEqual(obj1, obj2)
7091 self.assertSequenceEqual(list(obj1), list(obj2))
7093 def test_iterator_pickling(self):
7094 class SeqOf(SequenceOf):
7096 register_class(SeqOf)
7099 seqof = seqof(iter(range(10)))
7100 with self.assertRaisesRegex(ValueError, "iterator"):
7103 def test_iterator_bounds(self):
7104 class SeqOf(SequenceOf):
7113 seqof = SeqOf(gen(n))
7114 self.assertTrue(seqof.ready)
7115 with self.assertRaises(BoundsError):
7117 self.assertFalse(seqof.ready)
7118 seqof = seqof(gen(n))
7119 self.assertTrue(seqof.ready)
7120 with self.assertRaises(BoundsError):
7122 self.assertFalse(seqof.ready)
7124 def test_iterator_twice(self):
7125 class SeqOf(SequenceOf):
7127 bounds = (1, float("+inf"))
7132 seqof = SeqOf(gen())
7133 self.assertTrue(seqof.ready)
7135 self.assertFalse(seqof.ready)
7136 register_class(SeqOf)
7139 def test_iterator_2pass(self):
7140 class SeqOf(SequenceOf):
7142 bounds = (1, float("+inf"))
7147 seqof = SeqOf(gen())
7148 self.assertTrue(seqof.ready)
7149 _, state = seqof.encode1st()
7150 self.assertFalse(seqof.ready)
7151 seqof = seqof(gen())
7152 self.assertTrue(seqof.ready)
7154 seqof.encode2nd(buf.write, iter(state))
7155 self.assertSequenceEqual(
7156 [int(i) for i in seqof.decod(buf.getvalue())],
7160 def test_non_ready_bound_min(self):
7161 class SeqOf(SequenceOf):
7163 bounds = (1, float("+inf"))
7165 self.assertFalse(seqof.ready)
7168 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
7173 def _test_symmetric_compare_objs(self, obj1, obj2):
7174 self.assertSetEqual(
7175 set(int(v) for v in obj1),
7176 set(int(v) for v in obj2),
7179 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7180 @given(data_strategy())
7181 def test_sorted(self, d):
7182 values = [OctetString(v) for v in d.draw(lists(binary()))]
7185 schema = OctetString()
7187 seq_encoded = seq.encode()
7188 seq_decoded, _ = seq.decode(seq_encoded)
7189 self.assertSequenceEqual(
7190 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
7191 b"".join(sorted([v.encode() for v in values])),
7194 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7195 @given(data_strategy())
7196 def test_unsorted(self, d):
7197 values = [OctetString(v).encode() for v in d.draw(sets(
7198 binary(min_size=1, max_size=5),
7202 values = d.draw(permutations(values))
7203 assume(values != sorted(values))
7204 encoded = b"".join(values)
7205 seq_encoded = b"".join((
7207 len_encode(len(encoded)),
7212 schema = OctetString()
7214 with self.assertRaisesRegex(DecodeError, "unordered SET OF"):
7215 seq.decode(seq_encoded)
7217 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
7218 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
7219 self.assertTrue(seq_decoded.ber_encoded)
7220 self.assertTrue(seq_decoded.bered)
7221 seq_decoded = copy(seq_decoded)
7222 self.assertTrue(seq_decoded.ber_encoded)
7223 self.assertTrue(seq_decoded.bered)
7224 self.assertSequenceEqual(
7225 [obj.encode() for obj in seq_decoded],
7230 class TestGoMarshalVectors(TestCase):
7232 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
7233 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
7234 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
7235 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
7236 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
7238 class Seq(Sequence):
7240 ("erste", Integer()),
7241 ("zweite", Integer(optional=True))
7244 seq["erste"] = Integer(64)
7245 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7246 seq["erste"] = Integer(0x123456)
7247 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
7248 seq["erste"] = Integer(64)
7249 seq["zweite"] = Integer(65)
7250 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
7252 class NestedSeq(Sequence):
7256 seq["erste"] = Integer(127)
7257 seq["zweite"] = None
7258 nested = NestedSeq()
7259 nested["nest"] = seq
7260 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
7262 self.assertSequenceEqual(
7263 OctetString(b"\x01\x02\x03").encode(),
7264 hexdec("0403010203"),
7267 class Seq(Sequence):
7269 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
7272 seq["erste"] = Integer(64)
7273 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
7275 class Seq(Sequence):
7277 ("erste", Integer(expl=tag_ctxc(5))),
7280 seq["erste"] = Integer(64)
7281 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
7283 class Seq(Sequence):
7286 impl=tag_encode(0, klass=TagClassContext),
7291 seq["erste"] = Null()
7292 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
7294 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7296 self.assertSequenceEqual(
7297 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
7298 hexdec("170d3730303130313030303030305a"),
7300 self.assertSequenceEqual(
7301 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
7302 hexdec("170d3039313131353232353631365a"),
7304 self.assertSequenceEqual(
7305 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
7306 hexdec("180f32313030303430353132303130315a"),
7309 class Seq(Sequence):
7311 ("erste", GeneralizedTime()),
7314 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
7315 self.assertSequenceEqual(
7317 hexdec("3011180f32303039313131353232353631365a"),
7320 self.assertSequenceEqual(
7321 BitString((1, b"\x80")).encode(),
7324 self.assertSequenceEqual(
7325 BitString((12, b"\x81\xF0")).encode(),
7326 hexdec("03030481f0"),
7329 self.assertSequenceEqual(
7330 ObjectIdentifier("1.2.3.4").encode(),
7331 hexdec("06032a0304"),
7333 self.assertSequenceEqual(
7334 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
7335 hexdec("06092a864888932d010105"),
7337 self.assertSequenceEqual(
7338 ObjectIdentifier("2.100.3").encode(),
7339 hexdec("0603813403"),
7342 self.assertSequenceEqual(
7343 PrintableString("test").encode(),
7344 hexdec("130474657374"),
7346 self.assertSequenceEqual(
7347 PrintableString("x" * 127).encode(),
7348 hexdec("137F" + "78" * 127),
7350 self.assertSequenceEqual(
7351 PrintableString("x" * 128).encode(),
7352 hexdec("138180" + "78" * 128),
7354 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
7356 class Seq(Sequence):
7358 ("erste", IA5String()),
7361 seq["erste"] = IA5String("test")
7362 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
7364 class Seq(Sequence):
7366 ("erste", PrintableString()),
7369 seq["erste"] = PrintableString("test")
7370 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
7371 # Asterisk is actually not allowable
7372 PrintableString._allowable_chars |= set(b"*")
7373 seq["erste"] = PrintableString("test*")
7374 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
7375 PrintableString._allowable_chars -= set(b"*")
7377 class Seq(Sequence):
7379 ("erste", Any(optional=True)),
7380 ("zweite", Integer()),
7383 seq["zweite"] = Integer(64)
7384 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7389 seq.append(Integer(10))
7390 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
7392 class _SeqOf(SequenceOf):
7393 schema = PrintableString()
7395 class SeqOf(SequenceOf):
7398 _seqof.append(PrintableString("1"))
7400 seqof.append(_seqof)
7401 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
7403 class Seq(Sequence):
7405 ("erste", Integer(default=1)),
7408 seq["erste"] = Integer(0)
7409 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
7410 seq["erste"] = Integer(1)
7411 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7412 seq["erste"] = Integer(2)
7413 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
7416 class TestPP(TestCase):
7417 @given(data_strategy())
7418 def test_oid_printing(self, d):
7420 str(ObjectIdentifier(k)): v * 2
7421 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
7423 chosen = d.draw(sampled_from(sorted(oids)))
7424 chosen_id = oids[chosen]
7425 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
7426 self.assertNotIn(chosen_id, pp_console_row(pp))
7429 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
7433 class TestAutoAddSlots(TestCase):
7435 class Inher(Integer):
7438 with self.assertRaises(AttributeError):
7440 inher.unexistent = "whatever"
7443 class TestOIDDefines(TestCase):
7444 @given(data_strategy())
7445 def runTest(self, d):
7446 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
7447 value_name_chosen = d.draw(sampled_from(value_names))
7449 ObjectIdentifier(oid)
7450 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
7452 oid_chosen = d.draw(sampled_from(oids))
7453 values = d.draw(lists(
7455 min_size=len(value_names),
7456 max_size=len(value_names),
7458 for definable_class in (Any, OctetString, BitString):
7460 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
7461 oid: Integer() for oid in oids[:-1]
7464 for i, value_name in enumerate(value_names):
7465 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
7467 class Seq(Sequence):
7470 for value_name, value in zip(value_names, values):
7471 seq[value_name] = definable_class(Integer(value).encode())
7472 seq["type"] = oid_chosen
7473 seq, _ = Seq().decode(seq.encode())
7474 for value_name in value_names:
7475 if value_name == value_name_chosen:
7477 self.assertIsNone(seq[value_name].defined)
7478 if value_name_chosen in oids[:-1]:
7479 self.assertIsNotNone(seq[value_name_chosen].defined)
7480 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
7481 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
7484 pprint(seq, big_blobs=True, with_decode_path=True)
7487 class TestDefinesByPath(TestCase):
7488 def test_generated(self):
7489 class Seq(Sequence):
7491 ("type", ObjectIdentifier()),
7492 ("value", OctetString(expl=tag_ctxc(123))),
7495 class SeqInner(Sequence):
7497 ("typeInner", ObjectIdentifier()),
7498 ("valueInner", Any()),
7501 class PairValue(SetOf):
7504 class Pair(Sequence):
7506 ("type", ObjectIdentifier()),
7507 ("value", PairValue()),
7510 class Pairs(SequenceOf):
7517 type_octet_stringed,
7519 ObjectIdentifier(oid)
7520 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
7522 seq_integered = Seq()
7523 seq_integered["type"] = type_integered
7524 seq_integered["value"] = OctetString(Integer(123).encode())
7525 seq_integered_raw = seq_integered.encode()
7529 (type_octet_stringed, OctetString(b"whatever")),
7530 (type_integered, Integer(123)),
7531 (type_octet_stringed, OctetString(b"whenever")),
7532 (type_integered, Integer(234)),
7534 for t, v in pairs_input:
7537 ("value", PairValue((Any(v),))),
7539 seq_inner = SeqInner()
7540 seq_inner["typeInner"] = type_innered
7541 seq_inner["valueInner"] = Any(pairs)
7542 seq_sequenced = Seq()
7543 seq_sequenced["type"] = type_sequenced
7544 seq_sequenced["value"] = OctetString(seq_inner.encode())
7545 seq_sequenced_raw = seq_sequenced.encode()
7547 list(seq_sequenced.pps())
7548 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7550 defines_by_path = []
7551 ctx_copied = deepcopy(ctx_dummy)
7552 seq_integered, _ = Seq().decode(
7556 self.assertDictEqual(ctx_copied, ctx_dummy)
7557 self.assertIsNone(seq_integered["value"].defined)
7558 defines_by_path.append(
7559 (("type",), ((("value",), {
7560 type_integered: Integer(),
7561 type_sequenced: SeqInner(),
7564 ctx_copied["defines_by_path"] = defines_by_path
7565 seq_integered, _ = Seq().decode(
7569 del ctx_copied["defines_by_path"]
7570 self.assertDictEqual(ctx_copied, ctx_dummy)
7571 self.assertIsNotNone(seq_integered["value"].defined)
7572 self.assertEqual(seq_integered["value"].defined[0], type_integered)
7573 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
7574 self.assertTrue(seq_integered_raw[
7575 seq_integered["value"].defined[1].offset:
7576 ].startswith(Integer(123).encode()))
7578 list(seq_integered.pps())
7579 pprint(seq_integered, big_blobs=True, with_decode_path=True)
7581 ctx_copied["defines_by_path"] = defines_by_path
7582 seq_sequenced, _ = Seq().decode(
7586 del ctx_copied["defines_by_path"]
7587 self.assertDictEqual(ctx_copied, ctx_dummy)
7588 self.assertIsNotNone(seq_sequenced["value"].defined)
7589 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7590 seq_inner = seq_sequenced["value"].defined[1]
7591 self.assertIsNone(seq_inner["valueInner"].defined)
7593 list(seq_sequenced.pps())
7594 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7596 defines_by_path.append((
7597 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
7598 ((("valueInner",), {type_innered: Pairs()}),),
7600 ctx_copied["defines_by_path"] = defines_by_path
7601 seq_sequenced, _ = Seq().decode(
7605 del ctx_copied["defines_by_path"]
7606 self.assertDictEqual(ctx_copied, ctx_dummy)
7607 self.assertIsNotNone(seq_sequenced["value"].defined)
7608 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7609 seq_inner = seq_sequenced["value"].defined[1]
7610 self.assertIsNotNone(seq_inner["valueInner"].defined)
7611 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7612 pairs = seq_inner["valueInner"].defined[1]
7614 self.assertIsNone(pair["value"][0].defined)
7616 list(seq_sequenced.pps())
7617 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7619 defines_by_path.append((
7622 DecodePathDefBy(type_sequenced),
7624 DecodePathDefBy(type_innered),
7629 type_integered: Integer(),
7630 type_octet_stringed: OctetString(),
7633 ctx_copied["defines_by_path"] = defines_by_path
7634 seq_sequenced, _ = Seq().decode(
7638 del ctx_copied["defines_by_path"]
7639 self.assertDictEqual(ctx_copied, ctx_dummy)
7640 self.assertIsNotNone(seq_sequenced["value"].defined)
7641 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7642 seq_inner = seq_sequenced["value"].defined[1]
7643 self.assertIsNotNone(seq_inner["valueInner"].defined)
7644 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7645 pairs_got = seq_inner["valueInner"].defined[1]
7646 for pair_input, pair_got in zip(pairs_input, pairs_got):
7647 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7648 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7650 list(seq_sequenced.pps())
7651 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7653 @given(oid_strategy(), integers())
7654 def test_simple(self, oid, tgt):
7655 class Inner(Sequence):
7657 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7658 ObjectIdentifier(oid): Integer(),
7662 class Outer(Sequence):
7665 ("tgt", OctetString()),
7669 inner["oid"] = ObjectIdentifier(oid)
7671 outer["inner"] = inner
7672 outer["tgt"] = OctetString(Integer(tgt).encode())
7673 decoded, _ = Outer().decode(outer.encode())
7674 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7676 def test_remaining_data(self):
7677 oid = ObjectIdentifier("1.2.3")
7679 class Seq(Sequence):
7681 ("oid", ObjectIdentifier(defines=((("tgt",), {
7684 ("tgt", OctetString()),
7689 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7691 with self.assertRaisesRegex(DecodeError, "remaining data"):
7692 Seq().decode(seq.encode())
7694 def test_remaining_data_seqof(self):
7695 oid = ObjectIdentifier("1.2.3")
7698 schema = OctetString()
7700 class Seq(Sequence):
7702 ("oid", ObjectIdentifier(defines=((("tgt",), {
7710 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7712 with self.assertRaisesRegex(DecodeError, "remaining data"):
7713 Seq().decode(seq.encode())
7716 class TestAbsDecodePath(TestCase):
7718 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7719 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7721 def test_concat(self, decode_path, rel_path):
7722 dp = abs_decode_path(decode_path, rel_path)
7723 self.assertSequenceEqual(dp, decode_path + rel_path)
7727 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7728 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7730 def test_abs(self, decode_path, rel_path):
7731 self.assertSequenceEqual(
7732 abs_decode_path(decode_path, ("/",) + rel_path),
7737 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7738 integers(min_value=1, max_value=3),
7739 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7741 def test_dots(self, decode_path, number_of_dots, rel_path):
7742 self.assertSequenceEqual(
7743 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7744 decode_path[:-number_of_dots] + rel_path,
7748 class TestStrictDefaultExistence(TestCase):
7749 @given(data_strategy())
7750 def runTest(self, d):
7751 count = d.draw(integers(min_value=1, max_value=10))
7752 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7754 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7755 for i in range(count)
7757 for klass in (Sequence, Set):
7761 for i in range(count):
7762 seq["int%d" % i] = Integer(123)
7764 chosen_choice = "int%d" % chosen
7765 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7766 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
7768 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7769 self.assertTrue(decoded.ber_encoded)
7770 self.assertTrue(decoded.bered)
7771 decoded = copy(decoded)
7772 self.assertTrue(decoded.ber_encoded)
7773 self.assertTrue(decoded.bered)
7774 decoded, _ = seq.decode(raw, ctx={"bered": True})
7775 self.assertTrue(decoded.ber_encoded)
7776 self.assertTrue(decoded.bered)
7777 decoded = copy(decoded)
7778 self.assertTrue(decoded.ber_encoded)
7779 self.assertTrue(decoded.bered)
7782 class TestX690PrefixedType(TestCase):
7784 self.assertSequenceEqual(
7785 VisibleString("Jones").encode(),
7786 hexdec("1A054A6F6E6573"),
7790 self.assertSequenceEqual(
7793 impl=tag_encode(3, klass=TagClassApplication),
7795 hexdec("43054A6F6E6573"),
7799 self.assertSequenceEqual(
7803 impl=tag_encode(3, klass=TagClassApplication),
7807 hexdec("A20743054A6F6E6573"),
7811 self.assertSequenceEqual(
7815 impl=tag_encode(3, klass=TagClassApplication),
7817 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7819 hexdec("670743054A6F6E6573"),
7823 self.assertSequenceEqual(
7824 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7825 hexdec("82054A6F6E6573"),
7829 class TestExplOOB(TestCase):
7831 expl = tag_ctxc(123)
7832 raw = Integer(123).encode() + Integer(234).encode()
7833 raw = b"".join((expl, len_encode(len(raw)), raw))
7834 with self.assertRaisesRegex(DecodeError, "explicit tag out-of-bound"):
7835 Integer(expl=expl).decode(raw)
7836 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7839 class TestPickleDifferentVersion(TestCase):
7841 pickled = pickle_dumps(Integer(123), pickle_proto)
7843 version_orig = pyderasn.__version__
7844 pyderasn.__version__ += "different"
7845 with self.assertRaisesRegex(ValueError, "different PyDERASN version"):
7846 pickle_loads(pickled)
7847 pyderasn.__version__ = version_orig
7848 pickle_loads(pickled)
7851 class TestCERSetOrdering(TestCase):
7852 def test_vectors(self):
7853 """Taken from X.690-201508
7857 ("c", Integer(impl=tag_ctxp(2))),
7858 ("d", Integer(impl=tag_ctxp(4))),
7863 ("g", Integer(impl=tag_ctxp(5))),
7864 ("h", Integer(impl=tag_ctxp(6))),
7869 ("j", Integer(impl=tag_ctxp(0))),
7880 ("a", Integer(impl=tag_ctxp(3))),
7881 ("b", B(expl=tag_ctxc(1))),
7886 ("a", Integer(123)),
7887 ("b", B(("d", Integer(234)))),
7888 ("e", E(("f", F(("g", Integer(345)))))),
7890 order = sorted(a._values_for_encoding(), key=attrgetter("tag_order_cer"))
7891 self.assertSequenceEqual(
7892 [i.__class__.__name__ for i in order],
7893 ("E", "B", "Integer"),