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
128 max_examples = environ.get("MAX_EXAMPLES")
129 settings.register_profile("local", settings(
131 **({"max_examples": int(max_examples)} if max_examples else {})
133 settings.load_profile("local")
134 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
136 tag_classes = sampled_from((
142 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
143 decode_path_strat = lists(integers(), max_size=3).map(
144 lambda decode_path: tuple(str(dp) for dp in decode_path)
146 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
149 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
151 self_module = import_module(__name__)
154 def register_class(klass):
155 klassname = klass.__name__ + str(time()).replace(".", "")
156 klass.__name__ = klassname
157 klass.__qualname__ = klassname
158 setattr(self_module, klassname, klass)
161 def assert_exceeding_data(self, call, junk):
164 with self.assertRaisesRegex(ExceedingData, "%d trailing bytes" % len(junk)) as err:
169 class TestHex(TestCase):
171 def test_symmetric(self, data):
172 self.assertEqual(hexdec(hexenc(data)), data)
175 class TestTagCoder(TestCase):
176 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
180 integers(min_value=0, max_value=30),
183 def test_short(self, klass, form, num, junk):
184 raw = tag_encode(klass=klass, form=form, num=num)
185 self.assertEqual(tag_decode(raw), (klass, form, num))
186 self.assertEqual(len(raw), 1)
188 tag_encode(klass=klass, form=form, num=0)[0],
189 raw[0] & (1 << 7 | 1 << 6 | 1 << 5),
191 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
192 self.assertSequenceEqual(stripped.tobytes(), raw)
193 self.assertEqual(tlen, len(raw))
194 self.assertSequenceEqual(tail, junk)
196 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
200 integers(min_value=31),
203 def test_long(self, klass, form, num, junk):
204 raw = tag_encode(klass=klass, form=form, num=num)
205 self.assertEqual(tag_decode(raw), (klass, form, num))
206 self.assertGreater(len(raw), 1)
208 tag_encode(klass=klass, form=form, num=0)[0] | 31,
211 self.assertEqual(raw[-1] & 0x80, 0)
212 self.assertTrue(all(b & 0x80 > 0 for b in raw[1:-1]))
213 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
214 self.assertSequenceEqual(stripped.tobytes(), raw)
215 self.assertEqual(tlen, len(raw))
216 self.assertSequenceEqual(tail, junk)
218 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
219 @given(integers(min_value=31))
220 def test_unfinished_tag(self, num):
221 raw = bytearray(tag_encode(num=num))
222 for i in range(1, len(raw)):
224 with self.assertRaisesRegex(DecodeError, "unfinished tag"):
225 tag_strip(bytes(raw))
227 def test_go_vectors_valid(self):
228 for data, (eklass, etag, elen, eform) in (
229 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
230 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
231 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
232 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
233 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
234 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
235 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
236 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
237 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
238 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
240 tag, _, len_encoded = tag_strip(memoryview(data))
241 klass, form, num = tag_decode(tag)
242 _len, _, tail = len_decode(len_encoded)
243 self.assertSequenceEqual(tail, b"")
244 self.assertEqual(klass, eklass)
245 self.assertEqual(num, etag)
246 self.assertEqual(_len, elen)
247 self.assertEqual(form, eform)
249 def test_go_vectors_invalid(self):
257 with self.assertRaises(DecodeError):
258 _, _, len_encoded = tag_strip(memoryview(data))
259 len_decode(len_encoded)
262 integers(min_value=0, max_value=127),
263 integers(min_value=0, max_value=2),
265 def test_long_instead_of_short(self, l, dummy_num):
266 octets = (b"\x00" * dummy_num) + bytes([l])
267 octets = bytes([(dummy_num + 1) | 0x80]) + octets
268 with self.assertRaises(DecodeError):
271 @given(tag_classes, tag_forms, integers(min_value=31))
272 def test_leading_zero_byte(self, klass, form, num):
273 raw = tag_encode(klass=klass, form=form, num=num)
274 raw = b"".join((raw[:1], b"\x80", raw[1:]))
275 with self.assertRaisesRegex(DecodeError, "leading zero byte"):
278 @given(tag_classes, tag_forms, integers(max_value=30, min_value=0))
279 def test_unexpected_long_form(self, klass, form, num):
280 raw = bytes([klass | form | 31, num])
281 with self.assertRaisesRegex(DecodeError, "unexpected long form"):
285 class TestLenCoder(TestCase):
286 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
288 integers(min_value=0, max_value=127),
291 def test_short(self, l, junk):
292 raw = len_encode(l) + junk
293 decoded, llen, tail = len_decode(memoryview(raw))
294 self.assertEqual(decoded, l)
295 self.assertEqual(llen, 1)
296 self.assertEqual(len(raw), 1 + len(junk))
297 self.assertEqual(tail.tobytes(), junk)
299 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
301 integers(min_value=128),
304 def test_long(self, l, junk):
305 raw = len_encode(l) + junk
306 decoded, llen, tail = len_decode(memoryview(raw))
307 self.assertEqual(decoded, l)
308 self.assertEqual((llen - 1) | 0x80, raw[0])
309 self.assertEqual(llen, len(raw) - len(junk))
310 self.assertNotEqual(raw[1], 0)
311 self.assertSequenceEqual(tail.tobytes(), junk)
313 def test_empty(self):
314 with self.assertRaises(NotEnoughData):
317 @given(integers(min_value=128))
318 def test_stripped(self, _len):
319 with self.assertRaises(NotEnoughData):
320 len_decode(len_encode(_len)[:-1])
323 text_printable = text(alphabet=printable, min_size=1)
327 def text_letters(draw):
328 result = draw(text(alphabet=ascii_letters, min_size=1))
332 class CommonMixin(object):
333 def test_tag_default(self):
334 obj = self.base_klass()
335 self.assertEqual(obj.tag, obj.tag_default)
337 def test_simultaneous_impl_expl(self):
338 with self.assertRaises(ValueError):
339 self.base_klass(impl=b"whatever", expl=b"whenever")
341 @given(binary(min_size=1), integers(), integers(), integers())
342 def test_decoded(self, impl, offset, llen, vlen):
343 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
344 self.assertEqual(obj.offset, offset)
345 self.assertEqual(obj.llen, llen)
346 self.assertEqual(obj.vlen, vlen)
347 self.assertEqual(obj.tlen, len(impl))
348 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
350 @given(binary(min_size=1))
351 def test_impl_inherited(self, impl_tag):
352 class Inherited(self.base_klass):
355 self.assertSequenceEqual(obj.impl, impl_tag)
356 self.assertFalse(obj.expled)
358 tag_class, _, tag_num = tag_decode(impl_tag)
359 self.assertEqual(obj.tag_order, (tag_class, tag_num))
361 @given(binary(min_size=1))
362 def test_expl_inherited(self, expl_tag):
363 class Inherited(self.base_klass):
366 self.assertSequenceEqual(obj.expl, expl_tag)
367 self.assertTrue(obj.expled)
369 tag_class, _, tag_num = tag_decode(expl_tag)
370 self.assertEqual(obj.tag_order, (tag_class, tag_num))
372 def assert_copied_basic_fields(self, obj, obj_copied):
373 self.assertEqual(obj, obj_copied)
374 self.assertSequenceEqual(obj.tag, obj_copied.tag)
375 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
376 self.assertEqual(obj.default, obj_copied.default)
377 self.assertEqual(obj.optional, obj_copied.optional)
378 self.assertEqual(obj.offset, obj_copied.offset)
379 self.assertEqual(obj.llen, obj_copied.llen)
380 self.assertEqual(obj.vlen, obj_copied.vlen)
382 self.assertEqual(obj.tag_order, obj_copied.tag_order)
386 def boolean_values_strategy(draw, do_expl=False):
387 value = draw(one_of(none(), booleans()))
391 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
393 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
394 default = draw(one_of(none(), booleans()))
395 optional = draw(one_of(none(), booleans()))
397 draw(integers(min_value=0)),
398 draw(integers(min_value=0)),
399 draw(integers(min_value=0)),
401 return (value, impl, expl, default, optional, _decoded)
404 class BooleanInherited(Boolean):
408 class TestBoolean(CommonMixin, TestCase):
411 def test_invalid_value_type(self):
412 with self.assertRaises(InvalidValueType) as err:
417 def test_optional(self, optional):
418 obj = Boolean(default=Boolean(False), optional=optional)
419 self.assertTrue(obj.optional)
422 def test_ready(self, value):
424 self.assertFalse(obj.ready)
427 pprint(obj, big_blobs=True, with_decode_path=True)
428 with self.assertRaises(ObjNotReady) as err:
430 with self.assertRaises(ObjNotReady) as err:
434 self.assertTrue(obj.ready)
437 pprint(obj, big_blobs=True, with_decode_path=True)
439 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
440 def test_comparison(self, value1, value2, tag1, tag2):
441 for klass in (Boolean, BooleanInherited):
444 self.assertEqual(obj1 == obj2, value1 == value2)
445 self.assertEqual(obj1 != obj2, value1 != value2)
446 self.assertEqual(obj1 == bool(obj2), value1 == value2)
447 obj1 = klass(value1, impl=tag1)
448 obj2 = klass(value1, impl=tag2)
449 self.assertEqual(obj1 == obj2, tag1 == tag2)
450 self.assertEqual(obj1 != obj2, tag1 != tag2)
452 @given(data_strategy())
453 def test_call(self, d):
454 for klass in (Boolean, BooleanInherited):
462 ) = d.draw(boolean_values_strategy())
468 optional_initial or False,
478 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
479 obj = obj_initial(value, impl, expl, default, optional)
481 value_expected = default if value is None else value
483 default_initial if value_expected is None
486 self.assertEqual(obj, value_expected)
487 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
488 self.assertEqual(obj.expl_tag, expl or expl_initial)
491 default_initial if default is None else default,
493 if obj.default is None:
494 optional = optional_initial if optional is None else optional
495 optional = False if optional is None else optional
498 self.assertEqual(obj.optional, optional)
500 @given(boolean_values_strategy())
501 def test_copy(self, values):
502 for klass in (Boolean, BooleanInherited):
504 for copy_func in copy_funcs:
505 obj_copied = copy_func(obj)
506 self.assert_copied_basic_fields(obj, obj_copied)
510 integers(min_value=1).map(tag_encode),
512 def test_stripped(self, value, tag_impl):
513 obj = Boolean(value, impl=tag_impl)
514 with self.assertRaises(NotEnoughData):
515 obj.decode(obj.encode()[:-1])
516 with self.assertRaises(NotEnoughData):
517 obj.decode(encode2pass(obj)[:-1])
521 integers(min_value=1).map(tag_ctxc),
523 def test_stripped_expl(self, value, tag_expl):
524 obj = Boolean(value, expl=tag_expl)
525 with self.assertRaises(NotEnoughData):
526 obj.decode(obj.encode()[:-1])
527 with self.assertRaises(NotEnoughData):
528 obj.decode(encode2pass(obj)[:-1])
531 integers(min_value=31),
532 integers(min_value=0),
535 def test_bad_tag(self, tag, offset, decode_path):
536 with self.assertRaises(DecodeError) as err:
538 tag_encode(tag)[:-1],
540 decode_path=decode_path,
543 self.assertEqual(err.exception.offset, offset)
544 self.assertEqual(err.exception.decode_path, decode_path)
547 integers(min_value=31),
548 integers(min_value=0),
551 def test_bad_expl_tag(self, tag, offset, decode_path):
552 with self.assertRaises(DecodeError) as err:
553 Boolean(expl=Boolean.tag_default).decode(
554 tag_encode(tag)[:-1],
556 decode_path=decode_path,
559 self.assertEqual(err.exception.offset, offset)
560 self.assertEqual(err.exception.decode_path, decode_path)
563 integers(min_value=128),
564 integers(min_value=0),
567 def test_bad_len(self, l, offset, decode_path):
568 with self.assertRaises(DecodeError) as err:
570 Boolean.tag_default + len_encode(l)[:-1],
572 decode_path=decode_path,
575 self.assertEqual(err.exception.offset, offset)
576 self.assertEqual(err.exception.decode_path, decode_path)
579 integers(min_value=128),
580 integers(min_value=0),
583 def test_bad_expl_len(self, l, offset, decode_path):
584 with self.assertRaises(DecodeError) as err:
585 Boolean(expl=Boolean.tag_default).decode(
586 Boolean.tag_default + len_encode(l)[:-1],
588 decode_path=decode_path,
591 self.assertEqual(err.exception.offset, offset)
592 self.assertEqual(err.exception.decode_path, decode_path)
594 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
596 boolean_values_strategy(),
598 integers(min_value=1).map(tag_ctxc),
599 integers(min_value=0),
603 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
604 for klass in (Boolean, BooleanInherited):
605 _, _, _, default, optional, _decoded = values
614 pprint(obj, big_blobs=True, with_decode_path=True)
615 self.assertFalse(obj.expled)
616 obj_encoded = obj.encode()
617 self.assertEqual(encode2pass(obj), obj_encoded)
618 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
619 obj_expled = obj(value, expl=tag_expl)
620 self.assertTrue(obj_expled.expled)
622 list(obj_expled.pps())
623 pprint(obj_expled, big_blobs=True, with_decode_path=True)
624 obj_expled_cer = encode_cer(obj_expled)
625 self.assertNotEqual(obj_expled_cer, obj_encoded)
626 self.assertSequenceEqual(
627 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
630 obj_expled_hex_encoded = obj_expled.hexencode()
631 ctx_copied = deepcopy(ctx_dummy)
632 obj_decoded, tail = obj_expled.hexdecode(
633 obj_expled_hex_encoded + hexenc(tail_junk),
637 self.assertDictEqual(ctx_copied, ctx_dummy)
639 list(obj_decoded.pps())
640 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
641 self.assertEqual(tail, tail_junk)
642 self.assertEqual(obj_decoded, obj_expled)
643 self.assertNotEqual(obj_decoded, obj)
644 self.assertEqual(bool(obj_decoded), bool(obj_expled))
645 self.assertEqual(bool(obj_decoded), bool(obj))
646 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
647 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
648 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
650 obj_decoded.expl_llen,
651 len(len_encode(len(obj_encoded))),
653 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
654 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
657 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
659 self.assertEqual(obj_decoded.expl_offset, offset)
660 assert_exceeding_data(
662 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
666 evgens = list(obj_expled.decode_evgen(
667 hexdec(obj_expled_hex_encoded) + tail_junk,
669 decode_path=decode_path,
672 self.assertEqual(len(evgens), 1)
673 _decode_path, obj, tail = evgens[0]
674 self.assertSequenceEqual(tail, tail_junk)
675 self.assertEqual(_decode_path, decode_path)
676 self.assertEqual(obj, obj_decoded)
677 self.assertEqual(obj.expl_offset, offset)
681 @given(integers(min_value=2))
682 def test_invalid_len(self, l):
683 with self.assertRaises(InvalidLength):
684 Boolean().decode(b"".join((
690 @given(integers(min_value=0 + 1, max_value=255 - 1))
691 def test_ber_value(self, value):
692 with self.assertRaisesRegex(DecodeError, "unacceptable Boolean value"):
693 Boolean().decode(b"".join((
698 encoded = b"".join((Boolean.tag_default, len_encode(1), bytes([value])))
699 obj, _ = Boolean().decode(encoded, ctx={"bered": True})
700 list(Boolean().decode_evgen(encoded, ctx={"bered": True}))
701 self.assertTrue(bool(obj))
702 self.assertTrue(obj.ber_encoded)
703 self.assertFalse(obj.lenindef)
704 self.assertTrue(obj.bered)
706 self.assertTrue(obj.ber_encoded)
707 self.assertFalse(obj.lenindef)
708 self.assertTrue(obj.bered)
711 integers(min_value=1).map(tag_ctxc),
712 binary().filter(lambda x: not x.startswith(EOC)),
714 def test_ber_expl_no_eoc(self, expl, junk):
715 encoded = expl + LENINDEF + Boolean(False).encode()
716 with self.assertRaises(LenIndefForm):
717 Boolean(expl=expl).decode(encoded + junk)
718 with self.assertRaisesRegex(DecodeError, "no EOC"):
719 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
720 obj, tail = Boolean(expl=expl).decode(
721 encoded + EOC + junk,
724 self.assertTrue(obj.expl_lenindef)
725 self.assertFalse(obj.lenindef)
726 self.assertFalse(obj.ber_encoded)
727 self.assertTrue(obj.bered)
729 self.assertTrue(obj.expl_lenindef)
730 self.assertFalse(obj.lenindef)
731 self.assertFalse(obj.ber_encoded)
732 self.assertTrue(obj.bered)
733 self.assertSequenceEqual(tail, junk)
736 pprint(obj, big_blobs=True, with_decode_path=True)
739 integers(min_value=1).map(tag_ctxc),
746 def test_ber_expl(self, expl, values):
752 Boolean(value).encode() +
755 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
757 class SeqOf(SequenceOf):
758 schema = Boolean(expl=expl)
759 with self.assertRaises(LenIndefForm):
760 SeqOf().decode(encoded)
761 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
762 list(SeqOf().decode_evgen(encoded, ctx={"bered": True}))
763 self.assertSequenceEqual(tail, b"")
764 self.assertSequenceEqual([bool(v) for v in seqof], values)
780 len(expl) + 1 + 3 + EOC_LEN,
791 pprint(seqof, big_blobs=True, with_decode_path=True)
795 def integer_values_strategy(draw, do_expl=False):
796 bound_min, value, default, bound_max = sorted(draw(sets(
805 _specs = draw(sets(text_letters()))
808 min_size=len(_specs),
809 max_size=len(_specs),
811 _specs = list(zip(_specs, values))
814 bounds = (bound_min, bound_max)
818 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
820 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
823 optional = draw(one_of(none(), booleans()))
825 draw(integers(min_value=0)),
826 draw(integers(min_value=0)),
827 draw(integers(min_value=0)),
829 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
832 class IntegerInherited(Integer):
836 class TestInteger(CommonMixin, TestCase):
839 def test_invalid_value_type(self):
840 with self.assertRaises(InvalidValueType) as err:
844 @given(sets(text_letters(), min_size=2))
845 def test_unknown_name(self, names_input):
846 missing = names_input.pop()
849 schema = [(n, 123) for n in names_input]
850 with self.assertRaises(ObjUnknown) as err:
854 @given(sets(text_letters(), min_size=2))
855 def test_known_name(self, names_input):
857 schema = [(n, 123) for n in names_input]
858 Int(names_input.pop())
861 def test_optional(self, optional):
862 obj = Integer(default=Integer(0), optional=optional)
863 self.assertTrue(obj.optional)
866 def test_ready(self, value):
868 self.assertFalse(obj.ready)
871 pprint(obj, big_blobs=True, with_decode_path=True)
872 with self.assertRaises(ObjNotReady) as err:
874 with self.assertRaises(ObjNotReady) as err:
878 self.assertTrue(obj.ready)
881 pprint(obj, big_blobs=True, with_decode_path=True)
884 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
885 def test_comparison(self, value1, value2, tag1, tag2):
886 for klass in (Integer, IntegerInherited):
889 self.assertEqual(obj1 == obj2, value1 == value2)
890 self.assertEqual(obj1 != obj2, value1 != value2)
891 self.assertEqual(obj1 == int(obj2), value1 == value2)
892 obj1 = klass(value1, impl=tag1)
893 obj2 = klass(value1, impl=tag2)
894 self.assertEqual(obj1 == obj2, tag1 == tag2)
895 self.assertEqual(obj1 != obj2, tag1 != tag2)
897 @given(lists(integers()))
898 def test_sorted_works(self, values):
899 self.assertSequenceEqual(
900 [int(v) for v in sorted(Integer(v) for v in values)],
904 @given(data_strategy())
905 def test_named(self, d):
906 names_input = list(d.draw(sets(text_letters(), min_size=1)))
907 values_input = list(d.draw(sets(
909 min_size=len(names_input),
910 max_size=len(names_input),
912 chosen_name = d.draw(sampled_from(names_input))
913 names_input = dict(zip(names_input, values_input))
917 _int = Int(chosen_name)
918 self.assertEqual(_int.named, chosen_name)
919 self.assertEqual(int(_int), names_input[chosen_name])
921 @given(integers(), integers(min_value=0), integers(min_value=0))
922 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
923 value = bound_min + value_delta
924 bound_max = value + bound_delta
925 Integer(value=value, bounds=(bound_min, bound_max))
927 @given(sets(integers(), min_size=3, max_size=3))
928 def test_bounds_unsatisfied(self, values):
929 values = sorted(values)
930 with self.assertRaises(BoundsError) as err:
931 Integer(value=values[0], bounds=(values[1], values[2]))
933 with self.assertRaisesRegex(DecodeError, "bounds") as err:
934 Integer(bounds=(values[1], values[2])).decode(
935 Integer(values[0]).encode()
938 with self.assertRaisesRegex(DecodeError, "bounds") as err:
939 Integer(bounds=(values[1], values[2])).decode(
940 encode2pass(Integer(values[0]))
942 with self.assertRaises(BoundsError) as err:
943 Integer(value=values[2], bounds=(values[0], values[1]))
945 with self.assertRaisesRegex(DecodeError, "bounds") as err:
946 Integer(bounds=(values[0], values[1])).decode(
947 Integer(values[2]).encode()
950 with self.assertRaisesRegex(DecodeError, "bounds") as err:
951 Integer(bounds=(values[0], values[1])).decode(
952 encode2pass(Integer(values[2]))
955 @given(data_strategy())
956 def test_call(self, d):
957 for klass in (Integer, IntegerInherited):
967 ) = d.draw(integer_values_strategy())
974 optional_initial or False,
987 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
988 if (default is None) and (obj_initial.default is not None):
992 (value is not None) and
993 (bounds_initial is not None) and
994 not (bounds_initial[0] <= value <= bounds_initial[1])
999 (default is not None) and
1000 (bounds_initial is not None) and
1001 not (bounds_initial[0] <= default <= bounds_initial[1])
1004 obj = obj_initial(value, bounds, impl, expl, default, optional)
1006 value_expected = default if value is None else value
1008 default_initial if value_expected is None
1011 self.assertEqual(obj, value_expected)
1012 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1013 self.assertEqual(obj.expl_tag, expl or expl_initial)
1016 default_initial if default is None else default,
1018 if obj.default is None:
1019 optional = optional_initial if optional is None else optional
1020 optional = False if optional is None else optional
1023 self.assertEqual(obj.optional, optional)
1025 (obj._bound_min, obj._bound_max),
1026 bounds or bounds_initial or (float("-inf"), float("+inf")),
1030 {} if _specs_initial is None else dict(_specs_initial),
1033 @given(integer_values_strategy())
1034 def test_copy(self, values):
1035 for klass in (Integer, IntegerInherited):
1036 obj = klass(*values)
1037 for copy_func in copy_funcs:
1038 obj_copied = copy_func(obj)
1039 self.assert_copied_basic_fields(obj, obj_copied)
1040 self.assertEqual(obj.specs, obj_copied.specs)
1041 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1042 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1043 self.assertEqual(obj._value, obj_copied._value)
1047 integers(min_value=1).map(tag_encode),
1049 def test_stripped(self, value, tag_impl):
1050 obj = Integer(value, impl=tag_impl)
1051 with self.assertRaises(NotEnoughData):
1052 obj.decode(obj.encode()[:-1])
1056 integers(min_value=1).map(tag_ctxc),
1058 def test_stripped_expl(self, value, tag_expl):
1059 obj = Integer(value, expl=tag_expl)
1060 with self.assertRaises(NotEnoughData):
1061 obj.decode(obj.encode()[:-1])
1063 def test_zero_len(self):
1064 with self.assertRaises(NotEnoughData):
1065 Integer().decode(b"".join((
1066 Integer.tag_default,
1071 integers(min_value=31),
1072 integers(min_value=0),
1075 def test_bad_tag(self, tag, offset, decode_path):
1076 with self.assertRaises(DecodeError) as err:
1078 tag_encode(tag)[:-1],
1080 decode_path=decode_path,
1083 self.assertEqual(err.exception.offset, offset)
1084 self.assertEqual(err.exception.decode_path, decode_path)
1087 integers(min_value=128),
1088 integers(min_value=0),
1091 def test_bad_len(self, l, offset, decode_path):
1092 with self.assertRaises(DecodeError) as err:
1094 Integer.tag_default + len_encode(l)[:-1],
1096 decode_path=decode_path,
1099 self.assertEqual(err.exception.offset, offset)
1100 self.assertEqual(err.exception.decode_path, decode_path)
1103 sets(integers(), min_size=2, max_size=2),
1104 integers(min_value=0),
1107 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1108 value, bound_min = list(sorted(ints))
1111 bounds = (bound_min, bound_min)
1112 with self.assertRaises(DecodeError) as err:
1114 Integer(value).encode(),
1116 decode_path=decode_path,
1119 self.assertEqual(err.exception.offset, offset)
1120 self.assertEqual(err.exception.decode_path, decode_path)
1122 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1124 integer_values_strategy(),
1126 integers(min_value=1).map(tag_ctxc),
1127 integers(min_value=0),
1131 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
1132 for klass in (Integer, IntegerInherited):
1133 _, _, _, _, default, optional, _, _decoded = values
1142 pprint(obj, big_blobs=True, with_decode_path=True)
1143 self.assertFalse(obj.expled)
1144 obj_encoded = obj.encode()
1145 self.assertEqual(encode2pass(obj), obj_encoded)
1146 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1147 obj_expled = obj(value, expl=tag_expl)
1148 self.assertTrue(obj_expled.expled)
1150 list(obj_expled.pps())
1151 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1152 obj_expled_encoded = obj_expled.encode()
1153 obj_expled_cer = encode_cer(obj_expled)
1154 self.assertNotEqual(obj_expled_cer, obj_encoded)
1155 self.assertSequenceEqual(
1156 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1159 ctx_copied = deepcopy(ctx_dummy)
1160 obj_decoded, tail = obj_expled.decode(
1161 obj_expled_encoded + tail_junk,
1165 self.assertDictEqual(ctx_copied, ctx_dummy)
1167 list(obj_decoded.pps())
1168 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1169 self.assertEqual(tail, tail_junk)
1170 self.assertEqual(obj_decoded, obj_expled)
1171 self.assertNotEqual(obj_decoded, obj)
1172 self.assertEqual(int(obj_decoded), int(obj_expled))
1173 self.assertEqual(int(obj_decoded), int(obj))
1174 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1175 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1176 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1178 obj_decoded.expl_llen,
1179 len(len_encode(len(obj_encoded))),
1181 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1182 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1185 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1187 self.assertEqual(obj_decoded.expl_offset, offset)
1188 assert_exceeding_data(
1190 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1194 evgens = list(obj_expled.decode_evgen(
1195 obj_expled_encoded + tail_junk,
1197 decode_path=decode_path,
1200 self.assertEqual(len(evgens), 1)
1201 _decode_path, obj, tail = evgens[0]
1202 self.assertSequenceEqual(tail, tail_junk)
1203 self.assertEqual(_decode_path, decode_path)
1204 self.assertEqual(obj, obj_decoded)
1205 self.assertEqual(obj.expl_offset, offset)
1209 def test_go_vectors_valid(self):
1210 for data, expect in ((
1214 (b"\xff\x7f", -129),
1218 (b"\xff\x00", -256),
1222 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1223 (b"\x80\x00\x00\x00", -2147483648),
1226 Integer().decode(b"".join((
1227 Integer.tag_default,
1228 len_encode(len(data)),
1234 def test_go_vectors_invalid(self):
1239 with self.assertRaises(DecodeError):
1240 Integer().decode(b"".join((
1241 Integer.tag_default,
1242 len_encode(len(data)),
1248 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1251 if draw(booleans()):
1252 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1254 integers(min_value=0, max_value=255),
1255 min_size=len(schema),
1256 max_size=len(schema),
1258 schema = list(zip(schema, bits))
1260 def _value(value_required):
1261 if not value_required and draw(booleans()):
1263 generation_choice = 0
1265 generation_choice = draw(sampled_from((1, 2, 3)))
1266 if generation_choice == 1 or draw(booleans()):
1267 return "'%s'B" % "".join(draw(lists(
1268 sampled_from(("0", "1")),
1269 max_size=len(schema),
1271 if generation_choice == 2 or draw(booleans()):
1272 return draw(binary(max_size=len(schema) // 8))
1273 if generation_choice == 3 or draw(booleans()):
1274 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1276 value = _value(value_required)
1277 default = _value(value_required=False)
1281 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1283 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1284 optional = draw(one_of(none(), booleans()))
1286 draw(integers(min_value=0)),
1287 draw(integers(min_value=0)),
1288 draw(integers(min_value=0)),
1290 return (schema, value, impl, expl, default, optional, _decoded)
1293 class BitStringInherited(BitString):
1297 class TestBitString(CommonMixin, TestCase):
1298 base_klass = BitString
1300 @given(lists(booleans()))
1301 def test_b_encoding(self, bits):
1302 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1303 self.assertEqual(obj.bit_len, len(bits))
1304 self.assertSequenceEqual(list(obj), bits)
1305 for i, bit in enumerate(bits):
1306 self.assertEqual(obj[i], bit)
1308 @given(lists(booleans()))
1309 def test_out_of_bounds_bits(self, bits):
1310 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1311 for i in range(len(bits), len(bits) * 2):
1312 self.assertFalse(obj[i])
1314 def test_bad_b_encoding(self):
1315 with self.assertRaises(ValueError):
1316 BitString("'010120101'B")
1319 integers(min_value=1, max_value=255),
1320 integers(min_value=1, max_value=255),
1322 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1323 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1324 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1325 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1327 class BS(BitString):
1328 schema = (("whatever", 0),)
1329 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1330 self.assertEqual(obj.bit_len, leading_zeros + 1)
1331 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1333 def test_zero_len(self):
1334 with self.assertRaises(NotEnoughData):
1335 BitString().decode(b"".join((
1336 BitString.tag_default,
1340 def test_invalid_value_type(self):
1341 with self.assertRaises(InvalidValueType) as err:
1344 with self.assertRaises(InvalidValueType) as err:
1348 def test_obj_unknown(self):
1349 with self.assertRaises(ObjUnknown) as err:
1350 BitString(b"whatever")["whenever"]
1353 def test_get_invalid_type(self):
1354 with self.assertRaises(InvalidValueType) as err:
1355 BitString(b"whatever")[(1, 2, 3)]
1358 @given(data_strategy())
1359 def test_unknown_name(self, d):
1360 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1361 missing = _schema.pop()
1363 class BS(BitString):
1364 schema = [(n, i) for i, n in enumerate(_schema)]
1365 with self.assertRaises(ObjUnknown) as err:
1370 def test_optional(self, optional):
1371 obj = BitString(default=BitString(b""), optional=optional)
1372 self.assertTrue(obj.optional)
1375 def test_ready(self, value):
1377 self.assertFalse(obj.ready)
1380 pprint(obj, big_blobs=True, with_decode_path=True)
1381 with self.assertRaises(ObjNotReady) as err:
1384 with self.assertRaises(ObjNotReady) as err:
1386 obj = BitString(value)
1387 self.assertTrue(obj.ready)
1390 pprint(obj, big_blobs=True, with_decode_path=True)
1393 tuples(integers(min_value=0), binary()),
1394 tuples(integers(min_value=0), binary()),
1398 def test_comparison(self, value1, value2, tag1, tag2):
1399 for klass in (BitString, BitStringInherited):
1400 obj1 = klass(value1)
1401 obj2 = klass(value2)
1402 self.assertEqual(obj1 == obj2, value1 == value2)
1403 self.assertEqual(obj1 != obj2, value1 != value2)
1404 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1405 obj1 = klass(value1, impl=tag1)
1406 obj2 = klass(value1, impl=tag2)
1407 self.assertEqual(obj1 == obj2, tag1 == tag2)
1408 self.assertEqual(obj1 != obj2, tag1 != tag2)
1410 @given(data_strategy())
1411 def test_call(self, d):
1412 for klass in (BitString, BitStringInherited):
1421 ) = d.draw(bit_string_values_strategy())
1424 schema = schema_initial
1426 value=value_initial,
1429 default=default_initial,
1430 optional=optional_initial or False,
1431 _decoded=_decoded_initial,
1441 ) = d.draw(bit_string_values_strategy(
1442 schema=schema_initial,
1443 do_expl=impl_initial is None,
1452 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1453 self.assertEqual(obj.expl_tag, expl or expl_initial)
1454 if obj.default is None:
1455 optional = optional_initial if optional is None else optional
1456 optional = False if optional is None else optional
1459 self.assertEqual(obj.optional, optional)
1460 self.assertEqual(obj.specs, obj_initial.specs)
1462 @given(bit_string_values_strategy())
1463 def test_copy(self, values):
1464 for klass in (BitString, BitStringInherited):
1465 _schema, value, impl, expl, default, optional, _decoded = values
1475 optional=optional or False,
1478 for copy_func in copy_funcs:
1479 obj_copied = copy_func(obj)
1480 self.assert_copied_basic_fields(obj, obj_copied)
1481 self.assertEqual(obj.specs, obj_copied.specs)
1482 self.assertEqual(obj._value, obj_copied._value)
1486 integers(min_value=1).map(tag_encode),
1488 def test_stripped(self, value, tag_impl):
1489 obj = BitString(value, impl=tag_impl)
1490 with self.assertRaises(NotEnoughData):
1491 obj.decode(obj.encode()[:-1])
1495 integers(min_value=1).map(tag_ctxc),
1497 def test_stripped_expl(self, value, tag_expl):
1498 obj = BitString(value, expl=tag_expl)
1499 with self.assertRaises(NotEnoughData):
1500 obj.decode(obj.encode()[:-1])
1503 integers(min_value=31),
1504 integers(min_value=0),
1507 def test_bad_tag(self, tag, offset, decode_path):
1508 with self.assertRaises(DecodeError) as err:
1510 tag_encode(tag)[:-1],
1512 decode_path=decode_path,
1515 self.assertEqual(err.exception.offset, offset)
1516 self.assertEqual(err.exception.decode_path, decode_path)
1519 integers(min_value=128),
1520 integers(min_value=0),
1523 def test_bad_len(self, l, offset, decode_path):
1524 with self.assertRaises(DecodeError) as err:
1526 BitString.tag_default + len_encode(l)[:-1],
1528 decode_path=decode_path,
1531 self.assertEqual(err.exception.offset, offset)
1532 self.assertEqual(err.exception.decode_path, decode_path)
1534 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1535 @given(data_strategy())
1536 def test_symmetric(self, d):
1545 ) = d.draw(bit_string_values_strategy(value_required=True))
1546 tail_junk = d.draw(binary(max_size=5))
1547 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1548 offset = d.draw(integers(min_value=0))
1549 decode_path = d.draw(decode_path_strat)
1550 for klass in (BitString, BitStringInherited):
1561 pprint(obj, big_blobs=True, with_decode_path=True)
1562 self.assertFalse(obj.expled)
1563 obj_encoded = obj.encode()
1564 self.assertEqual(encode2pass(obj), obj_encoded)
1565 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1566 obj_expled = obj(value, expl=tag_expl)
1567 self.assertTrue(obj_expled.expled)
1569 list(obj_expled.pps())
1570 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1571 obj_expled_encoded = obj_expled.encode()
1572 obj_expled_cer = encode_cer(obj_expled)
1573 self.assertNotEqual(obj_expled_cer, obj_encoded)
1574 self.assertSequenceEqual(
1575 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1578 ctx_copied = deepcopy(ctx_dummy)
1579 obj_decoded, tail = obj_expled.decode(
1580 obj_expled_encoded + tail_junk,
1584 self.assertDictEqual(ctx_copied, ctx_dummy)
1586 list(obj_decoded.pps())
1587 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1588 self.assertEqual(tail, tail_junk)
1589 self.assertEqual(obj_decoded, obj_expled)
1590 self.assertNotEqual(obj_decoded, obj)
1591 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1592 self.assertEqual(bytes(obj_decoded), bytes(obj))
1593 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1594 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1595 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1597 obj_decoded.expl_llen,
1598 len(len_encode(len(obj_encoded))),
1600 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1601 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1604 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1606 self.assertEqual(obj_decoded.expl_offset, offset)
1607 if isinstance(value, tuple):
1608 self.assertSetEqual(set(value), set(obj_decoded.named))
1611 assert_exceeding_data(
1613 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1617 evgens = list(obj_expled.decode_evgen(
1618 obj_expled_encoded + tail_junk,
1620 decode_path=decode_path,
1623 self.assertEqual(len(evgens), 1)
1624 _decode_path, obj, tail = evgens[0]
1625 self.assertSequenceEqual(tail, tail_junk)
1626 self.assertEqual(_decode_path, decode_path)
1627 self.assertEqual(obj.expl_offset, offset)
1631 @given(integers(min_value=1, max_value=255))
1632 def test_bad_zero_value(self, pad_size):
1633 with self.assertRaises(DecodeError):
1634 BitString().decode(b"".join((
1635 BitString.tag_default,
1640 def test_go_vectors_invalid(self):
1646 with self.assertRaises(DecodeError):
1647 BitString().decode(b"".join((
1648 BitString.tag_default,
1653 def test_go_vectors_valid(self):
1654 obj, _ = BitString().decode(b"".join((
1655 BitString.tag_default,
1659 self.assertEqual(bytes(obj), b"")
1660 self.assertEqual(obj.bit_len, 0)
1662 obj, _ = BitString().decode(b"".join((
1663 BitString.tag_default,
1667 self.assertEqual(bytes(obj), b"\x00")
1668 self.assertEqual(obj.bit_len, 1)
1670 obj = BitString((16, b"\x82\x40"))
1671 self.assertTrue(obj[0])
1672 self.assertFalse(obj[1])
1673 self.assertTrue(obj[6])
1674 self.assertTrue(obj[9])
1675 self.assertFalse(obj[17])
1677 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1679 integers(min_value=1, max_value=30),
1682 binary(min_size=1, max_size=5),
1684 binary(min_size=1, max_size=5),
1692 lists(booleans(), min_size=1),
1696 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk, decode_path):
1697 def chunk_constructed(contents):
1699 tag_encode(form=TagFormConstructed, num=3) +
1701 b"".join(BitString(content).encode() for content in contents) +
1705 chunks_len_expected = []
1706 payload_expected = b""
1707 bit_len_expected = 0
1708 for chunk_input in chunk_inputs:
1709 if isinstance(chunk_input, bytes):
1710 chunks.append(BitString(chunk_input).encode())
1711 payload_expected += chunk_input
1712 bit_len_expected += len(chunk_input) * 8
1713 chunks_len_expected.append(len(chunk_input) + 1)
1715 chunks.append(chunk_constructed(chunk_input))
1716 payload = b"".join(chunk_input)
1717 payload_expected += payload
1718 bit_len_expected += len(payload) * 8
1719 for c in chunk_input:
1720 chunks_len_expected.append(len(c) + 1)
1721 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
1722 chunk_last = BitString("'%s'B" % "".join(
1723 "1" if bit else "0" for bit in chunk_last_bits
1725 chunks_len_expected.append(BitString().decod(chunk_last.encode()).vlen)
1726 payload_expected += bytes(chunk_last)
1727 bit_len_expected += chunk_last.bit_len
1728 encoded_indefinite = (
1729 tag_encode(form=TagFormConstructed, num=impl) +
1732 chunk_last.encode() +
1735 encoded_definite = (
1736 tag_encode(form=TagFormConstructed, num=impl) +
1737 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1741 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
1742 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1743 for lenindef_expected, encoded in (
1744 (True, encoded_indefinite),
1745 (False, encoded_definite),
1747 obj, tail = BitString(impl=tag_encode(impl)).decode(
1749 ctx={"bered": True},
1751 self.assertSequenceEqual(tail, junk)
1752 self.assertEqual(obj.bit_len, bit_len_expected)
1753 self.assertSequenceEqual(bytes(obj), payload_expected)
1754 self.assertTrue(obj.ber_encoded)
1755 self.assertEqual(obj.lenindef, lenindef_expected)
1756 self.assertTrue(obj.bered)
1758 self.assertTrue(obj.ber_encoded)
1759 self.assertEqual(obj.lenindef, lenindef_expected)
1760 self.assertTrue(obj.bered)
1761 self.assertEqual(len(encoded), obj.tlvlen)
1764 pprint(obj, big_blobs=True, with_decode_path=True)
1766 evgens = list(BitString(impl=tag_encode(impl)).decode_evgen(
1768 decode_path=decode_path,
1769 ctx={"bered": True},
1771 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
1772 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
1773 self.assertGreater(len(dp), len(decode_path))
1774 self.assertEqual(obj.vlen, chunk_len_expected)
1777 integers(min_value=0),
1780 def test_ber_definite_too_short(self, offset, decode_path):
1781 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
1783 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1785 decode_path=decode_path,
1786 ctx={"bered": True},
1788 self.assertEqual(err.exception.decode_path, decode_path)
1789 self.assertEqual(err.exception.offset, offset)
1792 integers(min_value=0),
1795 def test_ber_definite_no_data(self, offset, decode_path):
1796 with self.assertRaisesRegex(DecodeError, "zero length") as err:
1798 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1800 decode_path=decode_path,
1801 ctx={"bered": True},
1803 self.assertEqual(err.exception.decode_path, decode_path)
1804 self.assertEqual(err.exception.offset, offset)
1807 integers(min_value=0),
1809 integers(min_value=1, max_value=3),
1811 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1812 bs = BitString(b"data").encode()
1813 with self.assertRaises(NotEnoughData) as err:
1815 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1817 decode_path=decode_path,
1818 ctx={"bered": True},
1820 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1821 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1824 integers(min_value=0),
1826 integers(min_value=1, max_value=3),
1828 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1829 bs = BitString(b"data").encode()
1830 bs_longer = BitString(b"data-longer").encode()
1831 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
1834 tag_encode(3, form=TagFormConstructed) +
1835 len_encode((chunks + 1) * len(bs)) +
1840 decode_path=decode_path,
1841 ctx={"bered": True},
1843 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1844 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1847 integers(min_value=0),
1850 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1851 with self.assertRaisesRegex(DecodeError, "no chunks") as err:
1853 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1855 decode_path=decode_path,
1856 ctx={"bered": True},
1858 self.assertEqual(err.exception.decode_path, decode_path)
1859 self.assertEqual(err.exception.offset, offset)
1861 @given(data_strategy())
1862 def test_ber_indefinite_not_multiple(self, d):
1863 bs_short = BitString("'A'H").encode()
1864 bs_full = BitString("'AA'H").encode()
1865 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1866 chunks.append(bs_short)
1867 d.draw(permutations(chunks))
1868 chunks.append(bs_short)
1869 offset = d.draw(integers(min_value=0))
1870 decode_path = d.draw(decode_path_strat)
1871 with self.assertRaisesRegex(DecodeError, "multiple of 8 bits") as err:
1874 tag_encode(3, form=TagFormConstructed) +
1880 decode_path=decode_path,
1881 ctx={"bered": True},
1884 err.exception.decode_path,
1885 decode_path + (str(chunks.index(bs_short)),),
1888 err.exception.offset,
1889 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1892 def test_x690_vector(self):
1893 vector = BitString("'0A3B5F291CD'H")
1894 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1895 self.assertSequenceEqual(tail, b"")
1896 self.assertEqual(obj, vector)
1897 obj, tail = BitString().decode(
1898 hexdec("23800303000A3B0305045F291CD00000"),
1899 ctx={"bered": True},
1901 self.assertSequenceEqual(tail, b"")
1902 self.assertEqual(obj, vector)
1903 self.assertTrue(obj.ber_encoded)
1904 self.assertTrue(obj.lenindef)
1905 self.assertTrue(obj.bered)
1907 self.assertTrue(obj.ber_encoded)
1908 self.assertTrue(obj.lenindef)
1909 self.assertTrue(obj.bered)
1911 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1912 @given(integers(min_value=1000, max_value=3000))
1913 def test_cer(self, data_len):
1914 data = urandom(data_len)
1915 encoded = encode_cer(BitString(data))
1916 ctx = {"bered": True}
1917 self.assertSequenceEqual(bytes(BitString().decod(encoded, ctx=ctx)), data)
1918 evgens = list(BitString().decode_evgen(encoded, ctx=ctx))
1919 evgens_expected = data_len // 999
1920 if evgens_expected * 999 != data_len:
1921 evgens_expected += 1
1922 evgens_expected += 1
1923 self.assertEqual(len(evgens), evgens_expected)
1924 for (_, obj, _) in evgens[:-2]:
1925 self.assertEqual(obj.vlen, 1000)
1926 _, obj, _ = evgens[-2]
1927 self.assertEqual(obj.vlen, 1 + data_len - len(evgens[:-2]) * 999)
1931 def octet_string_values_strategy(draw, do_expl=False):
1932 bound_min, bound_max = sorted(draw(sets(
1933 integers(min_value=0, max_value=1 << 7),
1937 value = draw(one_of(
1939 binary(min_size=bound_min, max_size=bound_max),
1941 default = draw(one_of(
1943 binary(min_size=bound_min, max_size=bound_max),
1946 if draw(booleans()):
1947 bounds = (bound_min, bound_max)
1951 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1953 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1954 optional = draw(one_of(none(), booleans()))
1956 draw(integers(min_value=0)),
1957 draw(integers(min_value=0)),
1958 draw(integers(min_value=0)),
1960 return (value, bounds, impl, expl, default, optional, _decoded)
1963 class OctetStringInherited(OctetString):
1967 class TestOctetString(CommonMixin, TestCase):
1968 base_klass = OctetString
1970 def test_invalid_value_type(self):
1971 with self.assertRaises(InvalidValueType) as err:
1972 OctetString(str(123))
1976 def test_optional(self, optional):
1977 obj = OctetString(default=OctetString(b""), optional=optional)
1978 self.assertTrue(obj.optional)
1981 def test_ready(self, value):
1983 self.assertFalse(obj.ready)
1986 pprint(obj, big_blobs=True, with_decode_path=True)
1987 with self.assertRaises(ObjNotReady) as err:
1990 with self.assertRaises(ObjNotReady) as err:
1992 obj = OctetString(value)
1993 self.assertTrue(obj.ready)
1996 pprint(obj, big_blobs=True, with_decode_path=True)
1998 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1999 def test_comparison(self, value1, value2, tag1, tag2):
2000 for klass in (OctetString, OctetStringInherited):
2001 obj1 = klass(value1)
2002 obj2 = klass(value2)
2003 self.assertEqual(obj1 == obj2, value1 == value2)
2004 self.assertEqual(obj1 != obj2, value1 != value2)
2005 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2006 obj1 = klass(value1, impl=tag1)
2007 obj2 = klass(value1, impl=tag2)
2008 self.assertEqual(obj1 == obj2, tag1 == tag2)
2009 self.assertEqual(obj1 != obj2, tag1 != tag2)
2011 @given(lists(binary()))
2012 def test_sorted_works(self, values):
2013 self.assertSequenceEqual(
2014 [bytes(v) for v in sorted(OctetString(v) for v in values)],
2018 @given(data_strategy())
2019 def test_bounds_satisfied(self, d):
2020 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2021 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2022 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
2023 OctetString(value=value, bounds=(bound_min, bound_max))
2025 @given(data_strategy())
2026 def test_bounds_unsatisfied(self, d):
2027 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2028 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2029 value = d.draw(binary(max_size=bound_min - 1))
2030 with self.assertRaises(BoundsError) as err:
2031 OctetString(value=value, bounds=(bound_min, bound_max))
2033 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2034 OctetString(bounds=(bound_min, bound_max)).decode(
2035 OctetString(value).encode()
2038 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2039 OctetString(bounds=(bound_min, bound_max)).decode(
2040 encode2pass(OctetString(value))
2042 value = d.draw(binary(min_size=bound_max + 1))
2043 with self.assertRaises(BoundsError) as err:
2044 OctetString(value=value, bounds=(bound_min, bound_max))
2046 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2047 OctetString(bounds=(bound_min, bound_max)).decode(
2048 OctetString(value).encode()
2051 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2052 OctetString(bounds=(bound_min, bound_max)).decode(
2053 encode2pass(OctetString(value))
2056 @given(data_strategy())
2057 def test_call(self, d):
2058 for klass in (OctetString, OctetStringInherited):
2067 ) = d.draw(octet_string_values_strategy())
2068 obj_initial = klass(
2074 optional_initial or False,
2085 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
2086 if (default is None) and (obj_initial.default is not None):
2089 (bounds is None) and
2090 (value is not None) and
2091 (bounds_initial is not None) and
2092 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2096 (bounds is None) and
2097 (default is not None) and
2098 (bounds_initial is not None) and
2099 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2102 obj = obj_initial(value, bounds, impl, expl, default, optional)
2104 value_expected = default if value is None else value
2106 default_initial if value_expected is None
2109 self.assertEqual(obj, value_expected)
2110 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2111 self.assertEqual(obj.expl_tag, expl or expl_initial)
2114 default_initial if default is None else default,
2116 if obj.default is None:
2117 optional = optional_initial if optional is None else optional
2118 optional = False if optional is None else optional
2121 self.assertEqual(obj.optional, optional)
2123 (obj._bound_min, obj._bound_max),
2124 bounds or bounds_initial or (0, float("+inf")),
2127 @given(octet_string_values_strategy())
2128 def test_copy(self, values):
2129 for klass in (OctetString, OctetStringInherited):
2130 obj = klass(*values)
2131 for copy_func in copy_funcs:
2132 obj_copied = copy_func(obj)
2133 self.assert_copied_basic_fields(obj, obj_copied)
2134 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2135 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2136 self.assertEqual(obj._value, obj_copied._value)
2140 integers(min_value=1).map(tag_encode),
2142 def test_stripped(self, value, tag_impl):
2143 obj = OctetString(value, impl=tag_impl)
2144 with self.assertRaises(NotEnoughData):
2145 obj.decode(obj.encode()[:-1])
2149 integers(min_value=1).map(tag_ctxc),
2151 def test_stripped_expl(self, value, tag_expl):
2152 obj = OctetString(value, expl=tag_expl)
2153 with self.assertRaises(NotEnoughData):
2154 obj.decode(obj.encode()[:-1])
2157 integers(min_value=31),
2158 integers(min_value=0),
2161 def test_bad_tag(self, tag, offset, decode_path):
2162 with self.assertRaises(DecodeError) as err:
2163 OctetString().decode(
2164 tag_encode(tag)[:-1],
2166 decode_path=decode_path,
2169 self.assertEqual(err.exception.offset, offset)
2170 self.assertEqual(err.exception.decode_path, decode_path)
2173 integers(min_value=128),
2174 integers(min_value=0),
2177 def test_bad_len(self, l, offset, decode_path):
2178 with self.assertRaises(DecodeError) as err:
2179 OctetString().decode(
2180 OctetString.tag_default + len_encode(l)[:-1],
2182 decode_path=decode_path,
2185 self.assertEqual(err.exception.offset, offset)
2186 self.assertEqual(err.exception.decode_path, decode_path)
2189 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2190 integers(min_value=0),
2193 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2194 value, bound_min = list(sorted(ints))
2196 class String(OctetString):
2197 bounds = (bound_min, bound_min)
2198 with self.assertRaises(DecodeError) as err:
2200 OctetString(b"\x00" * value).encode(),
2202 decode_path=decode_path,
2205 self.assertEqual(err.exception.offset, offset)
2206 self.assertEqual(err.exception.decode_path, decode_path)
2208 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2210 octet_string_values_strategy(),
2212 integers(min_value=1).map(tag_ctxc),
2213 integers(min_value=0),
2217 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2218 for klass in (OctetString, OctetStringInherited):
2219 _, _, _, _, default, optional, _decoded = values
2228 pprint(obj, big_blobs=True, with_decode_path=True)
2229 self.assertFalse(obj.expled)
2230 obj_encoded = obj.encode()
2231 self.assertEqual(encode2pass(obj), obj_encoded)
2232 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2233 obj_expled = obj(value, expl=tag_expl)
2234 self.assertTrue(obj_expled.expled)
2236 list(obj_expled.pps())
2237 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2238 obj_expled_encoded = obj_expled.encode()
2239 obj_expled_cer = encode_cer(obj_expled)
2240 self.assertNotEqual(obj_expled_cer, obj_encoded)
2241 self.assertSequenceEqual(
2242 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2245 ctx_copied = deepcopy(ctx_dummy)
2246 obj_decoded, tail = obj_expled.decode(
2247 obj_expled_encoded + tail_junk,
2251 self.assertDictEqual(ctx_copied, ctx_dummy)
2253 list(obj_decoded.pps())
2254 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2255 self.assertEqual(tail, tail_junk)
2256 self.assertEqual(obj_decoded, obj_expled)
2257 self.assertNotEqual(obj_decoded, obj)
2258 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2259 self.assertEqual(bytes(obj_decoded), bytes(obj))
2260 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2261 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2262 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2264 obj_decoded.expl_llen,
2265 len(len_encode(len(obj_encoded))),
2267 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2268 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2271 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2273 self.assertEqual(obj_decoded.expl_offset, offset)
2274 assert_exceeding_data(
2276 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2280 evgens = list(obj_expled.decode_evgen(
2281 obj_expled_encoded + tail_junk,
2283 decode_path=decode_path,
2286 self.assertEqual(len(evgens), 1)
2287 _decode_path, obj, tail = evgens[0]
2288 self.assertSequenceEqual(tail, tail_junk)
2289 self.assertEqual(_decode_path, decode_path)
2290 self.assertEqual(obj.expl_offset, offset)
2294 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2296 integers(min_value=1, max_value=30),
2299 binary(min_size=1, max_size=5),
2301 binary(min_size=1, max_size=5),
2312 def test_constructed(self, impl, chunk_inputs, junk, decode_path):
2313 def chunk_constructed(contents):
2315 tag_encode(form=TagFormConstructed, num=4) +
2317 b"".join(OctetString(content).encode() for content in contents) +
2321 chunks_len_expected = []
2322 payload_expected = b""
2323 for chunk_input in chunk_inputs:
2324 if isinstance(chunk_input, bytes):
2325 chunks.append(OctetString(chunk_input).encode())
2326 payload_expected += chunk_input
2327 chunks_len_expected.append(len(chunk_input))
2329 chunks.append(chunk_constructed(chunk_input))
2330 payload = b"".join(chunk_input)
2331 payload_expected += payload
2332 for c in chunk_input:
2333 chunks_len_expected.append(len(c))
2334 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
2335 encoded_indefinite = (
2336 tag_encode(form=TagFormConstructed, num=impl) +
2341 encoded_definite = (
2342 tag_encode(form=TagFormConstructed, num=impl) +
2343 len_encode(len(b"".join(chunks))) +
2346 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
2347 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2348 for lenindef_expected, encoded in (
2349 (True, encoded_indefinite),
2350 (False, encoded_definite),
2352 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2354 ctx={"bered": True},
2356 self.assertSequenceEqual(tail, junk)
2357 self.assertSequenceEqual(bytes(obj), payload_expected)
2358 self.assertTrue(obj.ber_encoded)
2359 self.assertEqual(obj.lenindef, lenindef_expected)
2360 self.assertTrue(obj.bered)
2362 self.assertTrue(obj.ber_encoded)
2363 self.assertEqual(obj.lenindef, lenindef_expected)
2364 self.assertTrue(obj.bered)
2365 self.assertEqual(len(encoded), obj.tlvlen)
2368 pprint(obj, big_blobs=True, with_decode_path=True)
2370 evgens = list(OctetString(impl=tag_encode(impl)).decode_evgen(
2372 decode_path=decode_path,
2373 ctx={"bered": True},
2375 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
2376 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
2377 self.assertGreater(len(dp), len(decode_path))
2378 self.assertEqual(obj.vlen, chunk_len_expected)
2381 integers(min_value=0),
2384 def test_ber_definite_too_short(self, offset, decode_path):
2385 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
2386 OctetString().decode(
2387 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2389 decode_path=decode_path,
2390 ctx={"bered": True},
2392 self.assertEqual(err.exception.decode_path, decode_path)
2393 self.assertEqual(err.exception.offset, offset)
2396 integers(min_value=0),
2398 integers(min_value=1, max_value=3),
2400 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2401 bs = OctetString(b"data").encode()
2402 with self.assertRaises(NotEnoughData) as err:
2403 OctetString().decode(
2404 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2406 decode_path=decode_path,
2407 ctx={"bered": True},
2409 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2410 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2413 integers(min_value=0),
2415 integers(min_value=1, max_value=3),
2417 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2418 bs = OctetString(b"data").encode()
2419 bs_longer = OctetString(b"data-longer").encode()
2420 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
2421 OctetString().decode(
2423 tag_encode(4, form=TagFormConstructed) +
2424 len_encode((chunks + 1) * len(bs)) +
2429 decode_path=decode_path,
2430 ctx={"bered": True},
2432 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2433 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2435 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2436 @given(integers(min_value=1001, max_value=3000))
2437 def test_cer(self, data_len):
2438 data = urandom(data_len)
2439 encoded = encode_cer(OctetString(data))
2440 ctx = {"bered": True}
2441 self.assertSequenceEqual(bytes(OctetString().decod(encoded, ctx=ctx)), data)
2442 evgens = list(OctetString().decode_evgen(encoded, ctx=ctx))
2443 evgens_expected = data_len // 1000
2444 if evgens_expected * 1000 != data_len:
2445 evgens_expected += 1
2446 evgens_expected += 1
2447 self.assertEqual(len(evgens), evgens_expected)
2448 for (_, obj, _) in evgens[:-2]:
2449 self.assertEqual(obj.vlen, 1000)
2450 _, obj, _ = evgens[-2]
2451 self.assertEqual(obj.vlen, data_len - len(evgens[:-2]) * 1000)
2455 def null_values_strategy(draw, do_expl=False):
2459 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2461 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2462 optional = draw(one_of(none(), booleans()))
2464 draw(integers(min_value=0)),
2465 draw(integers(min_value=0)),
2466 draw(integers(min_value=0)),
2468 return (impl, expl, optional, _decoded)
2471 class NullInherited(Null):
2475 class TestNull(CommonMixin, TestCase):
2478 def test_ready(self):
2480 self.assertTrue(obj.ready)
2483 pprint(obj, big_blobs=True, with_decode_path=True)
2485 @given(binary(min_size=1), binary(min_size=1))
2486 def test_comparison(self, tag1, tag2):
2487 for klass in (Null, NullInherited):
2488 obj1 = klass(impl=tag1)
2489 obj2 = klass(impl=tag2)
2490 self.assertEqual(obj1 == obj2, tag1 == tag2)
2491 self.assertEqual(obj1 != obj2, tag1 != tag2)
2492 self.assertNotEqual(obj1, tag2)
2494 @given(data_strategy())
2495 def test_call(self, d):
2496 for klass in (Null, NullInherited):
2502 ) = d.draw(null_values_strategy())
2503 obj_initial = klass(
2506 optional=optional_initial or False,
2507 _decoded=_decoded_initial,
2514 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2515 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2516 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2517 self.assertEqual(obj.expl_tag, expl or expl_initial)
2518 optional = optional_initial if optional is None else optional
2519 optional = False if optional is None else optional
2520 self.assertEqual(obj.optional, optional)
2522 @given(null_values_strategy())
2523 def test_copy(self, values):
2524 for klass in (Null, NullInherited):
2525 impl, expl, optional, _decoded = values
2529 optional=optional or False,
2532 for copy_func in copy_funcs:
2533 obj_copied = copy_func(obj)
2534 self.assert_copied_basic_fields(obj, obj_copied)
2536 @given(integers(min_value=1).map(tag_encode))
2537 def test_stripped(self, tag_impl):
2538 obj = Null(impl=tag_impl)
2539 with self.assertRaises(NotEnoughData):
2540 obj.decode(obj.encode()[:-1])
2542 @given(integers(min_value=1).map(tag_ctxc))
2543 def test_stripped_expl(self, tag_expl):
2544 obj = Null(expl=tag_expl)
2545 with self.assertRaises(NotEnoughData):
2546 obj.decode(obj.encode()[:-1])
2549 integers(min_value=31),
2550 integers(min_value=0),
2553 def test_bad_tag(self, tag, offset, decode_path):
2554 with self.assertRaises(DecodeError) as err:
2556 tag_encode(tag)[:-1],
2558 decode_path=decode_path,
2561 self.assertEqual(err.exception.offset, offset)
2562 self.assertEqual(err.exception.decode_path, decode_path)
2565 integers(min_value=128),
2566 integers(min_value=0),
2569 def test_bad_len(self, l, offset, decode_path):
2570 with self.assertRaises(DecodeError) as err:
2572 Null.tag_default + len_encode(l)[:-1],
2574 decode_path=decode_path,
2577 self.assertEqual(err.exception.offset, offset)
2578 self.assertEqual(err.exception.decode_path, decode_path)
2580 @given(binary(min_size=1))
2581 def test_tag_mismatch(self, impl):
2582 assume(impl != Null.tag_default)
2583 with self.assertRaises(TagMismatch):
2584 Null(impl=impl).decode(Null().encode())
2587 null_values_strategy(),
2588 integers(min_value=1).map(tag_ctxc),
2589 integers(min_value=0),
2593 def test_symmetric(self, values, tag_expl, offset, tail_junk, decode_path):
2594 for klass in (Null, NullInherited):
2595 _, _, optional, _decoded = values
2596 obj = klass(optional=optional, _decoded=_decoded)
2599 pprint(obj, big_blobs=True, with_decode_path=True)
2600 self.assertFalse(obj.expled)
2601 obj_encoded = obj.encode()
2602 self.assertEqual(encode2pass(obj), obj_encoded)
2603 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2604 obj_expled = obj(expl=tag_expl)
2605 self.assertTrue(obj_expled.expled)
2607 list(obj_expled.pps())
2608 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2609 obj_expled_encoded = obj_expled.encode()
2610 obj_expled_cer = encode_cer(obj_expled)
2611 self.assertNotEqual(obj_expled_cer, obj_encoded)
2612 self.assertSequenceEqual(
2613 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2616 ctx_copied = deepcopy(ctx_dummy)
2617 obj_decoded, tail = obj_expled.decode(
2618 obj_expled_encoded + tail_junk,
2622 self.assertDictEqual(ctx_copied, ctx_dummy)
2624 list(obj_decoded.pps())
2625 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2626 self.assertEqual(tail, tail_junk)
2627 self.assertEqual(obj_decoded, obj_expled)
2628 self.assertNotEqual(obj_decoded, obj)
2629 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2630 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2631 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2633 obj_decoded.expl_llen,
2634 len(len_encode(len(obj_encoded))),
2636 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2637 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2640 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2642 self.assertEqual(obj_decoded.expl_offset, offset)
2643 assert_exceeding_data(
2645 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2649 evgens = list(obj_expled.decode_evgen(
2650 obj_expled_encoded + tail_junk,
2652 decode_path=decode_path,
2655 self.assertEqual(len(evgens), 1)
2656 _decode_path, obj, tail = evgens[0]
2657 self.assertSequenceEqual(tail, tail_junk)
2658 self.assertEqual(_decode_path, decode_path)
2659 self.assertEqual(obj, obj_decoded)
2660 self.assertEqual(obj.expl_offset, offset)
2664 @given(integers(min_value=1))
2665 def test_invalid_len(self, l):
2666 with self.assertRaises(InvalidLength):
2667 Null().decode(b"".join((
2674 def oid_strategy(draw):
2675 first_arc = draw(integers(min_value=0, max_value=2))
2677 if first_arc in (0, 1):
2678 second_arc = draw(integers(min_value=0, max_value=39))
2680 second_arc = draw(integers(min_value=0))
2681 other_arcs = draw(lists(integers(min_value=0)))
2682 return tuple([first_arc, second_arc] + other_arcs)
2686 def oid_values_strategy(draw, do_expl=False):
2687 value = draw(one_of(none(), oid_strategy()))
2691 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2693 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2694 default = draw(one_of(none(), oid_strategy()))
2695 optional = draw(one_of(none(), booleans()))
2697 draw(integers(min_value=0)),
2698 draw(integers(min_value=0)),
2699 draw(integers(min_value=0)),
2701 return (value, impl, expl, default, optional, _decoded)
2704 class ObjectIdentifierInherited(ObjectIdentifier):
2708 class TestObjectIdentifier(CommonMixin, TestCase):
2709 base_klass = ObjectIdentifier
2711 def test_invalid_value_type(self):
2712 with self.assertRaises(InvalidValueType) as err:
2713 ObjectIdentifier(123)
2717 def test_optional(self, optional):
2718 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2719 self.assertTrue(obj.optional)
2721 @given(oid_strategy())
2722 def test_ready(self, value):
2723 obj = ObjectIdentifier()
2724 self.assertFalse(obj.ready)
2727 pprint(obj, big_blobs=True, with_decode_path=True)
2728 with self.assertRaises(ObjNotReady) as err:
2731 with self.assertRaises(ObjNotReady) as err:
2733 obj = ObjectIdentifier(value)
2734 self.assertTrue(obj.ready)
2735 self.assertFalse(obj.ber_encoded)
2738 pprint(obj, big_blobs=True, with_decode_path=True)
2741 @given(oid_strategy(), oid_strategy(), binary(min_size=1), binary(min_size=1))
2742 def test_comparison(self, value1, value2, tag1, tag2):
2743 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2744 obj1 = klass(value1)
2745 obj2 = klass(value2)
2746 self.assertEqual(obj1 == obj2, value1 == value2)
2747 self.assertEqual(obj1 != obj2, value1 != value2)
2748 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2749 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2750 obj1 = klass(value1, impl=tag1)
2751 obj2 = klass(value1, impl=tag2)
2752 self.assertEqual(obj1 == obj2, tag1 == tag2)
2753 self.assertEqual(obj1 != obj2, tag1 != tag2)
2755 @given(lists(oid_strategy()))
2756 def test_sorted_works(self, values):
2757 self.assertSequenceEqual(
2758 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2762 @given(data_strategy())
2763 def test_call(self, d):
2764 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2772 ) = d.draw(oid_values_strategy())
2773 obj_initial = klass(
2774 value=value_initial,
2777 default=default_initial,
2778 optional=optional_initial or False,
2779 _decoded=_decoded_initial,
2788 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2797 value_expected = default if value is None else value
2799 default_initial if value_expected is None
2802 self.assertEqual(obj, value_expected)
2803 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2804 self.assertEqual(obj.expl_tag, expl or expl_initial)
2807 default_initial if default is None else default,
2809 if obj.default is None:
2810 optional = optional_initial if optional is None else optional
2811 optional = False if optional is None else optional
2814 self.assertEqual(obj.optional, optional)
2816 @given(oid_values_strategy())
2817 def test_copy(self, values):
2818 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2835 for copy_func in copy_funcs:
2836 obj_copied = copy_func(obj)
2837 self.assert_copied_basic_fields(obj, obj_copied)
2838 self.assertEqual(obj._value, obj_copied._value)
2840 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2843 integers(min_value=1).map(tag_encode),
2845 def test_stripped(self, value, tag_impl):
2846 obj = ObjectIdentifier(value, impl=tag_impl)
2847 with self.assertRaises(NotEnoughData):
2848 obj.decode(obj.encode()[:-1])
2852 integers(min_value=1).map(tag_ctxc),
2854 def test_stripped_expl(self, value, tag_expl):
2855 obj = ObjectIdentifier(value, expl=tag_expl)
2856 with self.assertRaises(NotEnoughData):
2857 obj.decode(obj.encode()[:-1])
2860 integers(min_value=31),
2861 integers(min_value=0),
2864 def test_bad_tag(self, tag, offset, decode_path):
2865 with self.assertRaises(DecodeError) as err:
2866 ObjectIdentifier().decode(
2867 tag_encode(tag)[:-1],
2869 decode_path=decode_path,
2872 self.assertEqual(err.exception.offset, offset)
2873 self.assertEqual(err.exception.decode_path, decode_path)
2876 integers(min_value=128),
2877 integers(min_value=0),
2880 def test_bad_len(self, l, offset, decode_path):
2881 with self.assertRaises(DecodeError) as err:
2882 ObjectIdentifier().decode(
2883 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2885 decode_path=decode_path,
2888 self.assertEqual(err.exception.offset, offset)
2889 self.assertEqual(err.exception.decode_path, decode_path)
2891 def test_zero_oid(self):
2892 with self.assertRaises(NotEnoughData):
2893 ObjectIdentifier().decode(
2894 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2897 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2898 @given(oid_strategy())
2899 def test_unfinished_oid(self, value):
2900 assume(list(value)[-1] > 255)
2901 obj_encoded = ObjectIdentifier(value).encode()
2902 obj, _ = ObjectIdentifier().decode(obj_encoded)
2903 data = obj_encoded[obj.tlen + obj.llen:-1]
2905 ObjectIdentifier.tag_default,
2906 len_encode(len(data)),
2909 with self.assertRaisesRegex(DecodeError, "unfinished OID"):
2912 @given(integers(min_value=0))
2913 def test_invalid_short(self, value):
2914 with self.assertRaises(InvalidOID):
2915 ObjectIdentifier((value,))
2916 with self.assertRaises(InvalidOID):
2917 ObjectIdentifier("%d" % value)
2919 @given(integers(min_value=3), integers(min_value=0))
2920 def test_invalid_first_arc(self, first_arc, second_arc):
2921 with self.assertRaises(InvalidOID):
2922 ObjectIdentifier((first_arc, second_arc))
2923 with self.assertRaises(InvalidOID):
2924 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2926 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2927 def test_invalid_second_arc(self, first_arc, second_arc):
2928 with self.assertRaises(InvalidOID):
2929 ObjectIdentifier((first_arc, second_arc))
2930 with self.assertRaises(InvalidOID):
2931 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2933 @given(text(alphabet=ascii_letters + ".", min_size=1))
2934 def test_junk(self, oid):
2935 with self.assertRaises(InvalidOID):
2936 ObjectIdentifier(oid)
2938 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2939 @given(oid_strategy())
2940 def test_validness(self, oid):
2941 obj = ObjectIdentifier(oid)
2942 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2945 pprint(obj, big_blobs=True, with_decode_path=True)
2947 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2949 oid_values_strategy(),
2951 integers(min_value=1).map(tag_ctxc),
2952 integers(min_value=0),
2956 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2957 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2958 _, _, _, default, optional, _decoded = values
2967 pprint(obj, big_blobs=True, with_decode_path=True)
2968 self.assertFalse(obj.expled)
2969 obj_encoded = obj.encode()
2970 self.assertEqual(encode2pass(obj), obj_encoded)
2971 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2972 obj_expled = obj(value, expl=tag_expl)
2973 self.assertTrue(obj_expled.expled)
2975 list(obj_expled.pps())
2976 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2977 obj_expled_encoded = obj_expled.encode()
2978 obj_expled_cer = encode_cer(obj_expled)
2979 self.assertNotEqual(obj_expled_cer, obj_encoded)
2980 self.assertSequenceEqual(
2981 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2984 ctx_copied = deepcopy(ctx_dummy)
2985 obj_decoded, tail = obj_expled.decode(
2986 obj_expled_encoded + tail_junk,
2990 self.assertDictEqual(ctx_copied, ctx_dummy)
2992 list(obj_decoded.pps())
2993 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2994 self.assertEqual(tail, tail_junk)
2995 self.assertEqual(obj_decoded, obj_expled)
2996 self.assertNotEqual(obj_decoded, obj)
2997 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2998 self.assertEqual(tuple(obj_decoded), tuple(obj))
2999 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3000 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3001 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3003 obj_decoded.expl_llen,
3004 len(len_encode(len(obj_encoded))),
3006 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3007 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3010 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3012 self.assertEqual(obj_decoded.expl_offset, offset)
3013 assert_exceeding_data(
3015 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3019 evgens = list(obj_expled.decode_evgen(
3020 obj_expled_encoded + tail_junk,
3022 decode_path=decode_path,
3025 self.assertEqual(len(evgens), 1)
3026 _decode_path, obj, tail = evgens[0]
3027 self.assertSequenceEqual(tail, tail_junk)
3028 self.assertEqual(_decode_path, decode_path)
3029 self.assertEqual(obj, obj_decoded)
3030 self.assertEqual(obj.expl_offset, offset)
3035 oid_strategy().map(ObjectIdentifier),
3036 oid_strategy().map(ObjectIdentifier),
3038 def test_add(self, oid1, oid2):
3039 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
3040 for oid_to_add in (oid2, tuple(oid2)):
3041 self.assertEqual(oid1 + oid_to_add, oid_expect)
3042 with self.assertRaises(InvalidValueType):
3045 def test_go_vectors_valid(self):
3046 for data, expect in (
3048 (b"\x55\x02", (2, 5, 2)),
3049 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
3050 (b"\x81\x34\x03", (2, 100, 3)),
3053 ObjectIdentifier().decode(b"".join((
3054 ObjectIdentifier.tag_default,
3055 len_encode(len(data)),
3061 def test_go_vectors_invalid(self):
3062 data = b"\x55\x02\xc0\x80\x80\x80\x80"
3063 with self.assertRaises(DecodeError):
3064 ObjectIdentifier().decode(b"".join((
3065 Integer.tag_default,
3066 len_encode(len(data)),
3070 def test_go_non_minimal_encoding(self):
3071 with self.assertRaises(DecodeError):
3072 ObjectIdentifier().decode(hexdec("060a2a80864886f70d01010b"))
3074 def test_x690_vector(self):
3076 ObjectIdentifier().decode(hexdec("0603883703"))[0],
3077 ObjectIdentifier((2, 999, 3)),
3080 def test_nonnormalized_first_arc(self):
3082 ObjectIdentifier.tag_default +
3085 ObjectIdentifier((1, 0)).encode()[-1:]
3087 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3088 self.assertTrue(obj.ber_encoded)
3089 self.assertTrue(obj.bered)
3091 self.assertTrue(obj.ber_encoded)
3092 self.assertTrue(obj.bered)
3093 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3094 ObjectIdentifier().decode(tampered)
3096 @given(data_strategy())
3097 def test_negative_arcs(self, d):
3098 oid = list(d.draw(oid_strategy()))
3101 idx = d.draw(integers(min_value=3, max_value=len(oid)))
3103 if oid[idx - 1] == 0:
3105 with self.assertRaises(InvalidOID):
3106 ObjectIdentifier(tuple(oid))
3107 with self.assertRaises(InvalidOID):
3108 ObjectIdentifier(".".join(str(i) for i in oid))
3110 @given(data_strategy())
3111 def test_plused_arcs(self, d):
3112 oid = [str(arc) for arc in d.draw(oid_strategy())]
3113 idx = d.draw(integers(min_value=0, max_value=len(oid)))
3114 oid[idx - 1] = "+" + oid[idx - 1]
3115 with self.assertRaises(InvalidOID):
3116 ObjectIdentifier(".".join(str(i) for i in oid))
3118 @given(data_strategy())
3119 def test_nonnormalized_arcs(self, d):
3120 arcs = d.draw(lists(
3121 integers(min_value=0, max_value=100),
3125 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
3126 _, _, lv = tag_strip(dered)
3127 _, _, v = len_decode(lv)
3128 v_no_first_arc = v[1:]
3129 idx_for_tamper = d.draw(integers(
3131 max_value=len(v_no_first_arc) - 1,
3133 tampered = list(bytearray(v_no_first_arc))
3134 for _ in range(d.draw(integers(min_value=1, max_value=3))):
3135 tampered.insert(idx_for_tamper, 0x80)
3136 tampered = bytes(bytearray(tampered))
3138 ObjectIdentifier.tag_default +
3139 len_encode(len(tampered)) +
3142 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3143 self.assertTrue(obj.ber_encoded)
3144 self.assertTrue(obj.bered)
3146 self.assertTrue(obj.ber_encoded)
3147 self.assertTrue(obj.bered)
3148 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3149 ObjectIdentifier().decode(tampered)
3153 def enumerated_values_strategy(draw, schema=None, do_expl=False):
3155 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
3156 values = list(draw(sets(
3158 min_size=len(schema),
3159 max_size=len(schema),
3161 schema = list(zip(schema, values))
3162 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
3166 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3168 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3169 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
3170 optional = draw(one_of(none(), booleans()))
3172 draw(integers(min_value=0)),
3173 draw(integers(min_value=0)),
3174 draw(integers(min_value=0)),
3176 return (schema, value, impl, expl, default, optional, _decoded)
3179 class TestEnumerated(CommonMixin, TestCase):
3180 class EWhatever(Enumerated):
3181 schema = (("whatever", 0),)
3183 base_klass = EWhatever
3185 def test_schema_required(self):
3186 with self.assertRaisesRegex(ValueError, "schema must be specified"):
3189 def test_invalid_value_type(self):
3190 with self.assertRaises(InvalidValueType) as err:
3191 self.base_klass((1, 2))
3194 @given(sets(text_letters(), min_size=2))
3195 def test_unknown_name(self, schema_input):
3196 missing = schema_input.pop()
3198 class E(Enumerated):
3199 schema = [(n, 123) for n in schema_input]
3200 with self.assertRaises(ObjUnknown) as err:
3205 sets(text_letters(), min_size=2),
3206 sets(integers(), min_size=2),
3208 def test_unknown_value(self, schema_input, values_input):
3210 missing_value = values_input.pop()
3211 _input = list(zip(schema_input, values_input))
3213 class E(Enumerated):
3215 with self.assertRaises(DecodeError) as err:
3220 def test_optional(self, optional):
3221 obj = self.base_klass(default="whatever", optional=optional)
3222 self.assertTrue(obj.optional)
3224 def test_ready(self):
3225 obj = self.base_klass()
3226 self.assertFalse(obj.ready)
3229 pprint(obj, big_blobs=True, with_decode_path=True)
3230 with self.assertRaises(ObjNotReady) as err:
3233 obj = self.base_klass("whatever")
3234 self.assertTrue(obj.ready)
3237 pprint(obj, big_blobs=True, with_decode_path=True)
3239 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
3240 def test_comparison(self, value1, value2, tag1, tag2):
3241 class E(Enumerated):
3243 ("whatever0", value1),
3244 ("whatever1", value2),
3247 class EInherited(E):
3249 for klass in (E, EInherited):
3250 obj1 = klass(value1)
3251 obj2 = klass(value2)
3252 self.assertEqual(obj1 == obj2, value1 == value2)
3253 self.assertEqual(obj1 != obj2, value1 != value2)
3254 self.assertEqual(obj1 == int(obj2), value1 == value2)
3255 obj1 = klass(value1, impl=tag1)
3256 obj2 = klass(value1, impl=tag2)
3257 self.assertEqual(obj1 == obj2, tag1 == tag2)
3258 self.assertEqual(obj1 != obj2, tag1 != tag2)
3260 @given(data_strategy())
3261 def test_call(self, d):
3270 ) = d.draw(enumerated_values_strategy())
3272 class E(Enumerated):
3273 schema = schema_initial
3275 value=value_initial,
3278 default=default_initial,
3279 optional=optional_initial or False,
3280 _decoded=_decoded_initial,
3290 ) = d.draw(enumerated_values_strategy(
3291 schema=schema_initial,
3292 do_expl=impl_initial is None,
3302 value_expected = default if value is None else value
3304 default_initial if value_expected is None
3309 dict(schema_initial).get(value_expected, value_expected),
3311 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3312 self.assertEqual(obj.expl_tag, expl or expl_initial)
3315 default_initial if default is None else default,
3317 if obj.default is None:
3318 optional = optional_initial if optional is None else optional
3319 optional = False if optional is None else optional
3322 self.assertEqual(obj.optional, optional)
3323 self.assertEqual(obj.specs, dict(schema_initial))
3325 @given(enumerated_values_strategy())
3326 def test_copy(self, values):
3327 schema_input, value, impl, expl, default, optional, _decoded = values
3329 class E(Enumerated):
3330 schema = schema_input
3340 for copy_func in copy_funcs:
3341 obj_copied = copy_func(obj)
3342 self.assert_copied_basic_fields(obj, obj_copied)
3343 self.assertEqual(obj.specs, obj_copied.specs)
3345 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3346 @given(data_strategy())
3347 def test_symmetric(self, d):
3348 schema_input, _, _, _, default, optional, _decoded = d.draw(
3349 enumerated_values_strategy(),
3351 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3352 offset = d.draw(integers(min_value=0))
3353 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3354 tail_junk = d.draw(binary(max_size=5))
3355 decode_path = d.draw(decode_path_strat)
3357 class E(Enumerated):
3358 schema = schema_input
3367 pprint(obj, big_blobs=True, with_decode_path=True)
3368 self.assertFalse(obj.expled)
3369 obj_encoded = obj.encode()
3370 self.assertEqual(encode2pass(obj), obj_encoded)
3371 obj_expled = obj(value, expl=tag_expl)
3372 self.assertTrue(obj_expled.expled)
3374 list(obj_expled.pps())
3375 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3376 obj_expled_encoded = obj_expled.encode()
3377 ctx_copied = deepcopy(ctx_dummy)
3378 obj_decoded, tail = obj_expled.decode(
3379 obj_expled_encoded + tail_junk,
3383 self.assertDictEqual(ctx_copied, ctx_dummy)
3385 list(obj_decoded.pps())
3386 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3387 self.assertEqual(tail, tail_junk)
3388 self.assertEqual(obj_decoded, obj_expled)
3389 self.assertNotEqual(obj_decoded, obj)
3390 self.assertEqual(int(obj_decoded), int(obj_expled))
3391 self.assertEqual(int(obj_decoded), int(obj))
3392 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3393 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3394 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3396 obj_decoded.expl_llen,
3397 len(len_encode(len(obj_encoded))),
3399 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3400 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3403 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3405 self.assertEqual(obj_decoded.expl_offset, offset)
3406 assert_exceeding_data(
3408 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3412 evgens = list(obj_expled.decode_evgen(
3413 obj_expled_encoded + tail_junk,
3415 decode_path=decode_path,
3418 self.assertEqual(len(evgens), 1)
3419 _decode_path, obj, tail = evgens[0]
3420 self.assertSequenceEqual(tail, tail_junk)
3421 self.assertEqual(_decode_path, decode_path)
3422 self.assertEqual(obj, obj_decoded)
3423 self.assertEqual(obj.expl_offset, offset)
3429 def string_values_strategy(draw, alphabet, do_expl=False):
3430 bound_min, bound_max = sorted(draw(sets(
3431 integers(min_value=0, max_value=1 << 7),
3435 value = draw(one_of(
3437 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3439 default = draw(one_of(
3441 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3444 if draw(booleans()):
3445 bounds = (bound_min, bound_max)
3449 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3451 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3452 optional = draw(one_of(none(), booleans()))
3454 draw(integers(min_value=0)),
3455 draw(integers(min_value=0)),
3456 draw(integers(min_value=0)),
3458 return (value, bounds, impl, expl, default, optional, _decoded)
3461 class StringMixin(object):
3462 def test_invalid_value_type(self):
3463 with self.assertRaises(InvalidValueType) as err:
3464 self.base_klass((1, 2))
3467 def text_alphabet(self):
3468 return "".join(chr(c) for c in range(256))
3471 def test_optional(self, optional):
3472 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3473 self.assertTrue(obj.optional)
3475 @given(data_strategy())
3476 def test_ready(self, d):
3477 obj = self.base_klass()
3478 self.assertFalse(obj.ready)
3481 pprint(obj, big_blobs=True, with_decode_path=True)
3483 with self.assertRaises(ObjNotReady) as err:
3486 with self.assertRaises(ObjNotReady) as err:
3488 value = d.draw(text(alphabet=self.text_alphabet()))
3489 obj = self.base_klass(value)
3490 self.assertTrue(obj.ready)
3493 pprint(obj, big_blobs=True, with_decode_path=True)
3496 @given(data_strategy())
3497 def test_comparison(self, d):
3498 value1 = d.draw(text(alphabet=self.text_alphabet()))
3499 value2 = d.draw(text(alphabet=self.text_alphabet()))
3500 tag1 = d.draw(binary(min_size=1))
3501 tag2 = d.draw(binary(min_size=1))
3502 obj1 = self.base_klass(value1)
3503 obj2 = self.base_klass(value2)
3504 self.assertEqual(obj1 == obj2, value1 == value2)
3505 self.assertEqual(obj1 != obj2, value1 != value2)
3506 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3507 self.assertEqual(obj1 == str(obj2), value1 == value2)
3508 obj1 = self.base_klass(value1, impl=tag1)
3509 obj2 = self.base_klass(value1, impl=tag2)
3510 self.assertEqual(obj1 == obj2, tag1 == tag2)
3511 self.assertEqual(obj1 != obj2, tag1 != tag2)
3513 @given(data_strategy())
3514 def test_bounds_satisfied(self, d):
3515 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3516 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3517 value = d.draw(text(
3518 alphabet=self.text_alphabet(),
3522 self.base_klass(value=value, bounds=(bound_min, bound_max))
3524 @given(data_strategy())
3525 def test_bounds_unsatisfied(self, d):
3526 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3527 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3528 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3529 with self.assertRaises(BoundsError) as err:
3530 self.base_klass(value=value, bounds=(bound_min, bound_max))
3532 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3533 self.base_klass(bounds=(bound_min, bound_max)).decode(
3534 self.base_klass(value).encode()
3537 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3538 self.base_klass(bounds=(bound_min, bound_max)).decode(
3539 encode2pass(self.base_klass(value))
3541 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3542 with self.assertRaises(BoundsError) as err:
3543 self.base_klass(value=value, bounds=(bound_min, bound_max))
3545 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3546 self.base_klass(bounds=(bound_min, bound_max)).decode(
3547 self.base_klass(value).encode()
3550 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3551 self.base_klass(bounds=(bound_min, bound_max)).decode(
3552 encode2pass(self.base_klass(value))
3555 @given(data_strategy())
3556 def test_call(self, d):
3565 ) = d.draw(string_values_strategy(self.text_alphabet()))
3566 obj_initial = self.base_klass(
3572 optional_initial or False,
3583 ) = d.draw(string_values_strategy(
3584 self.text_alphabet(),
3585 do_expl=impl_initial is None,
3587 if (default is None) and (obj_initial.default is not None):
3590 (bounds is None) and
3591 (value is not None) and
3592 (bounds_initial is not None) and
3593 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3597 (bounds is None) and
3598 (default is not None) and
3599 (bounds_initial is not None) and
3600 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3603 obj = obj_initial(value, bounds, impl, expl, default, optional)
3605 value_expected = default if value is None else value
3607 default_initial if value_expected is None
3610 self.assertEqual(obj, value_expected)
3611 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3612 self.assertEqual(obj.expl_tag, expl or expl_initial)
3615 default_initial if default is None else default,
3617 if obj.default is None:
3618 optional = optional_initial if optional is None else optional
3619 optional = False if optional is None else optional
3622 self.assertEqual(obj.optional, optional)
3624 (obj._bound_min, obj._bound_max),
3625 bounds or bounds_initial or (0, float("+inf")),
3628 @given(data_strategy())
3629 def test_copy(self, d):
3630 values = d.draw(string_values_strategy(self.text_alphabet()))
3631 obj = self.base_klass(*values)
3632 for copy_func in copy_funcs:
3633 obj_copied = copy_func(obj)
3634 self.assert_copied_basic_fields(obj, obj_copied)
3635 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3636 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3637 self.assertEqual(obj._value, obj_copied._value)
3639 @given(data_strategy())
3640 def test_stripped(self, d):
3641 value = d.draw(text(alphabet=self.text_alphabet()))
3642 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3643 obj = self.base_klass(value, impl=tag_impl)
3644 with self.assertRaises(NotEnoughData):
3645 obj.decode(obj.encode()[:-1])
3647 @given(data_strategy())
3648 def test_stripped_expl(self, d):
3649 value = d.draw(text(alphabet=self.text_alphabet()))
3650 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3651 obj = self.base_klass(value, expl=tag_expl)
3652 with self.assertRaises(NotEnoughData):
3653 obj.decode(obj.encode()[:-1])
3656 integers(min_value=31),
3657 integers(min_value=0),
3660 def test_bad_tag(self, tag, offset, decode_path):
3661 with self.assertRaises(DecodeError) as err:
3662 self.base_klass().decode(
3663 tag_encode(tag)[:-1],
3665 decode_path=decode_path,
3668 self.assertEqual(err.exception.offset, offset)
3669 self.assertEqual(err.exception.decode_path, decode_path)
3672 integers(min_value=128),
3673 integers(min_value=0),
3676 def test_bad_len(self, l, offset, decode_path):
3677 with self.assertRaises(DecodeError) as err:
3678 self.base_klass().decode(
3679 self.base_klass.tag_default + len_encode(l)[:-1],
3681 decode_path=decode_path,
3684 self.assertEqual(err.exception.offset, offset)
3685 self.assertEqual(err.exception.decode_path, decode_path)
3688 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3689 integers(min_value=0),
3692 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3693 value, bound_min = list(sorted(ints))
3695 class String(self.base_klass):
3696 # Multiply this value by four, to satisfy UTF-32 bounds
3697 # (4 bytes per character) validation
3698 bounds = (bound_min * 4, bound_min * 4)
3699 with self.assertRaises(DecodeError) as err:
3701 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3703 decode_path=decode_path,
3706 self.assertEqual(err.exception.offset, offset)
3707 self.assertEqual(err.exception.decode_path, decode_path)
3709 @given(data_strategy())
3710 def test_symmetric(self, d):
3711 values = d.draw(string_values_strategy(self.text_alphabet()))
3712 value = d.draw(text(alphabet=self.text_alphabet()))
3713 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3714 offset = d.draw(integers(min_value=0))
3715 tail_junk = d.draw(binary(max_size=5))
3716 decode_path = d.draw(decode_path_strat)
3717 _, _, _, _, default, optional, _decoded = values
3718 obj = self.base_klass(
3726 pprint(obj, big_blobs=True, with_decode_path=True)
3727 self.assertFalse(obj.expled)
3728 obj_encoded = obj.encode()
3729 self.assertEqual(encode2pass(obj), obj_encoded)
3730 obj_expled = obj(value, expl=tag_expl)
3731 self.assertTrue(obj_expled.expled)
3733 list(obj_expled.pps())
3734 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3735 obj_expled_encoded = obj_expled.encode()
3736 ctx_copied = deepcopy(ctx_dummy)
3737 obj_decoded, tail = obj_expled.decode(
3738 obj_expled_encoded + tail_junk,
3742 self.assertDictEqual(ctx_copied, ctx_dummy)
3744 list(obj_decoded.pps())
3745 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3746 self.assertEqual(tail, tail_junk)
3747 self.assertEqual(obj_decoded, obj_expled)
3748 self.assertNotEqual(obj_decoded, obj)
3749 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3750 self.assertEqual(bytes(obj_decoded), bytes(obj))
3751 self.assertEqual(str(obj_decoded), str(obj_expled))
3752 self.assertEqual(str(obj_decoded), str(obj))
3753 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3754 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3755 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3757 obj_decoded.expl_llen,
3758 len(len_encode(len(obj_encoded))),
3760 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3761 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3764 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3766 self.assertEqual(obj_decoded.expl_offset, offset)
3767 assert_exceeding_data(
3769 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3773 evgens = list(obj_expled.decode_evgen(
3774 obj_expled_encoded + tail_junk,
3776 decode_path=decode_path,
3779 self.assertEqual(len(evgens), 1)
3780 _decode_path, obj, tail = evgens[0]
3781 self.assertSequenceEqual(tail, tail_junk)
3782 self.assertEqual(_decode_path, decode_path)
3783 if not getattr(self, "evgen_mode_skip_value", True):
3784 self.assertEqual(obj, obj_decoded)
3785 self.assertEqual(obj.expl_offset, offset)
3790 cyrillic_letters = text(
3791 alphabet="".join(chr(i) for i in list(range(0x0410, 0x044f + 1))),
3797 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3798 base_klass = UTF8String
3800 @given(cyrillic_letters)
3801 def test_byte_per_primitive(self, chars):
3803 char_raw = char.encode("utf-8")
3804 encoded = b"".join((
3805 self.base_klass().tag_constructed,
3807 OctetString(char_raw[:1]).encode(),
3808 OctetString(char_raw[1:2]).encode(),
3812 self.base_klass().decod(encoded, ctx={"bered": True}),
3817 class UnicodeDecodeErrorMixin(object):
3818 @given(cyrillic_letters)
3819 def test_unicode_decode_error(self, cyrillic_text):
3820 with self.assertRaises(DecodeError):
3821 self.base_klass(cyrillic_text)
3824 class TestNumericString(StringMixin, CommonMixin, TestCase):
3825 base_klass = NumericString
3827 def text_alphabet(self):
3830 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3831 def test_non_numeric(self, non_numeric_text):
3832 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3833 self.base_klass(non_numeric_text)
3836 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3837 integers(min_value=0),
3840 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3841 value, bound_min = list(sorted(ints))
3843 class String(self.base_klass):
3844 bounds = (bound_min, bound_min)
3845 with self.assertRaises(DecodeError) as err:
3847 self.base_klass(b"1" * value).encode(),
3849 decode_path=decode_path,
3852 self.assertEqual(err.exception.offset, offset)
3853 self.assertEqual(err.exception.decode_path, decode_path)
3855 def test_byte_per_primitive(self):
3856 encoded = b"".join((
3857 self.base_klass().tag_constructed,
3859 OctetString(b"1").encode(),
3860 OctetString(b"2").encode(),
3864 self.base_klass().decod(encoded, ctx={"bered": True}),
3869 class TestPrintableString(
3870 UnicodeDecodeErrorMixin,
3875 base_klass = PrintableString
3877 def text_alphabet(self):
3878 return ascii_letters + digits + " '()+,-./:=?"
3880 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3881 def test_non_printable(self, non_printable_text):
3882 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3883 self.base_klass(non_printable_text)
3886 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3887 integers(min_value=0),
3890 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3891 value, bound_min = list(sorted(ints))
3893 class String(self.base_klass):
3894 bounds = (bound_min, bound_min)
3895 with self.assertRaises(DecodeError) as err:
3897 self.base_klass(b"1" * value).encode(),
3899 decode_path=decode_path,
3902 self.assertEqual(err.exception.offset, offset)
3903 self.assertEqual(err.exception.decode_path, decode_path)
3905 def test_allowable_invalid_chars(self):
3907 ("*", {"allow_asterisk": True}),
3908 ("&", {"allow_ampersand": True}),
3909 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3912 obj = self.base_klass(s)
3913 for prop in kwargs.keys():
3914 self.assertFalse(getattr(obj, prop))
3916 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3918 self.base_klass(s, **kwargs)
3919 klass = self.base_klass(**kwargs)
3921 for prop in kwargs.keys():
3922 self.assertTrue(getattr(obj, prop))
3925 for prop in kwargs.keys():
3926 self.assertTrue(getattr(obj, prop))
3929 class TestTeletexString(
3930 UnicodeDecodeErrorMixin,
3935 base_klass = TeletexString
3938 class TestVideotexString(
3939 UnicodeDecodeErrorMixin,
3944 base_klass = VideotexString
3947 class TestIA5String(
3948 UnicodeDecodeErrorMixin,
3953 base_klass = IA5String
3955 def text_alphabet(self):
3956 return "".join(chr(c) for c in range(128))
3958 @given(integers(min_value=128, max_value=255))
3959 def test_alphabet_bad(self, code):
3960 with self.assertRaises(DecodeError):
3961 self.base_klass().decod(
3962 self.base_klass.tag_default +
3964 bytes(bytearray([code])),
3968 class TestGraphicString(
3969 UnicodeDecodeErrorMixin,
3974 base_klass = GraphicString
3977 class TestVisibleString(
3978 UnicodeDecodeErrorMixin,
3983 base_klass = VisibleString
3985 def text_alphabet(self):
3986 return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
3988 def test_x690_vector(self):
3989 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3990 self.assertSequenceEqual(tail, b"")
3991 self.assertEqual(str(obj), "Jones")
3992 self.assertFalse(obj.ber_encoded)
3993 self.assertFalse(obj.lenindef)
3994 self.assertFalse(obj.bered)
3996 obj, tail = VisibleString().decode(
3997 hexdec("3A0904034A6F6E04026573"),
3998 ctx={"bered": True},
4000 self.assertSequenceEqual(tail, b"")
4001 self.assertEqual(str(obj), "Jones")
4002 self.assertTrue(obj.ber_encoded)
4003 self.assertFalse(obj.lenindef)
4004 self.assertTrue(obj.bered)
4006 self.assertTrue(obj.ber_encoded)
4007 self.assertFalse(obj.lenindef)
4008 self.assertTrue(obj.bered)
4010 obj, tail = VisibleString().decode(
4011 hexdec("3A8004034A6F6E040265730000"),
4012 ctx={"bered": True},
4014 self.assertSequenceEqual(tail, b"")
4015 self.assertEqual(str(obj), "Jones")
4016 self.assertTrue(obj.ber_encoded)
4017 self.assertTrue(obj.lenindef)
4018 self.assertTrue(obj.bered)
4020 self.assertTrue(obj.ber_encoded)
4021 self.assertTrue(obj.lenindef)
4022 self.assertTrue(obj.bered)
4025 integers(min_value=0, max_value=ord(" ") - 1),
4026 integers(min_value=ord("~") + 1, max_value=255),
4028 def test_alphabet_bad(self, code):
4029 with self.assertRaises(DecodeError):
4030 self.base_klass().decod(
4031 self.base_klass.tag_default +
4033 bytes(bytearray([code])),
4037 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
4038 integers(min_value=0),
4041 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
4042 value, bound_min = list(sorted(ints))
4044 class String(self.base_klass):
4045 bounds = (bound_min, bound_min)
4046 with self.assertRaises(DecodeError) as err:
4048 self.base_klass(b"1" * value).encode(),
4050 decode_path=decode_path,
4053 self.assertEqual(err.exception.offset, offset)
4054 self.assertEqual(err.exception.decode_path, decode_path)
4057 class TestGeneralString(
4058 UnicodeDecodeErrorMixin,
4063 base_klass = GeneralString
4066 class TestUniversalString(StringMixin, CommonMixin, TestCase):
4067 base_klass = UniversalString
4070 class TestBMPString(StringMixin, CommonMixin, TestCase):
4071 base_klass = BMPString
4075 def generalized_time_values_strategy(
4083 if draw(booleans()):
4084 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4086 value = value.replace(microsecond=0)
4088 if draw(booleans()):
4089 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4091 default = default.replace(microsecond=0)
4095 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4097 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4098 optional = draw(one_of(none(), booleans()))
4100 draw(integers(min_value=0)),
4101 draw(integers(min_value=0)),
4102 draw(integers(min_value=0)),
4104 return (value, impl, expl, default, optional, _decoded)
4107 class TimeMixin(object):
4108 def test_invalid_value_type(self):
4109 with self.assertRaises(InvalidValueType) as err:
4110 self.base_klass(datetime.now().timetuple())
4113 @given(data_strategy())
4114 def test_optional(self, d):
4115 default = d.draw(datetimes(
4116 min_value=self.min_datetime,
4117 max_value=self.max_datetime,
4119 optional = d.draw(booleans())
4120 obj = self.base_klass(default=default, optional=optional)
4121 self.assertTrue(obj.optional)
4123 @given(data_strategy())
4124 def test_ready(self, d):
4125 obj = self.base_klass()
4126 self.assertFalse(obj.ready)
4129 pprint(obj, big_blobs=True, with_decode_path=True)
4130 with self.assertRaises(ObjNotReady) as err:
4133 with self.assertRaises(ObjNotReady) as err:
4135 value = d.draw(datetimes(
4136 min_value=self.min_datetime,
4137 max_value=self.max_datetime,
4139 obj = self.base_klass(value)
4140 self.assertTrue(obj.ready)
4143 pprint(obj, big_blobs=True, with_decode_path=True)
4145 @given(data_strategy())
4146 def test_comparison(self, d):
4147 value1 = d.draw(datetimes(
4148 min_value=self.min_datetime,
4149 max_value=self.max_datetime,
4151 value2 = d.draw(datetimes(
4152 min_value=self.min_datetime,
4153 max_value=self.max_datetime,
4155 tag1 = d.draw(binary(min_size=1))
4156 tag2 = d.draw(binary(min_size=1))
4158 value1 = value1.replace(microsecond=0)
4159 value2 = value2.replace(microsecond=0)
4160 obj1 = self.base_klass(value1)
4161 obj2 = self.base_klass(value2)
4162 self.assertEqual(obj1 == obj2, value1 == value2)
4163 self.assertEqual(obj1 != obj2, value1 != value2)
4164 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
4165 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4166 obj1 = self.base_klass(value1, impl=tag1)
4167 obj2 = self.base_klass(value1, impl=tag2)
4168 self.assertEqual(obj1 == obj2, tag1 == tag2)
4169 self.assertEqual(obj1 != obj2, tag1 != tag2)
4171 @given(data_strategy())
4172 def test_call(self, d):
4180 ) = d.draw(generalized_time_values_strategy(
4181 min_datetime=self.min_datetime,
4182 max_datetime=self.max_datetime,
4183 omit_ms=self.omit_ms,
4185 obj_initial = self.base_klass(
4186 value=value_initial,
4189 default=default_initial,
4190 optional=optional_initial or False,
4191 _decoded=_decoded_initial,
4200 ) = d.draw(generalized_time_values_strategy(
4201 min_datetime=self.min_datetime,
4202 max_datetime=self.max_datetime,
4203 omit_ms=self.omit_ms,
4204 do_expl=impl_initial is None,
4214 value_expected = default if value is None else value
4216 default_initial if value_expected is None
4219 self.assertEqual(obj, value_expected)
4220 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4221 self.assertEqual(obj.expl_tag, expl or expl_initial)
4224 default_initial if default is None else default,
4226 if obj.default is None:
4227 optional = optional_initial if optional is None else optional
4228 optional = False if optional is None else optional
4231 self.assertEqual(obj.optional, optional)
4233 @given(data_strategy())
4234 def test_copy(self, d):
4235 values = d.draw(generalized_time_values_strategy(
4236 min_datetime=self.min_datetime,
4237 max_datetime=self.max_datetime,
4239 obj = self.base_klass(*values)
4240 for copy_func in copy_funcs:
4241 obj_copied = copy_func(obj)
4242 self.assert_copied_basic_fields(obj, obj_copied)
4243 self.assertEqual(obj._value, obj_copied._value)
4245 @given(data_strategy())
4246 def test_stripped(self, d):
4247 value = d.draw(datetimes(
4248 min_value=self.min_datetime,
4249 max_value=self.max_datetime,
4251 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4252 obj = self.base_klass(value, impl=tag_impl)
4253 with self.assertRaises(NotEnoughData):
4254 obj.decode(obj.encode()[:-1])
4256 @given(data_strategy())
4257 def test_stripped_expl(self, d):
4258 value = d.draw(datetimes(
4259 min_value=self.min_datetime,
4260 max_value=self.max_datetime,
4262 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4263 obj = self.base_klass(value, expl=tag_expl)
4264 with self.assertRaises(NotEnoughData):
4265 obj.decode(obj.encode()[:-1])
4267 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4268 @given(data_strategy())
4269 def test_symmetric(self, d):
4270 values = d.draw(generalized_time_values_strategy(
4271 min_datetime=self.min_datetime,
4272 max_datetime=self.max_datetime,
4274 value = d.draw(datetimes(
4275 min_value=self.min_datetime,
4276 max_value=self.max_datetime,
4278 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4279 offset = d.draw(integers(min_value=0))
4280 tail_junk = d.draw(binary(max_size=5))
4281 _, _, _, default, optional, _decoded = values
4282 obj = self.base_klass(
4290 pprint(obj, big_blobs=True, with_decode_path=True)
4291 self.assertFalse(obj.expled)
4292 obj_encoded = obj.encode()
4293 self.assertEqual(encode2pass(obj), obj_encoded)
4294 self.additional_symmetric_check(value, obj_encoded)
4295 obj_expled = obj(value, expl=tag_expl)
4296 self.assertTrue(obj_expled.expled)
4298 list(obj_expled.pps())
4299 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4300 obj_expled_encoded = obj_expled.encode()
4301 ctx_copied = deepcopy(ctx_dummy)
4302 obj_decoded, tail = obj_expled.decode(
4303 obj_expled_encoded + tail_junk,
4307 self.assertDictEqual(ctx_copied, ctx_dummy)
4309 list(obj_decoded.pps())
4310 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4311 self.assertEqual(tail, tail_junk)
4312 self.assertEqual(obj_decoded, obj_expled)
4313 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
4314 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
4315 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4316 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4317 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4319 obj_decoded.expl_llen,
4320 len(len_encode(len(obj_encoded))),
4322 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4323 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4326 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4328 self.assertEqual(obj_decoded.expl_offset, offset)
4329 assert_exceeding_data(
4331 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4336 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
4337 base_klass = GeneralizedTime
4339 min_datetime = datetime(1900, 1, 1)
4340 max_datetime = datetime(9999, 12, 31)
4341 evgen_mode_skip_value = False
4343 def additional_symmetric_check(self, value, obj_encoded):
4344 if value.microsecond > 0:
4345 self.assertFalse(obj_encoded.endswith(b"0Z"))
4347 def test_repr_not_ready(self):
4348 str(GeneralizedTime())
4349 repr(GeneralizedTime())
4351 def test_x690_vector_valid(self):
4355 b"19920722132100.3Z",
4357 GeneralizedTime(data)
4359 def test_x690_vector_invalid(self):
4362 b"19920622123421.0Z",
4363 b"19920722132100.30Z",
4365 with self.assertRaises(DecodeError) as err:
4366 GeneralizedTime(data)
4369 def test_go_vectors_invalid(self):
4381 b"-20100102030410Z",
4382 b"2010-0102030410Z",
4383 b"2010-0002030410Z",
4384 b"201001-02030410Z",
4385 b"20100102-030410Z",
4386 b"2010010203-0410Z",
4387 b"201001020304-10Z",
4388 # These ones are INVALID in *DER*, but accepted
4389 # by Go's encoding/asn1
4390 b"20100102030405+0607",
4391 b"20100102030405-0607",
4393 with self.assertRaises(DecodeError) as err:
4394 GeneralizedTime(data)
4397 def test_go_vectors_valid(self):
4399 GeneralizedTime(b"20100102030405Z").todatetime(),
4400 datetime(2010, 1, 2, 3, 4, 5, 0),
4403 def test_go_vectors_valid_ber(self):
4405 b"20100102030405+0607",
4406 b"20100102030405-0607",
4408 GeneralizedTime(data, ctx={"bered": True})
4410 def test_utc_offsets(self):
4411 """Some know equal UTC offsets
4414 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4418 "200101011130-0700",
4419 "200101011500-03:30",
4422 self.assertEqual(dts[0], dts[1])
4423 self.assertEqual(dts[0], dts[2])
4424 self.assertEqual(dts[0], dts[3])
4426 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4427 @given(data_strategy())
4428 def test_valid_ber(self, d):
4429 year = d.draw(integers(min_value=2, max_value=9999))
4430 month = d.draw(integers(min_value=1, max_value=12))
4431 day = d.draw(integers(min_value=1, max_value=28))
4432 hours = d.draw(integers(min_value=0, max_value=23))
4433 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4434 dt = datetime(year, month, day, hours)
4435 fractions_sign = d.draw(sampled_from(" ,."))
4437 if fractions_sign != " ":
4438 fractions = random()
4439 if d.draw(booleans()):
4440 minutes = d.draw(integers(min_value=0, max_value=59))
4441 data += "%02d" % minutes
4442 dt += timedelta(seconds=60 * minutes)
4443 if d.draw(booleans()):
4444 seconds = d.draw(integers(min_value=0, max_value=59))
4445 data += "%02d" % seconds
4446 dt += timedelta(seconds=seconds)
4447 if fractions is not None:
4448 dt += timedelta(microseconds=10**6 * fractions)
4449 elif fractions is not None:
4450 dt += timedelta(seconds=60 * fractions)
4451 elif fractions is not None:
4452 dt += timedelta(seconds=3600 * fractions)
4453 if fractions is not None:
4454 data += fractions_sign + str(fractions)[2:]
4455 if d.draw(booleans()):
4457 elif d.draw(booleans()):
4458 offset_hour = d.draw(integers(min_value=0, max_value=13))
4460 if d.draw(booleans()):
4465 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4466 data += "%02d" % offset_hour
4467 minutes_separator = d.draw(sampled_from((None, "", ":")))
4468 if minutes_separator is not None:
4469 offset_minute = d.draw(integers(min_value=0, max_value=59))
4470 dt -= timedelta(seconds=sign * 60 * offset_minute)
4471 data += "%s%02d" % (minutes_separator, offset_minute)
4472 data = data.encode("ascii")
4473 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4475 GeneralizedTime().decod(data_der)
4480 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4483 mktime(obj.todatetime().timetuple()),
4484 mktime(dt.timetuple()),
4488 obj.todatetime().timestamp()
4492 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4493 self.assertEqual(obj.ber_encoded, not dered)
4494 self.assertEqual(obj.bered, not dered)
4495 self.assertEqual(obj.ber_raw, None if dered else data)
4496 self.assertEqual(obj.encode() == data_der, dered)
4501 def test_invalid_ber(self):
4503 # "00010203040506.07",
4504 "-0010203040506.07",
4505 "0001-203040506.07",
4506 "000102-3040506.07",
4507 "00010203-40506.07",
4508 "0001020304-506.07",
4509 "000102030405-6.07",
4510 "00010203040506.-7",
4511 "+0010203040506.07",
4512 "0001+203040506.07",
4513 "000102+3040506.07",
4514 "00010203+40506.07",
4515 "0001020304+506.07",
4516 "000102030405+6.07",
4517 "00010203040506.+7",
4518 " 0010203040506.07",
4519 "0001 203040506.07",
4520 "000102 3040506.07",
4521 "00010203 40506.07",
4522 "0001020304 506.07",
4523 "000102030405 6.07",
4524 "00010203040506. 7",
4525 "001 0203040506.07",
4526 "00012 03040506.07",
4527 "0001023 040506.07",
4528 "000102034 0506.07",
4529 "00010203045 06.07",
4530 "0001020304056 .07",
4531 "00010203040506.7 ",
4611 "00010203040506.07+15",
4612 "00010203040506.07-15",
4613 "00010203040506.07+14:60",
4614 "00010203040506.07+1460",
4615 "00010203040506.07-1460",
4616 "00010203040506.07+00:60",
4617 "00010203040506.07-00:60",
4619 "00010203040506+15",
4620 "00010203040506-15",
4621 "00010203040506+14:60",
4622 "00010203040506+1460",
4623 "00010203040506-1460",
4624 "00010203040506+00:60",
4625 "00010203040506-00:60",
4634 with self.assertRaises(DecodeError):
4635 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4636 data = data.replace(".", ",")
4637 with self.assertRaises(DecodeError):
4638 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4642 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4643 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4645 binary(min_size=1, max_size=1),
4647 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4648 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4651 def test_junk(self, part0, part1, part2):
4652 junk = part0 + part1 + part2
4653 assume(not (set(junk) <= set(digits.encode("ascii"))))
4654 with self.assertRaises(DecodeError):
4655 GeneralizedTime().decode(
4656 GeneralizedTime.tag_default +
4657 len_encode(len(junk)) +
4663 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4664 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4666 binary(min_size=1, max_size=1),
4668 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4669 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4672 def test_junk_dm(self, part0, part1, part2):
4673 junk = part0 + part1 + part2
4674 assume(not (set(junk) <= set(digits.encode("ascii"))))
4675 with self.assertRaises(DecodeError):
4676 GeneralizedTime().decode(
4677 GeneralizedTime.tag_default +
4678 len_encode(len(junk)) +
4682 def test_ns_fractions(self):
4683 GeneralizedTime(b"20010101000000.000001Z")
4684 with self.assertRaisesRegex(DecodeError, "only microsecond fractions"):
4685 GeneralizedTime(b"20010101000000.0000001Z")
4687 def test_non_pure_integers(self):
4689 # b"20000102030405Z,
4696 b"20000102030405.+6Z",
4697 b"20000102030405.-6Z",
4704 b"20000102030405._6Z",
4705 b"20000102030405.6_Z",
4712 b"20000102030405. 6Z",
4719 b"20000102030405.6 Z",
4721 with self.assertRaises(DecodeError):
4722 GeneralizedTime(data)
4724 def test_aware(self):
4725 with self.assertRaisesRegex(ValueError, "only naive"):
4726 GeneralizedTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
4729 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4730 base_klass = UTCTime
4732 min_datetime = datetime(2000, 1, 1)
4733 max_datetime = datetime(2049, 12, 31)
4734 evgen_mode_skip_value = False
4736 def additional_symmetric_check(self, value, obj_encoded):
4739 def test_repr_not_ready(self):
4740 str(GeneralizedTime())
4743 def test_x690_vector_valid(self):
4751 def test_x690_vector_invalid(self):
4756 with self.assertRaises(DecodeError) as err:
4760 def test_go_vectors_invalid(self):
4786 # These ones are INVALID in *DER*, but accepted
4787 # by Go's encoding/asn1
4788 b"910506164540-0700",
4789 b"910506164540+0730",
4793 with self.assertRaises(DecodeError) as err:
4797 def test_go_vectors_valid(self):
4799 UTCTime(b"910506234540Z").todatetime(),
4800 datetime(1991, 5, 6, 23, 45, 40, 0),
4803 def test_non_pure_integers(self):
4832 with self.assertRaises(DecodeError):
4835 def test_x680_vector_valid_ber(self):
4837 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4838 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4839 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4840 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4842 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4843 obj = UTCTime().decod(data_der, ctx={"bered": True})
4844 self.assertEqual(obj, dt)
4845 self.assertEqual(obj.todatetime(), dt)
4846 self.assertTrue(obj.ber_encoded)
4847 self.assertTrue(obj.bered)
4848 self.assertEqual(obj.ber_raw, data)
4849 self.assertNotEqual(obj.encode(), data_der)
4852 def test_go_vectors_valid_ber(self):
4854 b"910506164540-0700",
4855 b"910506164540+0730",
4859 data = UTCTime.tag_default + len_encode(len(data)) + data
4860 obj = UTCTime().decod(data, ctx={"bered": True})
4861 self.assertTrue(obj.ber_encoded)
4862 self.assertTrue(obj.bered)
4863 self.assertNotEqual(obj.encode(), data)
4866 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4867 @given(data_strategy())
4868 def test_valid_ber(self, d):
4869 year = d.draw(integers(min_value=0, max_value=99))
4870 month = d.draw(integers(min_value=1, max_value=12))
4871 day = d.draw(integers(min_value=1, max_value=28))
4872 hours = d.draw(integers(min_value=0, max_value=23))
4873 minute = d.draw(integers(min_value=0, max_value=59))
4874 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4876 year + (2000 if year < 50 else 1900),
4883 if d.draw(booleans()):
4885 seconds = d.draw(integers(min_value=0, max_value=59))
4886 data += "%02d" % seconds
4887 dt += timedelta(seconds=seconds)
4888 if d.draw(booleans()):
4892 offset_hour = d.draw(integers(min_value=0, max_value=13))
4893 offset_minute = d.draw(integers(min_value=0, max_value=59))
4894 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4895 if d.draw(booleans()):
4901 data += "%02d%02d" % (offset_hour, offset_minute)
4902 data = data.encode("ascii")
4903 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4904 obj = UTCTime().decod(data_der, ctx={"bered": True})
4905 self.assertEqual(obj, dt)
4906 self.assertEqual(obj.todatetime(), dt)
4907 self.assertEqual(obj.ber_encoded, not dered)
4908 self.assertEqual(obj.bered, not dered)
4909 self.assertEqual(obj.ber_raw, None if dered else data)
4910 self.assertEqual(obj.encode() == data_der, dered)
4915 def test_invalid_ber(self):
4956 b"0001020304+0000Z",
4965 with self.assertRaises(DecodeError):
4966 UTCTime(data, ctx={"bered": True})
4967 data = data[:8] + data[8+2:]
4968 with self.assertRaises(DecodeError):
4969 UTCTime(data, ctx={"bered": True})
5014 b"000102030405+000",
5015 b"000102030405+000Z",
5016 b"000102030405+0000Z",
5017 b"000102030405+-101",
5018 b"000102030405+01-1",
5019 b"000102030405+0060",
5020 b"000102030405+1401",
5021 b"500101000002+0003",
5023 with self.assertRaises(DecodeError):
5024 UTCTime(data, ctx={"bered": True})
5026 @given(integers(min_value=0, max_value=49))
5027 def test_pre50(self, year):
5029 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5033 @given(integers(min_value=50, max_value=99))
5034 def test_post50(self, year):
5036 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5042 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5043 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5045 binary(min_size=1, max_size=1),
5047 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5048 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5051 def test_junk(self, part0, part1, part2):
5052 junk = part0 + part1 + part2
5053 assume(not (set(junk) <= set(digits.encode("ascii"))))
5054 with self.assertRaises(DecodeError):
5056 UTCTime.tag_default +
5057 len_encode(len(junk)) +
5061 def test_aware(self):
5062 with self.assertRaisesRegex(ValueError, "only naive"):
5063 UTCTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
5067 def tlv_value_strategy(draw):
5068 tag_num = draw(integers(min_value=1))
5069 data = draw(binary())
5070 return b"".join((tag_encode(tag_num), len_encode(len(data)), data))
5074 def any_values_strategy(draw, do_expl=False):
5075 value = draw(one_of(none(), tlv_value_strategy()))
5078 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5079 optional = draw(one_of(none(), booleans()))
5081 draw(integers(min_value=0)),
5082 draw(integers(min_value=0)),
5083 draw(integers(min_value=0)),
5085 return (value, expl, optional, _decoded)
5088 class AnyInherited(Any):
5092 class TestAny(CommonMixin, TestCase):
5095 def test_invalid_value_type(self):
5096 with self.assertRaises(InvalidValueType) as err:
5101 def test_optional(self, optional):
5102 obj = Any(optional=optional)
5103 self.assertEqual(obj.optional, optional)
5105 @given(tlv_value_strategy())
5106 def test_ready(self, value):
5108 self.assertFalse(obj.ready)
5111 pprint(obj, big_blobs=True, with_decode_path=True)
5112 with self.assertRaises(ObjNotReady) as err:
5115 with self.assertRaises(ObjNotReady) as err:
5118 self.assertTrue(obj.ready)
5121 pprint(obj, big_blobs=True, with_decode_path=True)
5124 def test_basic(self, value):
5125 integer_encoded = Integer(value).encode()
5127 Any(integer_encoded),
5128 Any(Integer(value)),
5129 Any(Any(Integer(value))),
5131 self.assertSequenceEqual(bytes(obj), integer_encoded)
5133 obj.decode(obj.encode())[0].vlen,
5134 len(integer_encoded),
5138 pprint(obj, big_blobs=True, with_decode_path=True)
5139 self.assertSequenceEqual(obj.encode(), integer_encoded)
5141 @given(tlv_value_strategy(), tlv_value_strategy())
5142 def test_comparison(self, value1, value2):
5143 for klass in (Any, AnyInherited):
5144 obj1 = klass(value1)
5145 obj2 = klass(value2)
5146 self.assertEqual(obj1 == obj2, value1 == value2)
5147 self.assertEqual(obj1 != obj2, value1 != value2)
5148 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
5150 @given(data_strategy())
5151 def test_call(self, d):
5152 for klass in (Any, AnyInherited):
5158 ) = d.draw(any_values_strategy())
5159 obj_initial = klass(
5162 optional_initial or False,
5170 ) = d.draw(any_values_strategy(do_expl=True))
5171 obj = obj_initial(value, expl, optional)
5173 value_expected = None if value is None else value
5174 self.assertEqual(obj, value_expected)
5175 self.assertEqual(obj.expl_tag, expl or expl_initial)
5176 if obj.default is None:
5177 optional = optional_initial if optional is None else optional
5178 optional = False if optional is None else optional
5179 self.assertEqual(obj.optional, optional)
5181 def test_simultaneous_impl_expl(self):
5182 # override it, as Any does not have implicit tag
5185 def test_decoded(self):
5186 # override it, as Any does not have implicit tag
5189 @given(any_values_strategy())
5190 def test_copy(self, values):
5191 for klass in (Any, AnyInherited):
5192 obj = klass(*values)
5193 for copy_func in copy_funcs:
5194 obj_copied = copy_func(obj)
5195 self.assert_copied_basic_fields(obj, obj_copied)
5196 self.assertEqual(obj._value, obj_copied._value)
5198 @given(binary().map(OctetString))
5199 def test_stripped(self, value):
5201 with self.assertRaises(NotEnoughData):
5202 obj.decode(obj.encode()[:-1])
5205 tlv_value_strategy(),
5206 integers(min_value=1).map(tag_ctxc),
5208 def test_stripped_expl(self, value, tag_expl):
5209 obj = Any(value, expl=tag_expl)
5210 with self.assertRaises(NotEnoughData):
5211 obj.decode(obj.encode()[:-1])
5214 integers(min_value=31),
5215 integers(min_value=0),
5218 def test_bad_tag(self, tag, offset, decode_path):
5219 with self.assertRaises(DecodeError) as err:
5221 tag_encode(tag)[:-1],
5223 decode_path=decode_path,
5226 self.assertEqual(err.exception.offset, offset)
5227 self.assertEqual(err.exception.decode_path, decode_path)
5230 integers(min_value=128),
5231 integers(min_value=0),
5234 def test_bad_len(self, l, offset, decode_path):
5235 with self.assertRaises(DecodeError) as err:
5237 Any.tag_default + len_encode(l)[:-1],
5239 decode_path=decode_path,
5242 self.assertEqual(err.exception.offset, offset)
5243 self.assertEqual(err.exception.decode_path, decode_path)
5245 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5247 any_values_strategy(),
5248 integers().map(lambda x: Integer(x).encode()),
5249 integers(min_value=1).map(tag_ctxc),
5250 integers(min_value=0),
5254 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
5255 for klass in (Any, AnyInherited):
5256 _, _, optional, _decoded = values
5257 obj = klass(value=value, optional=optional, _decoded=_decoded)
5260 pprint(obj, big_blobs=True, with_decode_path=True)
5261 self.assertFalse(obj.expled)
5262 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5263 self.assertEqual(obj.tag_order, (tag_class, tag_num))
5264 obj_encoded = obj.encode()
5265 self.assertEqual(encode2pass(obj), obj_encoded)
5266 obj_expled = obj(value, expl=tag_expl)
5267 self.assertTrue(obj_expled.expled)
5268 tag_class, _, tag_num = tag_decode(tag_expl)
5269 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5271 list(obj_expled.pps())
5272 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5273 obj_expled_encoded = obj_expled.encode()
5274 ctx_copied = deepcopy(ctx_dummy)
5275 obj_decoded, tail = obj_expled.decode(
5276 obj_expled_encoded + tail_junk,
5280 self.assertDictEqual(ctx_copied, ctx_dummy)
5282 list(obj_decoded.pps())
5283 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5284 self.assertEqual(tail, tail_junk)
5285 self.assertEqual(obj_decoded, obj_expled)
5286 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
5287 self.assertEqual(bytes(obj_decoded), bytes(obj))
5288 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5289 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5290 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5292 obj_decoded.expl_llen,
5293 len(len_encode(len(obj_encoded))),
5295 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5296 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5299 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5301 self.assertEqual(obj_decoded.expl_offset, offset)
5302 self.assertEqual(obj_decoded.tlen, 0)
5303 self.assertEqual(obj_decoded.llen, 0)
5304 self.assertEqual(obj_decoded.vlen, len(value))
5305 assert_exceeding_data(
5307 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5311 evgens = list(obj_expled.decode_evgen(
5312 obj_expled_encoded + tail_junk,
5314 decode_path=decode_path,
5317 self.assertEqual(len(evgens), 1)
5318 _decode_path, obj, tail = evgens[0]
5319 self.assertSequenceEqual(tail, tail_junk)
5320 self.assertEqual(_decode_path, decode_path)
5321 self.assertEqual(obj.expl_offset, offset)
5326 integers(min_value=1).map(tag_ctxc),
5327 integers(min_value=0, max_value=3),
5328 integers(min_value=0),
5332 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
5333 chunk = Boolean(False, expl=expl).encode()
5335 OctetString.tag_default +
5337 b"".join([chunk] * chunks) +
5340 with self.assertRaises(LenIndefForm):
5344 decode_path=decode_path,
5346 obj, tail = Any().decode(
5349 decode_path=decode_path,
5350 ctx={"bered": True},
5352 self.assertSequenceEqual(tail, junk)
5353 self.assertEqual(obj.offset, offset)
5354 self.assertEqual(obj.tlvlen, len(encoded))
5355 self.assertTrue(obj.lenindef)
5356 self.assertFalse(obj.ber_encoded)
5357 self.assertTrue(obj.bered)
5359 self.assertTrue(obj.lenindef)
5360 self.assertFalse(obj.ber_encoded)
5361 self.assertTrue(obj.bered)
5364 pprint(obj, big_blobs=True, with_decode_path=True)
5365 with self.assertRaises(NotEnoughData) as err:
5369 decode_path=decode_path,
5370 ctx={"bered": True},
5372 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
5373 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
5375 class SeqOf(SequenceOf):
5376 schema = Boolean(expl=expl)
5378 class Seq(Sequence):
5380 ("type", ObjectIdentifier(defines=((("value",), {
5381 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
5386 ("type", ObjectIdentifier("1.2.3")),
5387 ("value", Any(encoded)),
5389 seq_encoded = seq.encode()
5390 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5391 self.assertIsNotNone(seq_decoded["value"].defined)
5393 list(seq_decoded.pps())
5394 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5395 self.assertTrue(seq_decoded.bered)
5396 self.assertFalse(seq_decoded["type"].bered)
5397 self.assertTrue(seq_decoded["value"].bered)
5399 chunk = chunk[:-1] + b"\x01"
5400 chunks = b"".join([chunk] * (chunks + 1))
5401 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
5403 ("type", ObjectIdentifier("1.2.3")),
5404 ("value", Any(encoded)),
5406 seq_encoded = seq.encode()
5407 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5408 self.assertIsNotNone(seq_decoded["value"].defined)
5410 list(seq_decoded.pps())
5411 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5412 self.assertTrue(seq_decoded.bered)
5413 self.assertFalse(seq_decoded["type"].bered)
5414 self.assertTrue(seq_decoded["value"].bered)
5418 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
5420 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
5421 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
5423 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
5424 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
5426 min_size=len(names),
5427 max_size=len(names),
5430 (name, Integer(**tag_kwargs))
5431 for name, tag_kwargs in zip(names, tags)
5434 if value_required or draw(booleans()):
5435 value = draw(tuples(
5436 sampled_from([name for name, _ in schema]),
5437 integers().map(Integer),
5441 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5442 default = draw(one_of(
5444 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5446 optional = draw(one_of(none(), booleans()))
5448 draw(integers(min_value=0)),
5449 draw(integers(min_value=0)),
5450 draw(integers(min_value=0)),
5452 return (schema, value, expl, default, optional, _decoded)
5455 class ChoiceInherited(Choice):
5459 class TestChoice(CommonMixin, TestCase):
5461 schema = (("whatever", Boolean()),)
5464 def test_schema_required(self):
5465 with self.assertRaisesRegex(ValueError, "schema must be specified"):
5468 def test_impl_forbidden(self):
5469 with self.assertRaisesRegex(ValueError, "no implicit tag allowed"):
5470 Choice(impl=b"whatever")
5472 def test_invalid_value_type(self):
5473 with self.assertRaises(InvalidValueType) as err:
5474 self.base_klass(123)
5476 with self.assertRaises(ObjUnknown) as err:
5477 self.base_klass(("whenever", Boolean(False)))
5479 with self.assertRaises(InvalidValueType) as err:
5480 self.base_klass(("whatever", Integer(123)))
5484 def test_optional(self, optional):
5485 obj = self.base_klass(
5486 default=self.base_klass(("whatever", Boolean(False))),
5489 self.assertTrue(obj.optional)
5492 def test_ready(self, value):
5493 obj = self.base_klass()
5494 self.assertFalse(obj.ready)
5497 pprint(obj, big_blobs=True, with_decode_path=True)
5498 self.assertIsNone(obj["whatever"])
5499 with self.assertRaises(ObjNotReady) as err:
5502 with self.assertRaises(ObjNotReady) as err:
5504 obj["whatever"] = Boolean()
5505 self.assertFalse(obj.ready)
5508 pprint(obj, big_blobs=True, with_decode_path=True)
5509 obj["whatever"] = Boolean(value)
5510 self.assertTrue(obj.ready)
5513 pprint(obj, big_blobs=True, with_decode_path=True)
5515 @given(booleans(), booleans())
5516 def test_comparison(self, value1, value2):
5517 class WahlInherited(self.base_klass):
5519 for klass in (self.base_klass, WahlInherited):
5520 obj1 = klass(("whatever", Boolean(value1)))
5521 obj2 = klass(("whatever", Boolean(value2)))
5522 self.assertEqual(obj1 == obj2, value1 == value2)
5523 self.assertEqual(obj1 != obj2, value1 != value2)
5524 self.assertEqual(obj1 == obj2._value, value1 == value2)
5525 self.assertFalse(obj1 == obj2._value[1])
5527 @given(data_strategy())
5528 def test_call(self, d):
5529 for klass in (Choice, ChoiceInherited):
5537 ) = d.draw(choice_values_strategy())
5540 schema = schema_initial
5542 value=value_initial,
5544 default=default_initial,
5545 optional=optional_initial or False,
5546 _decoded=_decoded_initial,
5555 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5556 obj = obj_initial(value, expl, default, optional)
5558 value_expected = default if value is None else value
5560 default_initial if value_expected is None
5563 self.assertEqual(obj.choice, value_expected[0])
5564 self.assertEqual(obj.value, int(value_expected[1]))
5565 self.assertEqual(obj.expl_tag, expl or expl_initial)
5566 default_expect = default_initial if default is None else default
5567 if default_expect is not None:
5568 self.assertEqual(obj.default.choice, default_expect[0])
5569 self.assertEqual(obj.default.value, int(default_expect[1]))
5570 if obj.default is None:
5571 optional = optional_initial if optional is None else optional
5572 optional = False if optional is None else optional
5575 self.assertEqual(obj.optional, optional)
5576 self.assertEqual(obj.specs, obj_initial.specs)
5578 def test_simultaneous_impl_expl(self):
5579 # override it, as Any does not have implicit tag
5582 def test_decoded(self):
5583 # override it, as Any does not have implicit tag
5586 @given(choice_values_strategy())
5587 def test_copy(self, values):
5588 _schema, value, expl, default, optional, _decoded = values
5590 class Wahl(self.base_klass):
5592 register_class(Wahl)
5597 optional=optional or False,
5600 for copy_func in copy_funcs:
5601 obj_copied = copy_func(obj)
5602 self.assertIsNone(obj.tag)
5603 self.assertIsNone(obj_copied.tag)
5604 # hack for assert_copied_basic_fields
5605 obj.tag = "whatever"
5606 obj_copied.tag = "whatever"
5607 self.assert_copied_basic_fields(obj, obj_copied)
5609 self.assertEqual(obj._value, obj_copied._value)
5610 self.assertEqual(obj.specs, obj_copied.specs)
5613 def test_stripped(self, value):
5614 obj = self.base_klass(("whatever", Boolean(value)))
5615 with self.assertRaises(NotEnoughData):
5616 obj.decode(obj.encode()[:-1])
5620 integers(min_value=1).map(tag_ctxc),
5622 def test_stripped_expl(self, value, tag_expl):
5623 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5624 with self.assertRaises(NotEnoughData):
5625 obj.decode(obj.encode()[:-1])
5627 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5628 @given(data_strategy())
5629 def test_symmetric(self, d):
5630 _schema, value, _, default, optional, _decoded = d.draw(
5631 choice_values_strategy(value_required=True)
5633 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5634 offset = d.draw(integers(min_value=0))
5635 tail_junk = d.draw(binary(max_size=5))
5636 decode_path = d.draw(decode_path_strat)
5638 class Wahl(self.base_klass):
5648 pprint(obj, big_blobs=True, with_decode_path=True)
5649 self.assertFalse(obj.expled)
5650 self.assertEqual(obj.tag_order, obj.value.tag_order)
5651 obj_encoded = obj.encode()
5652 self.assertEqual(encode2pass(obj), obj_encoded)
5653 obj_expled = obj(value, expl=tag_expl)
5654 self.assertTrue(obj_expled.expled)
5655 tag_class, _, tag_num = tag_decode(tag_expl)
5656 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5658 list(obj_expled.pps())
5659 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5660 obj_expled_encoded = obj_expled.encode()
5661 ctx_copied = deepcopy(ctx_dummy)
5662 obj_decoded, tail = obj_expled.decode(
5663 obj_expled_encoded + tail_junk,
5667 self.assertDictEqual(ctx_copied, ctx_dummy)
5669 list(obj_decoded.pps())
5670 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5671 self.assertEqual(tail, tail_junk)
5672 self.assertEqual(obj_decoded, obj_expled)
5673 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5674 self.assertEqual(obj_decoded.value, obj_expled.value)
5675 self.assertEqual(obj_decoded.choice, obj.choice)
5676 self.assertEqual(obj_decoded.value, obj.value)
5677 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5678 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5679 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5681 obj_decoded.expl_llen,
5682 len(len_encode(len(obj_encoded))),
5684 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5685 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5688 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5690 self.assertEqual(obj_decoded.expl_offset, offset)
5691 self.assertSequenceEqual(
5693 obj_decoded.value.fulloffset - offset:
5694 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5698 assert_exceeding_data(
5700 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5704 evgens = list(obj_expled.decode_evgen(
5705 obj_expled_encoded + tail_junk,
5707 decode_path=decode_path,
5710 self.assertEqual(len(evgens), 2)
5711 _decode_path, obj, tail = evgens[0]
5712 self.assertEqual(_decode_path, decode_path + (obj_decoded.choice,))
5713 _decode_path, obj, tail = evgens[1]
5714 self.assertSequenceEqual(tail, tail_junk)
5715 self.assertEqual(_decode_path, decode_path)
5716 self.assertEqual(obj.expl_offset, offset)
5721 def test_set_get(self, value):
5724 ("erste", Boolean()),
5725 ("zweite", Integer()),
5728 with self.assertRaises(ObjUnknown) as err:
5729 obj["whatever"] = "whenever"
5730 with self.assertRaises(InvalidValueType) as err:
5731 obj["zweite"] = Boolean(False)
5732 obj["zweite"] = Integer(value)
5734 with self.assertRaises(ObjUnknown) as err:
5737 self.assertIsNone(obj["erste"])
5738 self.assertEqual(obj["zweite"], Integer(value))
5740 def test_tag_mismatch(self):
5743 ("erste", Boolean()),
5745 int_encoded = Integer(123).encode()
5746 bool_encoded = Boolean(False).encode()
5748 obj.decode(bool_encoded)
5749 with self.assertRaises(TagMismatch):
5750 obj.decode(int_encoded)
5752 def test_tag_mismatch_underlying(self):
5753 class SeqOfBoolean(SequenceOf):
5756 class SeqOfInteger(SequenceOf):
5761 ("erste", SeqOfBoolean()),
5764 int_encoded = SeqOfInteger((Integer(123),)).encode()
5765 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5767 obj.decode(bool_encoded)
5768 with self.assertRaises(TagMismatch) as err:
5769 obj.decode(int_encoded)
5770 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5774 def seq_values_strategy(draw, seq_klass, do_expl=False):
5776 if draw(booleans()):
5778 value._value = draw(dictionaries(
5781 booleans().map(Boolean),
5782 integers().map(Integer),
5786 if draw(booleans()):
5787 schema = list(draw(dictionaries(
5790 booleans().map(Boolean),
5791 integers().map(Integer),
5797 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5799 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5801 if draw(booleans()):
5802 default = seq_klass()
5803 default._value = draw(dictionaries(
5806 booleans().map(Boolean),
5807 integers().map(Integer),
5810 optional = draw(one_of(none(), booleans()))
5812 draw(integers(min_value=0)),
5813 draw(integers(min_value=0)),
5814 draw(integers(min_value=0)),
5816 return (value, schema, impl, expl, default, optional, _decoded)
5820 def sequence_strategy(draw, seq_klass):
5821 inputs = draw(lists(
5823 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5824 tuples(just(Integer), integers(), one_of(none(), integers())),
5829 integers(min_value=1),
5830 min_size=len(inputs),
5831 max_size=len(inputs),
5834 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5835 for tag, expled in zip(tags, draw(lists(
5837 min_size=len(inputs),
5838 max_size=len(inputs),
5842 for i, optional in enumerate(draw(lists(
5843 sampled_from(("required", "optional", "empty")),
5844 min_size=len(inputs),
5845 max_size=len(inputs),
5847 if optional in ("optional", "empty"):
5848 inits[i]["optional"] = True
5849 if optional == "empty":
5851 empties = set(empties)
5852 names = list(draw(sets(
5854 min_size=len(inputs),
5855 max_size=len(inputs),
5858 for i, (klass, value, default) in enumerate(inputs):
5859 schema.append((names[i], klass(default=default, **inits[i])))
5860 seq_name = draw(text_letters())
5861 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5864 for i, (klass, value, default) in enumerate(inputs):
5871 "default_value": None if spec.default is None else default,
5875 expect["optional"] = True
5877 expect["presented"] = True
5878 expect["value"] = value
5880 expect["optional"] = True
5881 if default is not None and default == value:
5882 expect["presented"] = False
5883 seq[name] = klass(value)
5884 expects.append(expect)
5889 def sequences_strategy(draw, seq_klass):
5890 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5892 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5893 for tag, expled in zip(tags, draw(lists(
5900 i for i, is_default in enumerate(draw(lists(
5906 names = list(draw(sets(
5911 seq_expectses = draw(lists(
5912 sequence_strategy(seq_klass=seq_klass),
5916 seqs = [seq for seq, _ in seq_expectses]
5918 for i, (name, seq) in enumerate(zip(names, seqs)):
5921 seq(default=(seq if i in defaulted else None), **inits[i]),
5923 seq_name = draw(text_letters())
5924 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5927 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5930 "expects": expects_inner,
5933 seq_outer[name] = seq_inner
5934 if seq_outer.specs[name].default is None:
5935 expect["presented"] = True
5936 expect_outers.append(expect)
5937 return seq_outer, expect_outers
5940 class SeqMixin(object):
5941 def test_invalid_value_type(self):
5942 with self.assertRaises(InvalidValueType) as err:
5943 self.base_klass(123)
5946 def test_invalid_value_type_set(self):
5947 class Seq(self.base_klass):
5948 schema = (("whatever", Boolean()),)
5950 with self.assertRaises(InvalidValueType) as err:
5951 seq["whatever"] = Integer(123)
5955 def test_optional(self, optional):
5956 obj = self.base_klass(default=self.base_klass(), optional=optional)
5957 self.assertTrue(obj.optional)
5959 @given(data_strategy())
5960 def test_ready(self, d):
5962 str(i): v for i, v in enumerate(d.draw(lists(
5969 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5976 for name in d.draw(permutations(
5977 list(ready.keys()) + list(non_ready.keys()),
5979 schema_input.append((name, Boolean()))
5981 class Seq(self.base_klass):
5982 schema = tuple(schema_input)
5984 for name in ready.keys():
5986 seq[name] = Boolean()
5987 self.assertFalse(seq.ready)
5990 pprint(seq, big_blobs=True, with_decode_path=True)
5991 for name, value in ready.items():
5992 seq[name] = Boolean(value)
5993 self.assertFalse(seq.ready)
5996 pprint(seq, big_blobs=True, with_decode_path=True)
5997 with self.assertRaises(ObjNotReady) as err:
6000 with self.assertRaises(ObjNotReady) as err:
6002 for name, value in non_ready.items():
6003 seq[name] = Boolean(value)
6004 self.assertTrue(seq.ready)
6007 pprint(seq, big_blobs=True, with_decode_path=True)
6009 @given(data_strategy())
6010 def test_call(self, d):
6011 class SeqInherited(self.base_klass):
6013 for klass in (self.base_klass, SeqInherited):
6022 ) = d.draw(seq_values_strategy(seq_klass=klass))
6023 obj_initial = klass(
6029 optional_initial or False,
6040 ) = d.draw(seq_values_strategy(
6042 do_expl=impl_initial is None,
6044 obj = obj_initial(value, impl, expl, default, optional)
6045 value_expected = default if value is None else value
6047 default_initial if value_expected is None
6050 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
6051 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6052 self.assertEqual(obj.expl_tag, expl or expl_initial)
6054 {} if obj.default is None else obj.default._value,
6055 getattr(default_initial if default is None else default, "_value", {}),
6057 if obj.default is None:
6058 optional = optional_initial if optional is None else optional
6059 optional = False if optional is None else optional
6062 self.assertEqual(list(obj.specs.items()), schema_initial or [])
6063 self.assertEqual(obj.optional, optional)
6065 @given(data_strategy())
6066 def test_copy(self, d):
6067 class SeqInherited(self.base_klass):
6069 register_class(SeqInherited)
6070 for klass in (self.base_klass, SeqInherited):
6071 values = d.draw(seq_values_strategy(seq_klass=klass))
6072 obj = klass(*values)
6073 for copy_func in copy_funcs:
6074 obj_copied = copy_func(obj)
6075 self.assert_copied_basic_fields(obj, obj_copied)
6076 self.assertEqual(obj.specs, obj_copied.specs)
6077 self.assertEqual(obj._value, obj_copied._value)
6079 @given(data_strategy())
6080 def test_stripped(self, d):
6081 value = d.draw(integers())
6082 tag_impl = tag_encode(d.draw(integers(min_value=1)))
6084 class Seq(self.base_klass):
6086 schema = (("whatever", Integer()),)
6088 seq["whatever"] = Integer(value)
6089 with self.assertRaises(NotEnoughData):
6090 seq.decode(seq.encode()[:-1])
6092 @given(data_strategy())
6093 def test_stripped_expl(self, d):
6094 value = d.draw(integers())
6095 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
6097 class Seq(self.base_klass):
6099 schema = (("whatever", Integer()),)
6101 seq["whatever"] = Integer(value)
6102 with self.assertRaises(NotEnoughData):
6103 seq.decode(seq.encode()[:-1])
6105 @given(integers(min_value=3), binary(min_size=2))
6106 def test_non_tag_mismatch_raised(self, junk_tag_num, junk):
6107 junk = tag_encode(junk_tag_num) + junk
6109 _, _, len_encoded = tag_strip(memoryview(junk))
6110 len_decode(len_encoded)
6116 class Seq(self.base_klass):
6118 ("whatever", Integer()),
6120 ("whenever", Integer()),
6123 seq["whatever"] = Integer(123)
6124 seq["junk"] = Any(junk)
6125 seq["whenever"] = Integer(123)
6126 with self.assertRaises(DecodeError):
6127 seq.decode(seq.encode())
6130 integers(min_value=31),
6131 integers(min_value=0),
6134 def test_bad_tag(self, tag, offset, decode_path):
6135 with self.assertRaises(DecodeError) as err:
6136 self.base_klass().decode(
6137 tag_encode(tag)[:-1],
6139 decode_path=decode_path,
6142 self.assertEqual(err.exception.offset, offset)
6143 self.assertEqual(err.exception.decode_path, decode_path)
6146 integers(min_value=128),
6147 integers(min_value=0),
6150 def test_bad_len(self, l, offset, decode_path):
6151 with self.assertRaises(DecodeError) as err:
6152 self.base_klass().decode(
6153 self.base_klass.tag_default + len_encode(l)[:-1],
6155 decode_path=decode_path,
6158 self.assertEqual(err.exception.offset, offset)
6159 self.assertEqual(err.exception.decode_path, decode_path)
6161 def _assert_expects(self, seq, expects):
6162 for expect in expects:
6164 seq.specs[expect["name"]].optional,
6167 if expect["default_value"] is not None:
6169 seq.specs[expect["name"]].default,
6170 expect["default_value"],
6172 if expect["presented"]:
6173 self.assertIn(expect["name"], seq)
6174 self.assertEqual(seq[expect["name"]], expect["value"])
6176 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6177 @given(data_strategy())
6178 def test_symmetric(self, d):
6179 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
6180 tail_junk = d.draw(binary(max_size=5))
6181 decode_path = d.draw(decode_path_strat)
6182 self.assertTrue(seq.ready)
6183 self.assertFalse(seq.decoded)
6184 self._assert_expects(seq, expects)
6187 pprint(seq, big_blobs=True, with_decode_path=True)
6188 self.assertTrue(seq.ready)
6189 seq_encoded = seq.encode()
6190 self.assertEqual(encode2pass(seq), seq_encoded)
6191 seq_encoded_cer = encode_cer(seq)
6192 self.assertNotEqual(seq_encoded_cer, seq_encoded)
6193 self.assertSequenceEqual(
6194 seq.decod(seq_encoded_cer, ctx={"bered": True}).encode(),
6197 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
6198 self.assertFalse(seq_decoded.lenindef)
6199 self.assertFalse(seq_decoded.ber_encoded)
6200 self.assertFalse(seq_decoded.bered)
6202 t, _, lv = tag_strip(seq_encoded)
6203 _, _, v = len_decode(lv)
6204 seq_encoded_lenindef = t + LENINDEF + v + EOC
6205 with self.assertRaises(DecodeError):
6206 seq.decode(seq_encoded_lenindef)
6207 ctx_copied = deepcopy(ctx_dummy)
6208 ctx_copied["bered"] = True
6209 seq_decoded_lenindef, tail_lenindef = seq.decode(
6210 seq_encoded_lenindef + tail_junk,
6213 del ctx_copied["bered"]
6214 self.assertDictEqual(ctx_copied, ctx_dummy)
6215 self.assertTrue(seq_decoded_lenindef.lenindef)
6216 self.assertTrue(seq_decoded_lenindef.bered)
6217 seq_decoded_lenindef = copy(seq_decoded_lenindef)
6218 self.assertTrue(seq_decoded_lenindef.lenindef)
6219 self.assertTrue(seq_decoded_lenindef.bered)
6220 with self.assertRaises(DecodeError):
6221 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
6222 with self.assertRaises(DecodeError):
6223 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
6224 repr(seq_decoded_lenindef)
6225 list(seq_decoded_lenindef.pps())
6226 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
6227 self.assertTrue(seq_decoded_lenindef.ready)
6229 for decoded, decoded_tail, encoded in (
6230 (seq_decoded, tail, seq_encoded),
6231 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
6233 self.assertEqual(decoded_tail, tail_junk)
6234 self._assert_expects(decoded, expects)
6235 self.assertEqual(seq, decoded)
6236 self.assertEqual(decoded.encode(), seq_encoded)
6237 self.assertEqual(decoded.tlvlen, len(encoded))
6238 for expect in expects:
6239 if not expect["presented"]:
6240 self.assertNotIn(expect["name"], decoded)
6242 self.assertIn(expect["name"], decoded)
6243 obj = decoded[expect["name"]]
6244 self.assertTrue(obj.decoded)
6245 offset = obj.expl_offset if obj.expled else obj.offset
6246 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6247 self.assertSequenceEqual(
6248 seq_encoded[offset:offset + tlvlen],
6252 evgens = list(seq.decode_evgen(
6253 encoded + decoded_tail,
6254 decode_path=decode_path,
6255 ctx={"bered": True},
6257 self.assertEqual(len(evgens), len(list(decoded._values_for_encoding())) + 1)
6258 for _decode_path, obj, _ in evgens[:-1]:
6259 self.assertEqual(_decode_path[:-1], decode_path)
6262 _decode_path, obj, tail = evgens[-1]
6263 self.assertEqual(_decode_path, decode_path)
6267 assert_exceeding_data(
6269 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
6273 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6274 @given(data_strategy())
6275 def test_symmetric_with_seq(self, d):
6276 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
6277 self.assertTrue(seq.ready)
6278 seq_encoded = seq.encode()
6279 self.assertEqual(encode2pass(seq), seq_encoded)
6280 seq_decoded, tail = seq.decode(seq_encoded)
6281 self.assertEqual(tail, b"")
6282 self.assertTrue(seq.ready)
6283 self.assertEqual(seq, seq_decoded)
6284 self.assertEqual(seq_decoded.encode(), seq_encoded)
6285 for expect_outer in expect_outers:
6286 if not expect_outer["presented"]:
6287 self.assertNotIn(expect_outer["name"], seq_decoded)
6289 self.assertIn(expect_outer["name"], seq_decoded)
6290 obj = seq_decoded[expect_outer["name"]]
6291 self.assertTrue(obj.decoded)
6292 offset = obj.expl_offset if obj.expled else obj.offset
6293 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6294 self.assertSequenceEqual(
6295 seq_encoded[offset:offset + tlvlen],
6298 self._assert_expects(obj, expect_outer["expects"])
6300 @given(data_strategy())
6301 def test_default_disappears(self, d):
6302 _schema = list(d.draw(dictionaries(
6304 sets(integers(), min_size=2, max_size=2),
6308 class Seq(self.base_klass):
6310 (n, Integer(default=d))
6311 for n, (_, d) in _schema
6314 for name, (value, _) in _schema:
6315 seq[name] = Integer(value)
6316 self.assertEqual(len(seq._value), len(_schema))
6317 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
6318 self.assertGreater(len(seq.encode()), len(empty_seq))
6319 for name, (_, default) in _schema:
6320 seq[name] = Integer(default)
6321 self.assertEqual(len(seq._value), 0)
6322 self.assertSequenceEqual(seq.encode(), empty_seq)
6324 @given(data_strategy())
6325 def test_encoded_default_not_accepted(self, d):
6326 _schema = list(d.draw(dictionaries(
6331 tags = [tag_encode(tag) for tag in d.draw(sets(
6332 integers(min_value=1),
6333 min_size=len(_schema),
6334 max_size=len(_schema),
6338 schema = (("int", Integer()),)
6340 class SeqWithoutDefault(self.base_klass):
6343 for (n, _), t in zip(_schema, tags)
6345 seq_without_default = SeqWithoutDefault()
6346 for name, value in _schema:
6347 seq_without_default[name] = Wahl(("int", Integer(value)))
6348 seq_encoded = seq_without_default.encode()
6349 seq_without_default.decode(seq_encoded)
6351 len(list(seq_without_default.decode_evgen(seq_encoded))),
6352 len(_schema) * 2 + 1,
6355 class SeqWithDefault(self.base_klass):
6357 (n, Wahl(default=Wahl(("int", Integer(v))), expl=t))
6358 for (n, v), t in zip(_schema, tags)
6360 seq_with_default = SeqWithDefault()
6361 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6362 seq_with_default.decode(seq_encoded)
6363 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6364 list(seq_with_default.decode_evgen(seq_encoded))
6365 for ctx in ({"bered": True}, {"allow_default_values": True}):
6366 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
6367 self.assertTrue(seq_decoded.ber_encoded)
6368 self.assertTrue(seq_decoded.bered)
6369 seq_decoded = copy(seq_decoded)
6370 self.assertTrue(seq_decoded.ber_encoded)
6371 self.assertTrue(seq_decoded.bered)
6372 for name, value in _schema:
6373 self.assertEqual(seq_decoded[name], seq_with_default[name])
6374 self.assertEqual(seq_decoded[name].value, value)
6376 len(list(seq_with_default.decode_evgen(seq_encoded, ctx=ctx))),
6380 seq_without_default = SeqWithoutDefault()
6381 for name, value in _schema:
6382 seq_without_default[name] = Wahl(("int", Integer(value + 1)))
6383 seq_encoded = seq_without_default.encode()
6384 seq_with_default.decode(seq_encoded)
6386 len(list(seq_with_default.decode_evgen(seq_encoded))),
6390 @given(data_strategy())
6391 def test_missing_from_spec(self, d):
6392 names = list(d.draw(sets(text_letters(), min_size=2)))
6393 tags = [tag_encode(tag) for tag in d.draw(sets(
6394 integers(min_value=1),
6395 min_size=len(names),
6396 max_size=len(names),
6398 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
6400 class SeqFull(self.base_klass):
6401 schema = [(n, Integer(impl=t)) for n, t in names_tags]
6402 seq_full = SeqFull()
6403 for i, name in enumerate(names):
6404 seq_full[name] = Integer(i)
6405 seq_encoded = seq_full.encode()
6406 altered = names_tags[:-2] + names_tags[-1:]
6408 class SeqMissing(self.base_klass):
6409 schema = [(n, Integer(impl=t)) for n, t in altered]
6410 seq_missing = SeqMissing()
6411 with self.assertRaises(TagMismatch):
6412 seq_missing.decode(seq_encoded)
6413 with self.assertRaises(TagMismatch):
6414 list(seq_missing.decode_evgen(seq_encoded))
6416 def test_bered(self):
6417 class Seq(self.base_klass):
6418 schema = (("underlying", Boolean()),)
6419 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
6420 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6421 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6422 self.assertFalse(decoded.ber_encoded)
6423 self.assertFalse(decoded.lenindef)
6424 self.assertTrue(decoded.bered)
6425 decoded = copy(decoded)
6426 self.assertFalse(decoded.ber_encoded)
6427 self.assertFalse(decoded.lenindef)
6428 self.assertTrue(decoded.bered)
6430 class Seq(self.base_klass):
6431 schema = (("underlying", OctetString()),)
6433 tag_encode(form=TagFormConstructed, num=4) +
6435 OctetString(b"whatever").encode() +
6438 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6439 with self.assertRaises(DecodeError):
6440 Seq().decode(encoded)
6441 with self.assertRaises(DecodeError):
6442 list(Seq().decode_evgen(encoded))
6443 list(Seq().decode_evgen(encoded, ctx={"bered": True}))
6444 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6445 self.assertFalse(decoded.ber_encoded)
6446 self.assertFalse(decoded.lenindef)
6447 self.assertTrue(decoded.bered)
6448 decoded = copy(decoded)
6449 self.assertFalse(decoded.ber_encoded)
6450 self.assertFalse(decoded.lenindef)
6451 self.assertTrue(decoded.bered)
6454 class TestSequence(SeqMixin, CommonMixin, TestCase):
6455 base_klass = Sequence
6461 def test_remaining(self, value, junk):
6462 class Seq(Sequence):
6464 ("whatever", Integer()),
6466 int_encoded = Integer(value).encode()
6468 Sequence.tag_default,
6469 len_encode(len(int_encoded + junk)),
6472 with self.assertRaisesRegex(DecodeError, "remaining"):
6473 Seq().decode(junked)
6475 @given(sets(text_letters(), min_size=2))
6476 def test_obj_unknown(self, names):
6477 missing = names.pop()
6479 class Seq(Sequence):
6480 schema = [(n, Boolean()) for n in names]
6482 with self.assertRaises(ObjUnknown) as err:
6485 with self.assertRaises(ObjUnknown) as err:
6486 seq[missing] = Boolean()
6489 def test_x690_vector(self):
6490 class Seq(Sequence):
6492 ("name", IA5String()),
6495 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
6496 self.assertEqual(seq["name"], "Smith")
6497 self.assertEqual(seq["ok"], True)
6500 class TestSet(SeqMixin, CommonMixin, TestCase):
6503 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6504 @given(data_strategy())
6505 def test_sorted(self, d):
6506 class DummySeq(Sequence):
6507 schema = (("null", Null()),)
6509 tag_nums = d.draw(sets(integers(min_value=1), min_size=1, max_size=50))
6510 _, _, dummy_seq_tag_num = tag_decode(DummySeq.tag_default)
6511 assume(any(i > dummy_seq_tag_num for i in tag_nums))
6512 tag_nums -= set([dummy_seq_tag_num])
6513 _schema = [(str(i), OctetString(impl=tag_encode(i))) for i in tag_nums]
6514 _schema.append(("seq", DummySeq()))
6517 schema = d.draw(permutations(_schema))
6519 for name, _ in _schema:
6521 seq[name] = OctetString(name.encode("ascii"))
6522 seq["seq"] = DummySeq((("null", Null()),))
6524 seq_encoded = seq.encode()
6525 seq_decoded, _ = seq.decode(seq_encoded)
6526 seq_encoded_expected = []
6527 for tag_num in sorted(tag_nums | set([dummy_seq_tag_num])):
6528 if tag_num == dummy_seq_tag_num:
6529 seq_encoded_expected.append(seq["seq"].encode())
6531 seq_encoded_expected.append(seq[str(tag_num)].encode())
6532 self.assertSequenceEqual(
6533 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6534 b"".join(seq_encoded_expected),
6537 encoded = b"".join(seq[str(i)].encode() for i in tag_nums)
6538 encoded += seq["seq"].encode()
6539 seq_encoded = b"".join((
6541 len_encode(len(encoded)),
6544 with self.assertRaisesRegex(DecodeError, "unordered SET"):
6545 seq.decode(seq_encoded)
6546 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6547 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6548 self.assertTrue(seq_decoded.ber_encoded)
6549 self.assertTrue(seq_decoded.bered)
6550 seq_decoded = copy(seq_decoded)
6551 self.assertTrue(seq_decoded.ber_encoded)
6552 self.assertTrue(seq_decoded.bered)
6554 def test_same_value_twice(self):
6557 ("bool", Boolean()),
6561 encoded = b"".join((
6562 Integer(123).encode(),
6563 Integer(234).encode(),
6564 Boolean(True).encode(),
6566 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6567 with self.assertRaises(TagMismatch):
6568 Seq().decod(encoded, ctx={"allow_unordered_set": True})
6572 def seqof_values_strategy(draw, schema=None, do_expl=False):
6574 schema = draw(sampled_from((Boolean(), Integer())))
6575 bound_min, bound_max = sorted(draw(sets(
6576 integers(min_value=0, max_value=10),
6580 if isinstance(schema, Boolean):
6581 values_generator = booleans().map(Boolean)
6582 elif isinstance(schema, Integer):
6583 values_generator = integers().map(Integer)
6584 values_generator = lists(
6589 values = draw(one_of(none(), values_generator))
6593 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6595 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6596 default = draw(one_of(none(), values_generator))
6597 optional = draw(one_of(none(), booleans()))
6599 draw(integers(min_value=0)),
6600 draw(integers(min_value=0)),
6601 draw(integers(min_value=0)),
6606 (bound_min, bound_max),
6615 class SeqOfMixin(object):
6616 def test_invalid_value_type(self):
6617 with self.assertRaises(InvalidValueType) as err:
6618 self.base_klass(123)
6621 def test_invalid_values_type(self):
6622 class SeqOf(self.base_klass):
6624 with self.assertRaises(InvalidValueType) as err:
6625 SeqOf([Integer(123), Boolean(False), Integer(234)])
6628 def test_schema_required(self):
6629 with self.assertRaisesRegex(ValueError, "schema must be specified"):
6630 self.base_klass.__mro__[1]()
6632 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6633 def test_comparison(self, value1, value2, tag1, tag2):
6634 class SeqOf(self.base_klass):
6636 obj1 = SeqOf([Boolean(value1)])
6637 obj2 = SeqOf([Boolean(value2)])
6638 self.assertEqual(obj1 == obj2, value1 == value2)
6639 self.assertEqual(obj1 != obj2, value1 != value2)
6640 self.assertEqual(obj1 == list(obj2), value1 == value2)
6641 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6642 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6643 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6644 self.assertEqual(obj1 == obj2, tag1 == tag2)
6645 self.assertEqual(obj1 != obj2, tag1 != tag2)
6647 @given(lists(booleans()))
6648 def test_iter(self, values):
6649 class SeqOf(self.base_klass):
6651 obj = SeqOf([Boolean(value) for value in values])
6652 self.assertEqual(len(obj), len(values))
6653 for i, value in enumerate(obj):
6654 self.assertEqual(value, values[i])
6656 @given(data_strategy())
6657 def test_ready(self, d):
6658 ready = [Integer(v) for v in d.draw(lists(
6665 range(d.draw(integers(min_value=1, max_value=5)))
6668 class SeqOf(self.base_klass):
6670 values = d.draw(permutations(ready + non_ready))
6672 for value in values:
6674 self.assertFalse(seqof.ready)
6677 pprint(seqof, big_blobs=True, with_decode_path=True)
6678 with self.assertRaises(ObjNotReady) as err:
6681 with self.assertRaises(ObjNotReady) as err:
6683 for i, value in enumerate(values):
6684 self.assertEqual(seqof[i], value)
6685 if not seqof[i].ready:
6686 seqof[i] = Integer(i)
6687 self.assertTrue(seqof.ready)
6690 pprint(seqof, big_blobs=True, with_decode_path=True)
6692 def test_spec_mismatch(self):
6693 class SeqOf(self.base_klass):
6696 seqof.append(Integer(123))
6697 with self.assertRaises(ValueError):
6698 seqof.append(Boolean(False))
6699 with self.assertRaises(ValueError):
6700 seqof[0] = Boolean(False)
6702 @given(data_strategy())
6703 def test_bounds_satisfied(self, d):
6704 class SeqOf(self.base_klass):
6706 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6707 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6708 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6709 SeqOf(value=value, bounds=(bound_min, bound_max))
6711 @given(data_strategy())
6712 def test_bounds_unsatisfied(self, d):
6713 class SeqOf(self.base_klass):
6715 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6716 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6717 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
6718 with self.assertRaises(BoundsError) as err:
6719 SeqOf(value=value, bounds=(bound_min, bound_max))
6721 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6722 SeqOf(bounds=(bound_min, bound_max)).decode(
6723 SeqOf(value).encode()
6726 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6727 SeqOf(bounds=(bound_min, bound_max)).decode(
6728 encode2pass(SeqOf(value))
6730 value = [Boolean(True)] * d.draw(integers(
6731 min_value=bound_max + 1,
6732 max_value=bound_max + 10,
6734 with self.assertRaises(BoundsError) as err:
6735 SeqOf(value=value, bounds=(bound_min, bound_max))
6737 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6738 SeqOf(bounds=(bound_min, bound_max)).decode(
6739 SeqOf(value).encode()
6742 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6743 SeqOf(bounds=(bound_min, bound_max)).decode(
6744 encode2pass(SeqOf(value))
6747 @given(integers(min_value=1, max_value=10))
6748 def test_out_of_bounds(self, bound_max):
6749 class SeqOf(self.base_klass):
6751 bounds = (0, bound_max)
6753 for _ in range(bound_max):
6754 seqof.append(Integer(123))
6755 with self.assertRaises(BoundsError):
6756 seqof.append(Integer(123))
6758 @given(data_strategy())
6759 def test_call(self, d):
6769 ) = d.draw(seqof_values_strategy())
6771 class SeqOf(self.base_klass):
6772 schema = schema_initial
6773 obj_initial = SeqOf(
6774 value=value_initial,
6775 bounds=bounds_initial,
6778 default=default_initial,
6779 optional=optional_initial or False,
6780 _decoded=_decoded_initial,
6791 ) = d.draw(seqof_values_strategy(
6792 schema=schema_initial,
6793 do_expl=impl_initial is None,
6795 if (default is None) and (obj_initial.default is not None):
6798 (bounds is None) and
6799 (value is not None) and
6800 (bounds_initial is not None) and
6801 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6805 (bounds is None) and
6806 (default is not None) and
6807 (bounds_initial is not None) and
6808 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6820 value_expected = default if value is None else value
6822 default_initial if value_expected is None
6825 value_expected = () if value_expected is None else value_expected
6826 self.assertEqual(obj, value_expected)
6827 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6828 self.assertEqual(obj.expl_tag, expl or expl_initial)
6831 default_initial if default is None else default,
6833 if obj.default is None:
6834 optional = optional_initial if optional is None else optional
6835 optional = False if optional is None else optional
6838 self.assertEqual(obj.optional, optional)
6840 (obj._bound_min, obj._bound_max),
6841 bounds or bounds_initial or (0, float("+inf")),
6844 @given(seqof_values_strategy())
6845 def test_copy(self, values):
6846 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6848 class SeqOf(self.base_klass):
6850 register_class(SeqOf)
6857 optional=optional or False,
6860 for copy_func in copy_funcs:
6861 obj_copied = copy_func(obj)
6862 self.assert_copied_basic_fields(obj, obj_copied)
6863 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6864 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6865 self.assertEqual(obj._value, obj_copied._value)
6869 integers(min_value=1).map(tag_encode),
6871 def test_stripped(self, values, tag_impl):
6872 class SeqOf(self.base_klass):
6873 schema = OctetString()
6874 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6875 with self.assertRaises(NotEnoughData):
6876 obj.decode(obj.encode()[:-1])
6880 integers(min_value=1).map(tag_ctxc),
6882 def test_stripped_expl(self, values, tag_expl):
6883 class SeqOf(self.base_klass):
6884 schema = OctetString()
6885 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6886 with self.assertRaises(NotEnoughData):
6887 obj.decode(obj.encode()[:-1])
6890 integers(min_value=31),
6891 integers(min_value=0),
6894 def test_bad_tag(self, tag, offset, decode_path):
6895 with self.assertRaises(DecodeError) as err:
6896 self.base_klass().decode(
6897 tag_encode(tag)[:-1],
6899 decode_path=decode_path,
6902 self.assertEqual(err.exception.offset, offset)
6903 self.assertEqual(err.exception.decode_path, decode_path)
6906 integers(min_value=128),
6907 integers(min_value=0),
6910 def test_bad_len(self, l, offset, decode_path):
6911 with self.assertRaises(DecodeError) as err:
6912 self.base_klass().decode(
6913 self.base_klass.tag_default + len_encode(l)[:-1],
6915 decode_path=decode_path,
6918 self.assertEqual(err.exception.offset, offset)
6919 self.assertEqual(err.exception.decode_path, decode_path)
6921 @given(binary(min_size=1))
6922 def test_tag_mismatch(self, impl):
6923 assume(impl != self.base_klass.tag_default)
6924 with self.assertRaises(TagMismatch):
6925 self.base_klass(impl=impl).decode(self.base_klass().encode())
6927 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6929 seqof_values_strategy(schema=Integer()),
6930 lists(integers().map(Integer)),
6931 integers(min_value=1).map(tag_ctxc),
6932 integers(min_value=0),
6936 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
6937 _, _, _, _, _, default, optional, _decoded = values
6939 class SeqOf(self.base_klass):
6949 pprint(obj, big_blobs=True, with_decode_path=True)
6950 self.assertFalse(obj.expled)
6951 obj_encoded = obj.encode()
6952 self.assertEqual(encode2pass(obj), obj_encoded)
6953 obj_encoded_cer = encode_cer(obj)
6954 self.assertNotEqual(obj_encoded_cer, obj_encoded)
6955 self.assertSequenceEqual(
6956 obj.decod(obj_encoded_cer, ctx={"bered": True}).encode(),
6959 obj_expled = obj(value, expl=tag_expl)
6960 self.assertTrue(obj_expled.expled)
6962 list(obj_expled.pps())
6963 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6964 obj_expled_encoded = obj_expled.encode()
6965 ctx_copied = deepcopy(ctx_dummy)
6966 obj_decoded, tail = obj_expled.decode(
6967 obj_expled_encoded + tail_junk,
6971 self.assertDictEqual(ctx_copied, ctx_dummy)
6973 list(obj_decoded.pps())
6974 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6975 self.assertEqual(tail, tail_junk)
6976 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6977 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6978 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6979 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6981 obj_decoded.expl_llen,
6982 len(len_encode(len(obj_encoded))),
6984 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
6985 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
6988 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
6990 self.assertEqual(obj_decoded.expl_offset, offset)
6991 for obj_inner in obj_decoded:
6992 self.assertIn(obj_inner, obj_decoded)
6993 self.assertSequenceEqual(
6996 obj_inner.offset - offset:
6997 obj_inner.offset + obj_inner.tlvlen - offset
7001 t, _, lv = tag_strip(obj_encoded)
7002 _, _, v = len_decode(lv)
7003 obj_encoded_lenindef = t + LENINDEF + v + EOC
7004 with self.assertRaises(DecodeError):
7005 obj.decode(obj_encoded_lenindef)
7006 obj_decoded_lenindef, tail_lenindef = obj.decode(
7007 obj_encoded_lenindef + tail_junk,
7008 ctx={"bered": True},
7010 self.assertTrue(obj_decoded_lenindef.lenindef)
7011 self.assertTrue(obj_decoded_lenindef.bered)
7012 obj_decoded_lenindef = copy(obj_decoded_lenindef)
7013 self.assertTrue(obj_decoded_lenindef.lenindef)
7014 self.assertTrue(obj_decoded_lenindef.bered)
7015 repr(obj_decoded_lenindef)
7016 list(obj_decoded_lenindef.pps())
7017 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
7018 self.assertEqual(tail_lenindef, tail_junk)
7019 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
7020 with self.assertRaises(DecodeError):
7021 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
7022 with self.assertRaises(DecodeError):
7023 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
7025 evgens = list(obj.decode_evgen(
7026 obj_encoded_lenindef + tail_junk,
7027 decode_path=decode_path,
7028 ctx={"bered": True},
7030 self.assertEqual(len(evgens), len(obj_decoded_lenindef) + 1)
7031 for i, (_decode_path, obj, _) in enumerate(evgens[:-1]):
7032 self.assertEqual(_decode_path, decode_path + (str(i),))
7035 _decode_path, obj, tail = evgens[-1]
7036 self.assertEqual(_decode_path, decode_path)
7040 assert_exceeding_data(
7042 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
7046 def test_bered(self):
7047 class SeqOf(self.base_klass):
7049 encoded = Boolean(False).encode()
7050 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
7051 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7052 with self.assertRaises(DecodeError):
7053 SeqOf().decode(encoded)
7054 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7055 self.assertFalse(decoded.ber_encoded)
7056 self.assertFalse(decoded.lenindef)
7057 self.assertTrue(decoded.bered)
7058 decoded = copy(decoded)
7059 self.assertFalse(decoded.ber_encoded)
7060 self.assertFalse(decoded.lenindef)
7061 self.assertTrue(decoded.bered)
7063 class SeqOf(self.base_klass):
7064 schema = OctetString()
7065 encoded = OctetString(b"whatever").encode()
7067 tag_encode(form=TagFormConstructed, num=4) +
7069 OctetString(b"whatever").encode() +
7072 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7073 with self.assertRaises(DecodeError):
7074 SeqOf().decode(encoded)
7075 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7076 self.assertFalse(decoded.ber_encoded)
7077 self.assertFalse(decoded.lenindef)
7078 self.assertTrue(decoded.bered)
7079 decoded = copy(decoded)
7080 self.assertFalse(decoded.ber_encoded)
7081 self.assertFalse(decoded.lenindef)
7082 self.assertTrue(decoded.bered)
7085 class TestSequenceOf(SeqOfMixin, CommonMixin, TestCase):
7086 class SeqOf(SequenceOf):
7090 def _test_symmetric_compare_objs(self, obj1, obj2):
7091 self.assertEqual(obj1, obj2)
7092 self.assertSequenceEqual(list(obj1), list(obj2))
7094 def test_iterator_pickling(self):
7095 class SeqOf(SequenceOf):
7097 register_class(SeqOf)
7100 seqof = seqof(iter(range(10)))
7101 with self.assertRaisesRegex(ValueError, "iterator"):
7104 def test_iterator_bounds(self):
7105 class SeqOf(SequenceOf):
7114 seqof = SeqOf(gen(n))
7115 self.assertTrue(seqof.ready)
7116 with self.assertRaises(BoundsError):
7118 self.assertFalse(seqof.ready)
7119 seqof = seqof(gen(n))
7120 self.assertTrue(seqof.ready)
7121 with self.assertRaises(BoundsError):
7123 self.assertFalse(seqof.ready)
7125 def test_iterator_twice(self):
7126 class SeqOf(SequenceOf):
7128 bounds = (1, float("+inf"))
7133 seqof = SeqOf(gen())
7134 self.assertTrue(seqof.ready)
7136 self.assertFalse(seqof.ready)
7137 register_class(SeqOf)
7140 def test_iterator_2pass(self):
7141 class SeqOf(SequenceOf):
7143 bounds = (1, float("+inf"))
7148 seqof = SeqOf(gen())
7149 self.assertTrue(seqof.ready)
7150 _, state = seqof.encode1st()
7151 self.assertFalse(seqof.ready)
7152 seqof = seqof(gen())
7153 self.assertTrue(seqof.ready)
7155 seqof.encode2nd(buf.write, iter(state))
7156 self.assertSequenceEqual(
7157 [int(i) for i in seqof.decod(buf.getvalue())],
7161 def test_non_ready_bound_min(self):
7162 class SeqOf(SequenceOf):
7164 bounds = (1, float("+inf"))
7166 self.assertFalse(seqof.ready)
7169 class TestSetOf(SeqOfMixin, CommonMixin, TestCase):
7174 def _test_symmetric_compare_objs(self, obj1, obj2):
7175 self.assertSetEqual(
7176 set(int(v) for v in obj1),
7177 set(int(v) for v in obj2),
7180 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7181 @given(data_strategy())
7182 def test_sorted(self, d):
7183 values = [OctetString(v) for v in d.draw(lists(binary()))]
7186 schema = OctetString()
7188 seq_encoded = seq.encode()
7189 seq_decoded, _ = seq.decode(seq_encoded)
7190 self.assertSequenceEqual(
7191 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
7192 b"".join(sorted([v.encode() for v in values])),
7195 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7196 @given(data_strategy())
7197 def test_unsorted(self, d):
7198 values = [OctetString(v).encode() for v in d.draw(sets(
7199 binary(min_size=1, max_size=5),
7203 values = d.draw(permutations(values))
7204 assume(values != sorted(values))
7205 encoded = b"".join(values)
7206 seq_encoded = b"".join((
7208 len_encode(len(encoded)),
7213 schema = OctetString()
7215 with self.assertRaisesRegex(DecodeError, "unordered SET OF"):
7216 seq.decode(seq_encoded)
7218 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
7219 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
7220 self.assertTrue(seq_decoded.ber_encoded)
7221 self.assertTrue(seq_decoded.bered)
7222 seq_decoded = copy(seq_decoded)
7223 self.assertTrue(seq_decoded.ber_encoded)
7224 self.assertTrue(seq_decoded.bered)
7225 self.assertSequenceEqual(
7226 [obj.encode() for obj in seq_decoded],
7231 class TestGoMarshalVectors(TestCase):
7233 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
7234 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
7235 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
7236 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
7237 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
7239 class Seq(Sequence):
7241 ("erste", Integer()),
7242 ("zweite", Integer(optional=True))
7245 seq["erste"] = Integer(64)
7246 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7247 seq["erste"] = Integer(0x123456)
7248 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
7249 seq["erste"] = Integer(64)
7250 seq["zweite"] = Integer(65)
7251 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
7253 class NestedSeq(Sequence):
7257 seq["erste"] = Integer(127)
7258 seq["zweite"] = None
7259 nested = NestedSeq()
7260 nested["nest"] = seq
7261 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
7263 self.assertSequenceEqual(
7264 OctetString(b"\x01\x02\x03").encode(),
7265 hexdec("0403010203"),
7268 class Seq(Sequence):
7270 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
7273 seq["erste"] = Integer(64)
7274 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
7276 class Seq(Sequence):
7278 ("erste", Integer(expl=tag_ctxc(5))),
7281 seq["erste"] = Integer(64)
7282 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
7284 class Seq(Sequence):
7287 impl=tag_encode(0, klass=TagClassContext),
7292 seq["erste"] = Null()
7293 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
7295 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7297 self.assertSequenceEqual(
7298 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
7299 hexdec("170d3730303130313030303030305a"),
7301 self.assertSequenceEqual(
7302 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
7303 hexdec("170d3039313131353232353631365a"),
7305 self.assertSequenceEqual(
7306 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
7307 hexdec("180f32313030303430353132303130315a"),
7310 class Seq(Sequence):
7312 ("erste", GeneralizedTime()),
7315 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
7316 self.assertSequenceEqual(
7318 hexdec("3011180f32303039313131353232353631365a"),
7321 self.assertSequenceEqual(
7322 BitString((1, b"\x80")).encode(),
7325 self.assertSequenceEqual(
7326 BitString((12, b"\x81\xF0")).encode(),
7327 hexdec("03030481f0"),
7330 self.assertSequenceEqual(
7331 ObjectIdentifier("1.2.3.4").encode(),
7332 hexdec("06032a0304"),
7334 self.assertSequenceEqual(
7335 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
7336 hexdec("06092a864888932d010105"),
7338 self.assertSequenceEqual(
7339 ObjectIdentifier("2.100.3").encode(),
7340 hexdec("0603813403"),
7343 self.assertSequenceEqual(
7344 PrintableString("test").encode(),
7345 hexdec("130474657374"),
7347 self.assertSequenceEqual(
7348 PrintableString("x" * 127).encode(),
7349 hexdec("137F" + "78" * 127),
7351 self.assertSequenceEqual(
7352 PrintableString("x" * 128).encode(),
7353 hexdec("138180" + "78" * 128),
7355 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
7357 class Seq(Sequence):
7359 ("erste", IA5String()),
7362 seq["erste"] = IA5String("test")
7363 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
7365 class Seq(Sequence):
7367 ("erste", PrintableString()),
7370 seq["erste"] = PrintableString("test")
7371 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
7372 # Asterisk is actually not allowable
7373 pyderasn.PRINTABLE_ALLOWABLE_CHARS |= set(b"*")
7374 seq["erste"] = PrintableString("test*")
7375 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
7376 pyderasn.PRINTABLE_ALLOWABLE_CHARS -= set(b"*")
7378 class Seq(Sequence):
7380 ("erste", Any(optional=True)),
7381 ("zweite", Integer()),
7384 seq["zweite"] = Integer(64)
7385 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7390 seq.append(Integer(10))
7391 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
7393 class _SeqOf(SequenceOf):
7394 schema = PrintableString()
7396 class SeqOf(SequenceOf):
7399 _seqof.append(PrintableString("1"))
7401 seqof.append(_seqof)
7402 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
7404 class Seq(Sequence):
7406 ("erste", Integer(default=1)),
7409 seq["erste"] = Integer(0)
7410 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
7411 seq["erste"] = Integer(1)
7412 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7413 seq["erste"] = Integer(2)
7414 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
7417 class TestPP(TestCase):
7418 @given(data_strategy())
7419 def test_oid_printing(self, d):
7421 str(ObjectIdentifier(k)): v * 2
7422 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
7424 chosen = d.draw(sampled_from(sorted(oids)))
7425 chosen_id = oids[chosen]
7426 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
7427 self.assertNotIn(chosen_id, pp_console_row(pp))
7430 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
7434 class TestAutoAddSlots(TestCase):
7436 class Inher(Integer):
7439 with self.assertRaises(AttributeError):
7441 inher.unexistent = "whatever"
7444 class TestOIDDefines(TestCase):
7445 @given(data_strategy())
7446 def runTest(self, d):
7447 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
7448 value_name_chosen = d.draw(sampled_from(value_names))
7450 ObjectIdentifier(oid)
7451 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
7453 oid_chosen = d.draw(sampled_from(oids))
7454 values = d.draw(lists(
7456 min_size=len(value_names),
7457 max_size=len(value_names),
7459 for definable_class in (Any, OctetString, BitString):
7461 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
7462 oid: Integer() for oid in oids[:-1]
7465 for i, value_name in enumerate(value_names):
7466 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
7468 class Seq(Sequence):
7471 for value_name, value in zip(value_names, values):
7472 seq[value_name] = definable_class(Integer(value).encode())
7473 seq["type"] = oid_chosen
7474 seq, _ = Seq().decode(seq.encode())
7475 for value_name in value_names:
7476 if value_name == value_name_chosen:
7478 self.assertIsNone(seq[value_name].defined)
7479 if value_name_chosen in oids[:-1]:
7480 self.assertIsNotNone(seq[value_name_chosen].defined)
7481 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
7482 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
7485 pprint(seq, big_blobs=True, with_decode_path=True)
7488 class TestDefinesByPath(TestCase):
7489 def test_generated(self):
7490 class Seq(Sequence):
7492 ("type", ObjectIdentifier()),
7493 ("value", OctetString(expl=tag_ctxc(123))),
7496 class SeqInner(Sequence):
7498 ("typeInner", ObjectIdentifier()),
7499 ("valueInner", Any()),
7502 class PairValue(SetOf):
7505 class Pair(Sequence):
7507 ("type", ObjectIdentifier()),
7508 ("value", PairValue()),
7511 class Pairs(SequenceOf):
7518 type_octet_stringed,
7520 ObjectIdentifier(oid)
7521 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
7523 seq_integered = Seq()
7524 seq_integered["type"] = type_integered
7525 seq_integered["value"] = OctetString(Integer(123).encode())
7526 seq_integered_raw = seq_integered.encode()
7530 (type_octet_stringed, OctetString(b"whatever")),
7531 (type_integered, Integer(123)),
7532 (type_octet_stringed, OctetString(b"whenever")),
7533 (type_integered, Integer(234)),
7535 for t, v in pairs_input:
7538 ("value", PairValue((Any(v),))),
7540 seq_inner = SeqInner()
7541 seq_inner["typeInner"] = type_innered
7542 seq_inner["valueInner"] = Any(pairs)
7543 seq_sequenced = Seq()
7544 seq_sequenced["type"] = type_sequenced
7545 seq_sequenced["value"] = OctetString(seq_inner.encode())
7546 seq_sequenced_raw = seq_sequenced.encode()
7548 list(seq_sequenced.pps())
7549 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7551 defines_by_path = []
7552 ctx_copied = deepcopy(ctx_dummy)
7553 seq_integered, _ = Seq().decode(
7557 self.assertDictEqual(ctx_copied, ctx_dummy)
7558 self.assertIsNone(seq_integered["value"].defined)
7559 defines_by_path.append(
7560 (("type",), ((("value",), {
7561 type_integered: Integer(),
7562 type_sequenced: SeqInner(),
7565 ctx_copied["defines_by_path"] = defines_by_path
7566 seq_integered, _ = Seq().decode(
7570 del ctx_copied["defines_by_path"]
7571 self.assertDictEqual(ctx_copied, ctx_dummy)
7572 self.assertIsNotNone(seq_integered["value"].defined)
7573 self.assertEqual(seq_integered["value"].defined[0], type_integered)
7574 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
7575 self.assertTrue(seq_integered_raw[
7576 seq_integered["value"].defined[1].offset:
7577 ].startswith(Integer(123).encode()))
7579 list(seq_integered.pps())
7580 pprint(seq_integered, big_blobs=True, with_decode_path=True)
7582 ctx_copied["defines_by_path"] = defines_by_path
7583 seq_sequenced, _ = Seq().decode(
7587 del ctx_copied["defines_by_path"]
7588 self.assertDictEqual(ctx_copied, ctx_dummy)
7589 self.assertIsNotNone(seq_sequenced["value"].defined)
7590 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7591 seq_inner = seq_sequenced["value"].defined[1]
7592 self.assertIsNone(seq_inner["valueInner"].defined)
7594 list(seq_sequenced.pps())
7595 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7597 defines_by_path.append((
7598 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
7599 ((("valueInner",), {type_innered: Pairs()}),),
7601 ctx_copied["defines_by_path"] = defines_by_path
7602 seq_sequenced, _ = Seq().decode(
7606 del ctx_copied["defines_by_path"]
7607 self.assertDictEqual(ctx_copied, ctx_dummy)
7608 self.assertIsNotNone(seq_sequenced["value"].defined)
7609 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7610 seq_inner = seq_sequenced["value"].defined[1]
7611 self.assertIsNotNone(seq_inner["valueInner"].defined)
7612 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7613 pairs = seq_inner["valueInner"].defined[1]
7615 self.assertIsNone(pair["value"][0].defined)
7617 list(seq_sequenced.pps())
7618 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7620 defines_by_path.append((
7623 DecodePathDefBy(type_sequenced),
7625 DecodePathDefBy(type_innered),
7630 type_integered: Integer(),
7631 type_octet_stringed: OctetString(),
7634 ctx_copied["defines_by_path"] = defines_by_path
7635 seq_sequenced, _ = Seq().decode(
7639 del ctx_copied["defines_by_path"]
7640 self.assertDictEqual(ctx_copied, ctx_dummy)
7641 self.assertIsNotNone(seq_sequenced["value"].defined)
7642 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7643 seq_inner = seq_sequenced["value"].defined[1]
7644 self.assertIsNotNone(seq_inner["valueInner"].defined)
7645 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7646 pairs_got = seq_inner["valueInner"].defined[1]
7647 for pair_input, pair_got in zip(pairs_input, pairs_got):
7648 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7649 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7651 list(seq_sequenced.pps())
7652 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7654 @given(oid_strategy(), integers())
7655 def test_simple(self, oid, tgt):
7656 class Inner(Sequence):
7658 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7659 ObjectIdentifier(oid): Integer(),
7663 class Outer(Sequence):
7666 ("tgt", OctetString()),
7670 inner["oid"] = ObjectIdentifier(oid)
7672 outer["inner"] = inner
7673 outer["tgt"] = OctetString(Integer(tgt).encode())
7674 decoded, _ = Outer().decode(outer.encode())
7675 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7677 def test_remaining_data(self):
7678 oid = ObjectIdentifier("1.2.3")
7680 class Seq(Sequence):
7682 ("oid", ObjectIdentifier(defines=((("tgt",), {
7685 ("tgt", OctetString()),
7690 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7692 with self.assertRaisesRegex(DecodeError, "remaining data"):
7693 Seq().decode(seq.encode())
7695 def test_remaining_data_seqof(self):
7696 oid = ObjectIdentifier("1.2.3")
7699 schema = OctetString()
7701 class Seq(Sequence):
7703 ("oid", ObjectIdentifier(defines=((("tgt",), {
7711 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7713 with self.assertRaisesRegex(DecodeError, "remaining data"):
7714 Seq().decode(seq.encode())
7717 class TestAbsDecodePath(TestCase):
7719 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7720 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7722 def test_concat(self, decode_path, rel_path):
7723 dp = abs_decode_path(decode_path, rel_path)
7724 self.assertSequenceEqual(dp, decode_path + rel_path)
7728 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7729 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7731 def test_abs(self, decode_path, rel_path):
7732 self.assertSequenceEqual(
7733 abs_decode_path(decode_path, ("/",) + rel_path),
7738 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7739 integers(min_value=1, max_value=3),
7740 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7742 def test_dots(self, decode_path, number_of_dots, rel_path):
7743 self.assertSequenceEqual(
7744 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7745 decode_path[:-number_of_dots] + rel_path,
7749 class TestStrictDefaultExistence(TestCase):
7750 @given(data_strategy())
7751 def runTest(self, d):
7752 count = d.draw(integers(min_value=1, max_value=10))
7753 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7755 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7756 for i in range(count)
7758 for klass in (Sequence, Set):
7762 for i in range(count):
7763 seq["int%d" % i] = Integer(123)
7765 chosen_choice = "int%d" % chosen
7766 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7767 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
7769 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7770 self.assertTrue(decoded.ber_encoded)
7771 self.assertTrue(decoded.bered)
7772 decoded = copy(decoded)
7773 self.assertTrue(decoded.ber_encoded)
7774 self.assertTrue(decoded.bered)
7775 decoded, _ = seq.decode(raw, ctx={"bered": True})
7776 self.assertTrue(decoded.ber_encoded)
7777 self.assertTrue(decoded.bered)
7778 decoded = copy(decoded)
7779 self.assertTrue(decoded.ber_encoded)
7780 self.assertTrue(decoded.bered)
7783 class TestX690PrefixedType(TestCase):
7785 self.assertSequenceEqual(
7786 VisibleString("Jones").encode(),
7787 hexdec("1A054A6F6E6573"),
7791 self.assertSequenceEqual(
7794 impl=tag_encode(3, klass=TagClassApplication),
7796 hexdec("43054A6F6E6573"),
7800 self.assertSequenceEqual(
7804 impl=tag_encode(3, klass=TagClassApplication),
7808 hexdec("A20743054A6F6E6573"),
7812 self.assertSequenceEqual(
7816 impl=tag_encode(3, klass=TagClassApplication),
7818 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7820 hexdec("670743054A6F6E6573"),
7824 self.assertSequenceEqual(
7825 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7826 hexdec("82054A6F6E6573"),
7830 class TestExplOOB(TestCase):
7832 expl = tag_ctxc(123)
7833 raw = Integer(123).encode() + Integer(234).encode()
7834 raw = b"".join((expl, len_encode(len(raw)), raw))
7835 with self.assertRaisesRegex(DecodeError, "explicit tag out-of-bound"):
7836 Integer(expl=expl).decode(raw)
7837 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7840 class TestPickleDifferentVersion(TestCase):
7842 pickled = pickle_dumps(Integer(123), pickle_proto)
7844 version_orig = pyderasn.__version__
7845 pyderasn.__version__ += "different"
7846 with self.assertRaisesRegex(ValueError, "different PyDERASN version"):
7847 pickle_loads(pickled)
7848 pyderasn.__version__ = version_orig
7849 pickle_loads(pickled)
7852 class TestCERSetOrdering(TestCase):
7853 def test_vectors(self):
7854 """Taken from X.690-201508
7858 ("c", Integer(impl=tag_ctxp(2))),
7859 ("d", Integer(impl=tag_ctxp(4))),
7864 ("g", Integer(impl=tag_ctxp(5))),
7865 ("h", Integer(impl=tag_ctxp(6))),
7870 ("j", Integer(impl=tag_ctxp(0))),
7881 ("a", Integer(impl=tag_ctxp(3))),
7882 ("b", B(expl=tag_ctxc(1))),
7887 ("a", Integer(123)),
7888 ("b", B(("d", Integer(234)))),
7889 ("e", E(("f", F(("g", Integer(345)))))),
7891 order = sorted(a._values_for_encoding(), key=attrgetter("tag_order_cer"))
7892 self.assertSequenceEqual(
7893 [i.__class__.__name__ for i in order],
7894 ("E", "B", "Integer"),