2 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures
3 # Copyright (C) 2017-2022 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
35 from unittest.mock import patch
37 from dateutil.tz import UTC
38 from hypothesis import assume
39 from hypothesis import given
40 from hypothesis import settings
41 from hypothesis.strategies import binary
42 from hypothesis.strategies import booleans
43 from hypothesis.strategies import composite
44 from hypothesis.strategies import data as data_strategy
45 from hypothesis.strategies import datetimes
46 from hypothesis.strategies import dictionaries
47 from hypothesis.strategies import integers
48 from hypothesis.strategies import just
49 from hypothesis.strategies import lists
50 from hypothesis.strategies import none
51 from hypothesis.strategies import one_of
52 from hypothesis.strategies import permutations
53 from hypothesis.strategies import sampled_from
54 from hypothesis.strategies import sets
55 from hypothesis.strategies import text
56 from hypothesis.strategies import tuples
57 from pickle import dumps as pickle_dumps
58 from pickle import HIGHEST_PROTOCOL as pickle_proto
59 from pickle import loads as pickle_loads
61 from pyderasn import _pp
62 from pyderasn import abs_decode_path
63 from pyderasn import Any
64 from pyderasn import BitString
65 from pyderasn import BMPString
66 from pyderasn import Boolean
67 from pyderasn import BoundsError
68 from pyderasn import Choice
69 from pyderasn import DecodeError
70 from pyderasn import DecodePathDefBy
71 from pyderasn import encode2pass
72 from pyderasn import encode_cer
73 from pyderasn import Enumerated
74 from pyderasn import EOC
75 from pyderasn import EOC_LEN
76 from pyderasn import ExceedingData
77 from pyderasn import GeneralizedTime
78 from pyderasn import GeneralString
79 from pyderasn import GraphicString
80 from pyderasn import hexdec
81 from pyderasn import hexenc
82 from pyderasn import IA5String
83 from pyderasn import Integer
84 from pyderasn import InvalidLength
85 from pyderasn import InvalidOID
86 from pyderasn import InvalidValueType
87 from pyderasn import len_decode
88 from pyderasn import len_encode
89 from pyderasn import LEN_YYMMDDHHMMSSZ
90 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
91 from pyderasn import LEN_YYYYMMDDHHMMSSZ
92 from pyderasn import LENINDEF
93 from pyderasn import LenIndefForm
94 from pyderasn import NotEnoughData
95 from pyderasn import Null
96 from pyderasn import NumericString
97 from pyderasn import ObjectIdentifier
98 from pyderasn import ObjNotReady
99 from pyderasn import ObjUnknown
100 from pyderasn import OctetString
101 from pyderasn import pp_console_row
102 from pyderasn import pprint
103 from pyderasn import PrintableString
104 from pyderasn import Sequence
105 from pyderasn import SequenceOf
106 from pyderasn import Set
107 from pyderasn import SetOf
108 from pyderasn import tag_ctxc
109 from pyderasn import tag_ctxp
110 from pyderasn import tag_decode
111 from pyderasn import tag_encode
112 from pyderasn import tag_strip
113 from pyderasn import TagClassApplication
114 from pyderasn import TagClassContext
115 from pyderasn import TagClassPrivate
116 from pyderasn import TagClassUniversal
117 from pyderasn import TagFormConstructed
118 from pyderasn import TagFormPrimitive
119 from pyderasn import TagMismatch
120 from pyderasn import TeletexString
121 from pyderasn import UniversalString
122 from pyderasn import UTCTime
123 from pyderasn import UTF8String
124 from pyderasn import VideotexString
125 from pyderasn import VisibleString
129 max_examples = environ.get("MAX_EXAMPLES")
130 settings.register_profile("local", settings(
132 **({"max_examples": int(max_examples)} if max_examples else {})
134 settings.load_profile("local")
135 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
137 tag_classes = sampled_from((
143 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
144 decode_path_strat = lists(integers(), max_size=3).map(
145 lambda decode_path: tuple(str(dp) for dp in decode_path)
147 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
150 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
152 self_module = import_module(__name__)
155 def register_class(klass):
156 klassname = klass.__name__ + str(time()).replace(".", "")
157 klass.__name__ = klassname
158 klass.__qualname__ = klassname
159 setattr(self_module, klassname, klass)
162 def assert_exceeding_data(self, call, junk):
165 with self.assertRaisesRegex(ExceedingData, "%d trailing bytes" % len(junk)) as err:
170 class TestHex(TestCase):
172 def test_symmetric(self, data):
173 self.assertEqual(hexdec(hexenc(data)), data)
176 class TestTagCoder(TestCase):
177 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
181 integers(min_value=0, max_value=30),
184 def test_short(self, klass, form, num, junk):
185 raw = tag_encode(klass=klass, form=form, num=num)
186 self.assertEqual(tag_decode(raw), (klass, form, num))
187 self.assertEqual(len(raw), 1)
189 tag_encode(klass=klass, form=form, num=0)[0],
190 raw[0] & (1 << 7 | 1 << 6 | 1 << 5),
192 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
193 self.assertSequenceEqual(stripped.tobytes(), raw)
194 self.assertEqual(tlen, len(raw))
195 self.assertSequenceEqual(tail, junk)
197 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
201 integers(min_value=31),
204 def test_long(self, klass, form, num, junk):
205 raw = tag_encode(klass=klass, form=form, num=num)
206 self.assertEqual(tag_decode(raw), (klass, form, num))
207 self.assertGreater(len(raw), 1)
209 tag_encode(klass=klass, form=form, num=0)[0] | 31,
212 self.assertEqual(raw[-1] & 0x80, 0)
213 self.assertTrue(all(b & 0x80 > 0 for b in raw[1:-1]))
214 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
215 self.assertSequenceEqual(stripped.tobytes(), raw)
216 self.assertEqual(tlen, len(raw))
217 self.assertSequenceEqual(tail, junk)
219 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
220 @given(integers(min_value=31))
221 def test_unfinished_tag(self, num):
222 raw = bytearray(tag_encode(num=num))
223 for i in range(1, len(raw)):
225 with self.assertRaisesRegex(DecodeError, "unfinished tag"):
226 tag_strip(bytes(raw))
228 def test_go_vectors_valid(self):
229 for data, (eklass, etag, elen, eform) in (
230 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
231 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
232 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
233 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
234 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
235 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
236 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
237 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
238 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
239 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
241 tag, _, len_encoded = tag_strip(memoryview(data))
242 klass, form, num = tag_decode(tag)
243 _len, _, tail = len_decode(len_encoded)
244 self.assertSequenceEqual(tail, b"")
245 self.assertEqual(klass, eklass)
246 self.assertEqual(num, etag)
247 self.assertEqual(_len, elen)
248 self.assertEqual(form, eform)
250 def test_go_vectors_invalid(self):
258 with self.assertRaises(DecodeError):
259 _, _, len_encoded = tag_strip(memoryview(data))
260 len_decode(len_encoded)
263 integers(min_value=0, max_value=127),
264 integers(min_value=0, max_value=2),
266 def test_long_instead_of_short(self, l, dummy_num):
267 octets = (b"\x00" * dummy_num) + bytes([l])
268 octets = bytes([(dummy_num + 1) | 0x80]) + octets
269 with self.assertRaises(DecodeError):
272 @given(tag_classes, tag_forms, integers(min_value=31))
273 def test_leading_zero_byte(self, klass, form, num):
274 raw = tag_encode(klass=klass, form=form, num=num)
275 raw = b"".join((raw[:1], b"\x80", raw[1:]))
276 with self.assertRaisesRegex(DecodeError, "leading zero byte"):
279 @given(tag_classes, tag_forms, integers(max_value=30, min_value=0))
280 def test_unexpected_long_form(self, klass, form, num):
281 raw = bytes([klass | form | 31, num])
282 with self.assertRaisesRegex(DecodeError, "unexpected long form"):
286 class TestLenCoder(TestCase):
287 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
289 integers(min_value=0, max_value=127),
292 def test_short(self, l, junk):
293 raw = len_encode(l) + junk
294 decoded, llen, tail = len_decode(memoryview(raw))
295 self.assertEqual(decoded, l)
296 self.assertEqual(llen, 1)
297 self.assertEqual(len(raw), 1 + len(junk))
298 self.assertEqual(tail.tobytes(), junk)
300 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
302 integers(min_value=128),
305 def test_long(self, l, junk):
306 raw = len_encode(l) + junk
307 decoded, llen, tail = len_decode(memoryview(raw))
308 self.assertEqual(decoded, l)
309 self.assertEqual((llen - 1) | 0x80, raw[0])
310 self.assertEqual(llen, len(raw) - len(junk))
311 self.assertNotEqual(raw[1], 0)
312 self.assertSequenceEqual(tail.tobytes(), junk)
314 def test_empty(self):
315 with self.assertRaises(NotEnoughData):
318 @given(integers(min_value=128))
319 def test_stripped(self, _len):
320 with self.assertRaises(NotEnoughData):
321 len_decode(len_encode(_len)[:-1])
324 text_printable = text(alphabet=printable, min_size=1)
328 def text_letters(draw):
329 result = draw(text(alphabet=ascii_letters, min_size=1))
333 class CommonMixin(object):
334 def test_tag_default(self):
335 obj = self.base_klass()
336 self.assertEqual(obj.tag, obj.tag_default)
338 def test_simultaneous_impl_expl(self):
339 with self.assertRaises(ValueError):
340 self.base_klass(impl=b"whatever", expl=b"whenever")
342 @given(binary(min_size=1), integers(), integers(), integers())
343 def test_decoded(self, impl, offset, llen, vlen):
344 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
345 self.assertEqual(obj.offset, offset)
346 self.assertEqual(obj.llen, llen)
347 self.assertEqual(obj.vlen, vlen)
348 self.assertEqual(obj.tlen, len(impl))
349 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
351 @given(binary(min_size=1))
352 def test_impl_inherited(self, impl_tag):
353 class Inherited(self.base_klass):
356 self.assertSequenceEqual(obj.impl, impl_tag)
357 self.assertFalse(obj.expled)
359 tag_class, _, tag_num = tag_decode(impl_tag)
360 self.assertEqual(obj.tag_order, (tag_class, tag_num))
362 @given(binary(min_size=1))
363 def test_expl_inherited(self, expl_tag):
364 class Inherited(self.base_klass):
367 self.assertSequenceEqual(obj.expl, expl_tag)
368 self.assertTrue(obj.expled)
370 tag_class, _, tag_num = tag_decode(expl_tag)
371 self.assertEqual(obj.tag_order, (tag_class, tag_num))
373 def assert_copied_basic_fields(self, obj, obj_copied):
374 self.assertEqual(obj, obj_copied)
375 self.assertSequenceEqual(obj.tag, obj_copied.tag)
376 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
377 self.assertEqual(obj.default, obj_copied.default)
378 self.assertEqual(obj.optional, obj_copied.optional)
379 self.assertEqual(obj.offset, obj_copied.offset)
380 self.assertEqual(obj.llen, obj_copied.llen)
381 self.assertEqual(obj.vlen, obj_copied.vlen)
383 self.assertEqual(obj.tag_order, obj_copied.tag_order)
387 def boolean_values_strategy(draw, do_expl=False):
388 value = draw(one_of(none(), booleans()))
392 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
394 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
395 default = draw(one_of(none(), booleans()))
396 optional = draw(one_of(none(), booleans()))
398 draw(integers(min_value=0)),
399 draw(integers(min_value=0)),
400 draw(integers(min_value=0)),
402 return (value, impl, expl, default, optional, _decoded)
405 class BooleanInherited(Boolean):
409 class TestBoolean(CommonMixin, TestCase):
412 def test_invalid_value_type(self):
413 with self.assertRaises(InvalidValueType) as err:
418 def test_optional(self, optional):
419 obj = Boolean(default=Boolean(False), optional=optional)
420 self.assertTrue(obj.optional)
423 def test_ready(self, value):
425 self.assertFalse(obj.ready)
428 pprint(obj, big_blobs=True, with_decode_path=True)
429 with self.assertRaises(ObjNotReady) as err:
431 with self.assertRaises(ObjNotReady) as err:
435 self.assertTrue(obj.ready)
438 pprint(obj, big_blobs=True, with_decode_path=True)
440 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
441 def test_comparison(self, value1, value2, tag1, tag2):
442 for klass in (Boolean, BooleanInherited):
445 self.assertEqual(obj1 == obj2, value1 == value2)
446 self.assertEqual(obj1 != obj2, value1 != value2)
447 self.assertEqual(obj1 == bool(obj2), value1 == value2)
448 obj1 = klass(value1, impl=tag1)
449 obj2 = klass(value1, impl=tag2)
450 self.assertEqual(obj1 == obj2, tag1 == tag2)
451 self.assertEqual(obj1 != obj2, tag1 != tag2)
453 @given(data_strategy())
454 def test_call(self, d):
455 for klass in (Boolean, BooleanInherited):
463 ) = d.draw(boolean_values_strategy())
469 optional_initial or False,
479 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
480 obj = obj_initial(value, impl, expl, default, optional)
482 value_expected = default if value is None else value
484 default_initial if value_expected is None
487 self.assertEqual(obj, value_expected)
488 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
489 self.assertEqual(obj.expl_tag, expl or expl_initial)
492 default_initial if default is None else default,
494 if obj.default is None:
495 optional = optional_initial if optional is None else optional
496 optional = False if optional is None else optional
499 self.assertEqual(obj.optional, optional)
501 @given(boolean_values_strategy())
502 def test_copy(self, values):
503 for klass in (Boolean, BooleanInherited):
505 for copy_func in copy_funcs:
506 obj_copied = copy_func(obj)
507 self.assert_copied_basic_fields(obj, obj_copied)
511 integers(min_value=1).map(tag_encode),
513 def test_stripped(self, value, tag_impl):
514 obj = Boolean(value, impl=tag_impl)
515 with self.assertRaises(NotEnoughData):
516 obj.decode(obj.encode()[:-1])
517 with self.assertRaises(NotEnoughData):
518 obj.decode(encode2pass(obj)[:-1])
522 integers(min_value=1).map(tag_ctxc),
524 def test_stripped_expl(self, value, tag_expl):
525 obj = Boolean(value, expl=tag_expl)
526 with self.assertRaises(NotEnoughData):
527 obj.decode(obj.encode()[:-1])
528 with self.assertRaises(NotEnoughData):
529 obj.decode(encode2pass(obj)[:-1])
532 integers(min_value=31),
533 integers(min_value=0),
536 def test_bad_tag(self, tag, offset, decode_path):
537 with self.assertRaises(DecodeError) as err:
539 tag_encode(tag)[:-1],
541 decode_path=decode_path,
544 self.assertEqual(err.exception.offset, offset)
545 self.assertEqual(err.exception.decode_path, decode_path)
548 integers(min_value=31),
549 integers(min_value=0),
552 def test_bad_expl_tag(self, tag, offset, decode_path):
553 with self.assertRaises(DecodeError) as err:
554 Boolean(expl=Boolean.tag_default).decode(
555 tag_encode(tag)[:-1],
557 decode_path=decode_path,
560 self.assertEqual(err.exception.offset, offset)
561 self.assertEqual(err.exception.decode_path, decode_path)
564 integers(min_value=128),
565 integers(min_value=0),
568 def test_bad_len(self, l, offset, decode_path):
569 with self.assertRaises(DecodeError) as err:
571 Boolean.tag_default + len_encode(l)[:-1],
573 decode_path=decode_path,
576 self.assertEqual(err.exception.offset, offset)
577 self.assertEqual(err.exception.decode_path, decode_path)
580 integers(min_value=128),
581 integers(min_value=0),
584 def test_bad_expl_len(self, l, offset, decode_path):
585 with self.assertRaises(DecodeError) as err:
586 Boolean(expl=Boolean.tag_default).decode(
587 Boolean.tag_default + len_encode(l)[:-1],
589 decode_path=decode_path,
592 self.assertEqual(err.exception.offset, offset)
593 self.assertEqual(err.exception.decode_path, decode_path)
595 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
597 boolean_values_strategy(),
599 integers(min_value=1).map(tag_ctxc),
600 integers(min_value=0),
604 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
605 for klass in (Boolean, BooleanInherited):
606 _, _, _, default, optional, _decoded = values
615 pprint(obj, big_blobs=True, with_decode_path=True)
616 self.assertFalse(obj.expled)
617 obj_encoded = obj.encode()
618 self.assertEqual(encode2pass(obj), obj_encoded)
619 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
620 obj_expled = obj(value, expl=tag_expl)
621 self.assertTrue(obj_expled.expled)
623 list(obj_expled.pps())
624 pprint(obj_expled, big_blobs=True, with_decode_path=True)
625 obj_expled_cer = encode_cer(obj_expled)
626 self.assertNotEqual(obj_expled_cer, obj_encoded)
627 self.assertSequenceEqual(
628 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
631 obj_expled_hex_encoded = obj_expled.hexencode()
632 ctx_copied = deepcopy(ctx_dummy)
633 obj_decoded, tail = obj_expled.hexdecode(
634 obj_expled_hex_encoded + hexenc(tail_junk),
638 self.assertDictEqual(ctx_copied, ctx_dummy)
640 list(obj_decoded.pps())
641 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
642 self.assertEqual(tail, tail_junk)
643 self.assertEqual(obj_decoded, obj_expled)
644 self.assertNotEqual(obj_decoded, obj)
645 self.assertEqual(bool(obj_decoded), bool(obj_expled))
646 self.assertEqual(bool(obj_decoded), bool(obj))
647 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
648 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
649 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
651 obj_decoded.expl_llen,
652 len(len_encode(len(obj_encoded))),
654 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
655 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
658 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
660 self.assertEqual(obj_decoded.expl_offset, offset)
661 assert_exceeding_data(
663 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
667 evgens = list(obj_expled.decode_evgen(
668 hexdec(obj_expled_hex_encoded) + tail_junk,
670 decode_path=decode_path,
673 self.assertEqual(len(evgens), 1)
674 _decode_path, obj, tail = evgens[0]
675 self.assertSequenceEqual(tail, tail_junk)
676 self.assertEqual(_decode_path, decode_path)
677 self.assertEqual(obj, obj_decoded)
678 self.assertEqual(obj.expl_offset, offset)
682 @given(integers(min_value=2, max_value=10))
683 def test_invalid_len(self, l):
684 with self.assertRaises(InvalidLength):
685 Boolean().decode(b"".join((
691 @given(integers(min_value=0 + 1, max_value=255 - 1))
692 def test_ber_value(self, value):
693 with self.assertRaisesRegex(DecodeError, "unacceptable Boolean value"):
694 Boolean().decode(b"".join((
699 encoded = b"".join((Boolean.tag_default, len_encode(1), bytes([value])))
700 obj, _ = Boolean().decode(encoded, ctx={"bered": True})
701 list(Boolean().decode_evgen(encoded, ctx={"bered": True}))
702 self.assertTrue(bool(obj))
703 self.assertTrue(obj.ber_encoded)
704 self.assertFalse(obj.lenindef)
705 self.assertTrue(obj.bered)
707 self.assertTrue(obj.ber_encoded)
708 self.assertFalse(obj.lenindef)
709 self.assertTrue(obj.bered)
712 integers(min_value=1).map(tag_ctxc),
713 binary().filter(lambda x: not x.startswith(EOC)),
715 def test_ber_expl_no_eoc(self, expl, junk):
716 encoded = expl + LENINDEF + Boolean(False).encode()
717 with self.assertRaises(LenIndefForm):
718 Boolean(expl=expl).decode(encoded + junk)
719 with self.assertRaisesRegex(DecodeError, "no EOC"):
720 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
721 obj, tail = Boolean(expl=expl).decode(
722 encoded + EOC + junk,
725 self.assertTrue(obj.expl_lenindef)
726 self.assertFalse(obj.lenindef)
727 self.assertFalse(obj.ber_encoded)
728 self.assertTrue(obj.bered)
730 self.assertTrue(obj.expl_lenindef)
731 self.assertFalse(obj.lenindef)
732 self.assertFalse(obj.ber_encoded)
733 self.assertTrue(obj.bered)
734 self.assertSequenceEqual(tail, junk)
737 pprint(obj, big_blobs=True, with_decode_path=True)
740 integers(min_value=1).map(tag_ctxc),
747 def test_ber_expl(self, expl, values):
753 Boolean(value).encode() +
756 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
758 class SeqOf(SequenceOf):
759 schema = Boolean(expl=expl)
760 with self.assertRaises(LenIndefForm):
761 SeqOf().decode(encoded)
762 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
763 list(SeqOf().decode_evgen(encoded, ctx={"bered": True}))
764 self.assertSequenceEqual(tail, b"")
765 self.assertSequenceEqual([bool(v) for v in seqof], values)
781 len(expl) + 1 + 3 + EOC_LEN,
792 pprint(seqof, big_blobs=True, with_decode_path=True)
796 def integer_values_strategy(draw, do_expl=False):
797 bound_min, value, default, bound_max = sorted(draw(sets(
806 _specs = draw(sets(text_letters()))
809 min_size=len(_specs),
810 max_size=len(_specs),
812 _specs = list(zip(_specs, values))
815 bounds = (bound_min, bound_max)
819 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
821 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
824 optional = draw(one_of(none(), booleans()))
826 draw(integers(min_value=0)),
827 draw(integers(min_value=0)),
828 draw(integers(min_value=0)),
830 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
833 class IntegerInherited(Integer):
837 class TestInteger(CommonMixin, TestCase):
840 def test_invalid_value_type(self):
841 with self.assertRaises(InvalidValueType) as err:
845 @given(sets(text_letters(), min_size=2))
846 def test_unknown_name(self, names_input):
847 missing = names_input.pop()
850 schema = [(n, 123) for n in names_input]
851 with self.assertRaises(ObjUnknown) as err:
855 @given(sets(text_letters(), min_size=2))
856 def test_known_name(self, names_input):
858 schema = [(n, 123) for n in names_input]
859 Int(names_input.pop())
862 def test_optional(self, optional):
863 obj = Integer(default=Integer(0), optional=optional)
864 self.assertTrue(obj.optional)
867 def test_ready(self, value):
869 self.assertFalse(obj.ready)
872 pprint(obj, big_blobs=True, with_decode_path=True)
873 with self.assertRaises(ObjNotReady) as err:
875 with self.assertRaises(ObjNotReady) as err:
879 self.assertTrue(obj.ready)
882 pprint(obj, big_blobs=True, with_decode_path=True)
885 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
886 def test_comparison(self, value1, value2, tag1, tag2):
887 for klass in (Integer, IntegerInherited):
890 self.assertEqual(obj1 == obj2, value1 == value2)
891 self.assertEqual(obj1 != obj2, value1 != value2)
892 self.assertEqual(obj1 == int(obj2), value1 == value2)
893 obj1 = klass(value1, impl=tag1)
894 obj2 = klass(value1, impl=tag2)
895 self.assertEqual(obj1 == obj2, tag1 == tag2)
896 self.assertEqual(obj1 != obj2, tag1 != tag2)
898 @given(lists(integers()))
899 def test_sorted_works(self, values):
900 self.assertSequenceEqual(
901 [int(v) for v in sorted(Integer(v) for v in values)],
905 @given(data_strategy())
906 def test_named(self, d):
907 names_input = list(d.draw(sets(text_letters(), min_size=1)))
908 values_input = list(d.draw(sets(
910 min_size=len(names_input),
911 max_size=len(names_input),
913 chosen_name = d.draw(sampled_from(names_input))
914 names_input = dict(zip(names_input, values_input))
918 _int = Int(chosen_name)
919 self.assertEqual(_int.named, chosen_name)
920 self.assertEqual(int(_int), names_input[chosen_name])
922 @given(integers(), integers(min_value=0), integers(min_value=0))
923 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
924 value = bound_min + value_delta
925 bound_max = value + bound_delta
926 Integer(value=value, bounds=(bound_min, bound_max))
928 @given(sets(integers(), min_size=3, max_size=3))
929 def test_bounds_unsatisfied(self, values):
930 values = sorted(values)
931 with self.assertRaises(BoundsError) as err:
932 Integer(value=values[0], bounds=(values[1], values[2]))
934 with self.assertRaisesRegex(DecodeError, "bounds") as err:
935 Integer(bounds=(values[1], values[2])).decode(
936 Integer(values[0]).encode()
939 with self.assertRaisesRegex(DecodeError, "bounds") as err:
940 Integer(bounds=(values[1], values[2])).decode(
941 encode2pass(Integer(values[0]))
943 with self.assertRaises(BoundsError) as err:
944 Integer(value=values[2], bounds=(values[0], values[1]))
946 with self.assertRaisesRegex(DecodeError, "bounds") as err:
947 Integer(bounds=(values[0], values[1])).decode(
948 Integer(values[2]).encode()
951 with self.assertRaisesRegex(DecodeError, "bounds") as err:
952 Integer(bounds=(values[0], values[1])).decode(
953 encode2pass(Integer(values[2]))
956 @given(data_strategy())
957 def test_call(self, d):
958 for klass in (Integer, IntegerInherited):
968 ) = d.draw(integer_values_strategy())
975 optional_initial or False,
988 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
989 if (default is None) and (obj_initial.default is not None):
993 (value is not None) and
994 (bounds_initial is not None) and
995 not (bounds_initial[0] <= value <= bounds_initial[1])
1000 (default is not None) and
1001 (bounds_initial is not None) and
1002 not (bounds_initial[0] <= default <= bounds_initial[1])
1005 obj = obj_initial(value, bounds, impl, expl, default, optional)
1007 value_expected = default if value is None else value
1009 default_initial if value_expected is None
1012 self.assertEqual(obj, value_expected)
1013 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1014 self.assertEqual(obj.expl_tag, expl or expl_initial)
1017 default_initial if default is None else default,
1019 if obj.default is None:
1020 optional = optional_initial if optional is None else optional
1021 optional = False if optional is None else optional
1024 self.assertEqual(obj.optional, optional)
1026 (obj._bound_min, obj._bound_max),
1027 bounds or bounds_initial or (float("-inf"), float("+inf")),
1031 {} if _specs_initial is None else dict(_specs_initial),
1034 @given(integer_values_strategy())
1035 def test_copy(self, values):
1036 for klass in (Integer, IntegerInherited):
1037 obj = klass(*values)
1038 for copy_func in copy_funcs:
1039 obj_copied = copy_func(obj)
1040 self.assert_copied_basic_fields(obj, obj_copied)
1041 self.assertEqual(obj.specs, obj_copied.specs)
1042 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1043 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1044 self.assertEqual(obj._value, obj_copied._value)
1048 integers(min_value=1).map(tag_encode),
1050 def test_stripped(self, value, tag_impl):
1051 obj = Integer(value, impl=tag_impl)
1052 with self.assertRaises(NotEnoughData):
1053 obj.decode(obj.encode()[:-1])
1057 integers(min_value=1).map(tag_ctxc),
1059 def test_stripped_expl(self, value, tag_expl):
1060 obj = Integer(value, expl=tag_expl)
1061 with self.assertRaises(NotEnoughData):
1062 obj.decode(obj.encode()[:-1])
1064 def test_zero_len(self):
1065 with self.assertRaises(NotEnoughData):
1066 Integer().decode(b"".join((
1067 Integer.tag_default,
1072 integers(min_value=31),
1073 integers(min_value=0),
1076 def test_bad_tag(self, tag, offset, decode_path):
1077 with self.assertRaises(DecodeError) as err:
1079 tag_encode(tag)[:-1],
1081 decode_path=decode_path,
1084 self.assertEqual(err.exception.offset, offset)
1085 self.assertEqual(err.exception.decode_path, decode_path)
1088 integers(min_value=128),
1089 integers(min_value=0),
1092 def test_bad_len(self, l, offset, decode_path):
1093 with self.assertRaises(DecodeError) as err:
1095 Integer.tag_default + len_encode(l)[:-1],
1097 decode_path=decode_path,
1100 self.assertEqual(err.exception.offset, offset)
1101 self.assertEqual(err.exception.decode_path, decode_path)
1104 sets(integers(), min_size=2, max_size=2),
1105 integers(min_value=0),
1108 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1109 value, bound_min = list(sorted(ints))
1112 bounds = (bound_min, bound_min)
1113 with self.assertRaises(DecodeError) as err:
1115 Integer(value).encode(),
1117 decode_path=decode_path,
1120 self.assertEqual(err.exception.offset, offset)
1121 self.assertEqual(err.exception.decode_path, decode_path)
1123 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1125 integer_values_strategy(),
1127 integers(min_value=1).map(tag_ctxc),
1128 integers(min_value=0),
1132 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
1133 for klass in (Integer, IntegerInherited):
1134 _, _, _, _, default, optional, _, _decoded = values
1143 pprint(obj, big_blobs=True, with_decode_path=True)
1144 self.assertFalse(obj.expled)
1145 obj_encoded = obj.encode()
1146 self.assertEqual(encode2pass(obj), obj_encoded)
1147 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1148 obj_expled = obj(value, expl=tag_expl)
1149 self.assertTrue(obj_expled.expled)
1151 list(obj_expled.pps())
1152 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1153 obj_expled_encoded = obj_expled.encode()
1154 obj_expled_cer = encode_cer(obj_expled)
1155 self.assertNotEqual(obj_expled_cer, obj_encoded)
1156 self.assertSequenceEqual(
1157 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1160 ctx_copied = deepcopy(ctx_dummy)
1161 obj_decoded, tail = obj_expled.decode(
1162 obj_expled_encoded + tail_junk,
1166 self.assertDictEqual(ctx_copied, ctx_dummy)
1168 list(obj_decoded.pps())
1169 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1170 self.assertEqual(tail, tail_junk)
1171 self.assertEqual(obj_decoded, obj_expled)
1172 self.assertNotEqual(obj_decoded, obj)
1173 self.assertEqual(int(obj_decoded), int(obj_expled))
1174 self.assertEqual(int(obj_decoded), int(obj))
1175 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1176 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1177 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1179 obj_decoded.expl_llen,
1180 len(len_encode(len(obj_encoded))),
1182 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1183 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1186 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1188 self.assertEqual(obj_decoded.expl_offset, offset)
1189 assert_exceeding_data(
1191 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1195 evgens = list(obj_expled.decode_evgen(
1196 obj_expled_encoded + tail_junk,
1198 decode_path=decode_path,
1201 self.assertEqual(len(evgens), 1)
1202 _decode_path, obj, tail = evgens[0]
1203 self.assertSequenceEqual(tail, tail_junk)
1204 self.assertEqual(_decode_path, decode_path)
1205 self.assertEqual(obj, obj_decoded)
1206 self.assertEqual(obj.expl_offset, offset)
1210 def test_go_vectors_valid(self):
1211 for data, expect in ((
1215 (b"\xff\x7f", -129),
1219 (b"\xff\x00", -256),
1223 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1224 (b"\x80\x00\x00\x00", -2147483648),
1227 Integer().decode(b"".join((
1228 Integer.tag_default,
1229 len_encode(len(data)),
1235 def test_go_vectors_invalid(self):
1240 with self.assertRaises(DecodeError):
1241 Integer().decode(b"".join((
1242 Integer.tag_default,
1243 len_encode(len(data)),
1249 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1252 if draw(booleans()):
1253 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1255 integers(min_value=0, max_value=255),
1256 min_size=len(schema),
1257 max_size=len(schema),
1259 schema = list(zip(schema, bits))
1261 def _value(value_required):
1262 if not value_required and draw(booleans()):
1264 generation_choice = 0
1266 generation_choice = draw(sampled_from((1, 2, 3)))
1267 if generation_choice == 1 or draw(booleans()):
1268 return "'%s'B" % "".join(draw(lists(
1269 sampled_from(("0", "1")),
1270 max_size=len(schema),
1272 if generation_choice == 2 or draw(booleans()):
1273 return draw(binary(max_size=len(schema) // 8))
1274 if generation_choice == 3 or draw(booleans()):
1275 if len(schema) == 0:
1277 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1279 value = _value(value_required)
1280 default = _value(value_required=False)
1284 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1286 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1287 optional = draw(one_of(none(), booleans()))
1289 draw(integers(min_value=0)),
1290 draw(integers(min_value=0)),
1291 draw(integers(min_value=0)),
1293 return (schema, value, impl, expl, default, optional, _decoded)
1296 class BitStringInherited(BitString):
1300 class TestBitString(CommonMixin, TestCase):
1301 base_klass = BitString
1303 @given(lists(booleans()))
1304 def test_b_encoding(self, bits):
1305 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1306 self.assertEqual(obj.bit_len, len(bits))
1307 self.assertSequenceEqual(list(obj), bits)
1308 for i, bit in enumerate(bits):
1309 self.assertEqual(obj[i], bit)
1311 @given(lists(booleans()))
1312 def test_out_of_bounds_bits(self, bits):
1313 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1314 for i in range(len(bits), len(bits) * 2):
1315 self.assertFalse(obj[i])
1317 def test_bad_b_encoding(self):
1318 with self.assertRaises(ValueError):
1319 BitString("'010120101'B")
1322 integers(min_value=1, max_value=255),
1323 integers(min_value=1, max_value=255),
1325 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1326 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1327 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1328 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1330 class BS(BitString):
1331 schema = (("whatever", 0),)
1332 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1333 self.assertEqual(obj.bit_len, leading_zeros + 1)
1334 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1336 def test_zero_len(self):
1337 with self.assertRaises(NotEnoughData):
1338 BitString().decode(b"".join((
1339 BitString.tag_default,
1343 def test_invalid_value_type(self):
1344 with self.assertRaises(InvalidValueType) as err:
1347 with self.assertRaises(InvalidValueType) as err:
1351 def test_obj_unknown(self):
1352 with self.assertRaises(ObjUnknown) as err:
1353 BitString(b"whatever")["whenever"]
1356 def test_get_invalid_type(self):
1357 with self.assertRaises(InvalidValueType) as err:
1358 BitString(b"whatever")[(1, 2, 3)]
1361 @given(data_strategy())
1362 def test_unknown_name(self, d):
1363 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1364 missing = _schema.pop()
1366 class BS(BitString):
1367 schema = [(n, i) for i, n in enumerate(_schema)]
1368 with self.assertRaises(ObjUnknown) as err:
1373 def test_optional(self, optional):
1374 obj = BitString(default=BitString(b""), optional=optional)
1375 self.assertTrue(obj.optional)
1378 def test_ready(self, value):
1380 self.assertFalse(obj.ready)
1383 pprint(obj, big_blobs=True, with_decode_path=True)
1384 with self.assertRaises(ObjNotReady) as err:
1387 with self.assertRaises(ObjNotReady) as err:
1389 obj = BitString(value)
1390 self.assertTrue(obj.ready)
1393 pprint(obj, big_blobs=True, with_decode_path=True)
1396 tuples(integers(min_value=0), binary()),
1397 tuples(integers(min_value=0), binary()),
1401 def test_comparison(self, value1, value2, tag1, tag2):
1402 for klass in (BitString, BitStringInherited):
1403 obj1 = klass(value1)
1404 obj2 = klass(value2)
1405 self.assertEqual(obj1 == obj2, value1 == value2)
1406 self.assertEqual(obj1 != obj2, value1 != value2)
1407 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1408 obj1 = klass(value1, impl=tag1)
1409 obj2 = klass(value1, impl=tag2)
1410 self.assertEqual(obj1 == obj2, tag1 == tag2)
1411 self.assertEqual(obj1 != obj2, tag1 != tag2)
1413 @given(data_strategy())
1414 def test_call(self, d):
1415 for klass in (BitString, BitStringInherited):
1424 ) = d.draw(bit_string_values_strategy())
1427 schema = schema_initial
1429 value=value_initial,
1432 default=default_initial,
1433 optional=optional_initial or False,
1434 _decoded=_decoded_initial,
1444 ) = d.draw(bit_string_values_strategy(
1445 schema=schema_initial,
1446 do_expl=impl_initial is None,
1455 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1456 self.assertEqual(obj.expl_tag, expl or expl_initial)
1457 if obj.default is None:
1458 optional = optional_initial if optional is None else optional
1459 optional = False if optional is None else optional
1462 self.assertEqual(obj.optional, optional)
1463 self.assertEqual(obj.specs, obj_initial.specs)
1465 @given(bit_string_values_strategy())
1466 def test_copy(self, values):
1467 for klass in (BitString, BitStringInherited):
1468 _schema, value, impl, expl, default, optional, _decoded = values
1478 optional=optional or False,
1481 for copy_func in copy_funcs:
1482 obj_copied = copy_func(obj)
1483 self.assert_copied_basic_fields(obj, obj_copied)
1484 self.assertEqual(obj.specs, obj_copied.specs)
1485 self.assertEqual(obj._value, obj_copied._value)
1489 integers(min_value=1).map(tag_encode),
1491 def test_stripped(self, value, tag_impl):
1492 obj = BitString(value, impl=tag_impl)
1493 with self.assertRaises(NotEnoughData):
1494 obj.decode(obj.encode()[:-1])
1498 integers(min_value=1).map(tag_ctxc),
1500 def test_stripped_expl(self, value, tag_expl):
1501 obj = BitString(value, expl=tag_expl)
1502 with self.assertRaises(NotEnoughData):
1503 obj.decode(obj.encode()[:-1])
1506 integers(min_value=31),
1507 integers(min_value=0),
1510 def test_bad_tag(self, tag, offset, decode_path):
1511 with self.assertRaises(DecodeError) as err:
1513 tag_encode(tag)[:-1],
1515 decode_path=decode_path,
1518 self.assertEqual(err.exception.offset, offset)
1519 self.assertEqual(err.exception.decode_path, decode_path)
1522 integers(min_value=128),
1523 integers(min_value=0),
1526 def test_bad_len(self, l, offset, decode_path):
1527 with self.assertRaises(DecodeError) as err:
1529 BitString.tag_default + len_encode(l)[:-1],
1531 decode_path=decode_path,
1534 self.assertEqual(err.exception.offset, offset)
1535 self.assertEqual(err.exception.decode_path, decode_path)
1537 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1538 @given(data_strategy())
1539 def test_symmetric(self, d):
1548 ) = d.draw(bit_string_values_strategy(value_required=True))
1549 tail_junk = d.draw(binary(max_size=5))
1550 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1551 offset = d.draw(integers(min_value=0))
1552 decode_path = d.draw(decode_path_strat)
1553 for klass in (BitString, BitStringInherited):
1564 pprint(obj, big_blobs=True, with_decode_path=True)
1565 self.assertFalse(obj.expled)
1566 obj_encoded = obj.encode()
1567 self.assertEqual(encode2pass(obj), obj_encoded)
1568 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1569 obj_expled = obj(value, expl=tag_expl)
1570 self.assertTrue(obj_expled.expled)
1572 list(obj_expled.pps())
1573 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1574 obj_expled_encoded = obj_expled.encode()
1575 obj_expled_cer = encode_cer(obj_expled)
1576 self.assertNotEqual(obj_expled_cer, obj_encoded)
1577 self.assertSequenceEqual(
1578 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1581 ctx_copied = deepcopy(ctx_dummy)
1582 obj_decoded, tail = obj_expled.decode(
1583 obj_expled_encoded + tail_junk,
1587 self.assertDictEqual(ctx_copied, ctx_dummy)
1589 list(obj_decoded.pps())
1590 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1591 self.assertEqual(tail, tail_junk)
1592 self.assertEqual(obj_decoded, obj_expled)
1593 self.assertNotEqual(obj_decoded, obj)
1594 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1595 self.assertEqual(bytes(obj_decoded), bytes(obj))
1596 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1597 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1598 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1600 obj_decoded.expl_llen,
1601 len(len_encode(len(obj_encoded))),
1603 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1604 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1607 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1609 self.assertEqual(obj_decoded.expl_offset, offset)
1610 if isinstance(value, tuple):
1611 self.assertSetEqual(set(value), set(obj_decoded.named))
1614 assert_exceeding_data(
1616 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1620 evgens = list(obj_expled.decode_evgen(
1621 obj_expled_encoded + tail_junk,
1623 decode_path=decode_path,
1626 self.assertEqual(len(evgens), 1)
1627 _decode_path, obj, tail = evgens[0]
1628 self.assertSequenceEqual(tail, tail_junk)
1629 self.assertEqual(_decode_path, decode_path)
1630 self.assertEqual(obj.expl_offset, offset)
1634 @given(integers(min_value=1, max_value=255))
1635 def test_bad_zero_value(self, pad_size):
1636 with self.assertRaises(DecodeError):
1637 BitString().decode(b"".join((
1638 BitString.tag_default,
1643 def test_go_vectors_invalid(self):
1649 with self.assertRaises(DecodeError):
1650 BitString().decode(b"".join((
1651 BitString.tag_default,
1656 def test_go_vectors_valid(self):
1657 obj, _ = BitString().decode(b"".join((
1658 BitString.tag_default,
1662 self.assertEqual(bytes(obj), b"")
1663 self.assertEqual(obj.bit_len, 0)
1665 obj, _ = BitString().decode(b"".join((
1666 BitString.tag_default,
1670 self.assertEqual(bytes(obj), b"\x00")
1671 self.assertEqual(obj.bit_len, 1)
1673 obj = BitString((16, b"\x82\x40"))
1674 self.assertTrue(obj[0])
1675 self.assertFalse(obj[1])
1676 self.assertTrue(obj[6])
1677 self.assertTrue(obj[9])
1678 self.assertFalse(obj[17])
1680 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1682 integers(min_value=1, max_value=30),
1685 binary(min_size=1, max_size=5),
1687 binary(min_size=1, max_size=5),
1695 lists(booleans(), min_size=1),
1699 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk, decode_path):
1700 def chunk_constructed(contents):
1702 tag_encode(form=TagFormConstructed, num=3) +
1704 b"".join(BitString(content).encode() for content in contents) +
1708 chunks_len_expected = []
1709 payload_expected = b""
1710 bit_len_expected = 0
1711 for chunk_input in chunk_inputs:
1712 if isinstance(chunk_input, bytes):
1713 chunks.append(BitString(chunk_input).encode())
1714 payload_expected += chunk_input
1715 bit_len_expected += len(chunk_input) * 8
1716 chunks_len_expected.append(len(chunk_input) + 1)
1718 chunks.append(chunk_constructed(chunk_input))
1719 payload = b"".join(chunk_input)
1720 payload_expected += payload
1721 bit_len_expected += len(payload) * 8
1722 for c in chunk_input:
1723 chunks_len_expected.append(len(c) + 1)
1724 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
1725 chunk_last = BitString("'%s'B" % "".join(
1726 "1" if bit else "0" for bit in chunk_last_bits
1728 chunks_len_expected.append(BitString().decod(chunk_last.encode()).vlen)
1729 payload_expected += bytes(chunk_last)
1730 bit_len_expected += chunk_last.bit_len
1731 encoded_indefinite = (
1732 tag_encode(form=TagFormConstructed, num=impl) +
1735 chunk_last.encode() +
1738 encoded_definite = (
1739 tag_encode(form=TagFormConstructed, num=impl) +
1740 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1744 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
1745 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1746 for lenindef_expected, encoded in (
1747 (True, encoded_indefinite),
1748 (False, encoded_definite),
1750 obj, tail = BitString(impl=tag_encode(impl)).decode(
1752 ctx={"bered": True},
1754 self.assertSequenceEqual(tail, junk)
1755 self.assertEqual(obj.bit_len, bit_len_expected)
1756 self.assertSequenceEqual(bytes(obj), payload_expected)
1757 self.assertTrue(obj.ber_encoded)
1758 self.assertEqual(obj.lenindef, lenindef_expected)
1759 self.assertTrue(obj.bered)
1761 self.assertTrue(obj.ber_encoded)
1762 self.assertEqual(obj.lenindef, lenindef_expected)
1763 self.assertTrue(obj.bered)
1764 self.assertEqual(len(encoded), obj.tlvlen)
1767 pprint(obj, big_blobs=True, with_decode_path=True)
1769 evgens = list(BitString(impl=tag_encode(impl)).decode_evgen(
1771 decode_path=decode_path,
1772 ctx={"bered": True},
1774 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
1775 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
1776 self.assertGreater(len(dp), len(decode_path))
1777 self.assertEqual(obj.vlen, chunk_len_expected)
1780 integers(min_value=0),
1783 def test_ber_definite_too_short(self, offset, decode_path):
1784 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
1786 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1788 decode_path=decode_path,
1789 ctx={"bered": True},
1791 self.assertEqual(err.exception.decode_path, decode_path)
1792 self.assertEqual(err.exception.offset, offset)
1795 integers(min_value=0),
1798 def test_ber_definite_no_data(self, offset, decode_path):
1799 with self.assertRaisesRegex(DecodeError, "zero length") as err:
1801 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1803 decode_path=decode_path,
1804 ctx={"bered": True},
1806 self.assertEqual(err.exception.decode_path, decode_path)
1807 self.assertEqual(err.exception.offset, offset)
1810 integers(min_value=0),
1812 integers(min_value=1, max_value=3),
1814 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1815 bs = BitString(b"data").encode()
1816 with self.assertRaises(NotEnoughData) as err:
1818 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1820 decode_path=decode_path,
1821 ctx={"bered": True},
1823 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1824 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1827 integers(min_value=0),
1829 integers(min_value=1, max_value=3),
1831 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1832 bs = BitString(b"data").encode()
1833 bs_longer = BitString(b"data-longer").encode()
1834 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
1837 tag_encode(3, form=TagFormConstructed) +
1838 len_encode((chunks + 1) * len(bs)) +
1843 decode_path=decode_path,
1844 ctx={"bered": True},
1846 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1847 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1850 integers(min_value=0),
1853 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1854 with self.assertRaisesRegex(DecodeError, "no chunks") as err:
1856 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1858 decode_path=decode_path,
1859 ctx={"bered": True},
1861 self.assertEqual(err.exception.decode_path, decode_path)
1862 self.assertEqual(err.exception.offset, offset)
1864 @given(data_strategy())
1865 def test_ber_indefinite_not_multiple(self, d):
1866 bs_short = BitString("'A'H").encode()
1867 bs_full = BitString("'AA'H").encode()
1868 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1869 chunks.append(bs_short)
1870 d.draw(permutations(chunks))
1871 chunks.append(bs_short)
1872 offset = d.draw(integers(min_value=0))
1873 decode_path = d.draw(decode_path_strat)
1874 with self.assertRaisesRegex(DecodeError, "multiple of 8 bits") as err:
1877 tag_encode(3, form=TagFormConstructed) +
1883 decode_path=decode_path,
1884 ctx={"bered": True},
1887 err.exception.decode_path,
1888 decode_path + (str(chunks.index(bs_short)),),
1891 err.exception.offset,
1892 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1895 def test_x690_vector(self):
1896 vector = BitString("'0A3B5F291CD'H")
1897 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1898 self.assertSequenceEqual(tail, b"")
1899 self.assertEqual(obj, vector)
1900 obj, tail = BitString().decode(
1901 hexdec("23800303000A3B0305045F291CD00000"),
1902 ctx={"bered": True},
1904 self.assertSequenceEqual(tail, b"")
1905 self.assertEqual(obj, vector)
1906 self.assertTrue(obj.ber_encoded)
1907 self.assertTrue(obj.lenindef)
1908 self.assertTrue(obj.bered)
1910 self.assertTrue(obj.ber_encoded)
1911 self.assertTrue(obj.lenindef)
1912 self.assertTrue(obj.bered)
1914 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1915 @given(integers(min_value=1000, max_value=3000))
1916 def test_cer(self, data_len):
1917 data = urandom(data_len)
1918 encoded = encode_cer(BitString(data))
1919 ctx = {"bered": True}
1920 self.assertSequenceEqual(bytes(BitString().decod(encoded, ctx=ctx)), data)
1921 evgens = list(BitString().decode_evgen(encoded, ctx=ctx))
1922 evgens_expected = data_len // 999
1923 if evgens_expected * 999 != data_len:
1924 evgens_expected += 1
1925 evgens_expected += 1
1926 self.assertEqual(len(evgens), evgens_expected)
1927 for (_, obj, _) in evgens[:-2]:
1928 self.assertEqual(obj.vlen, 1000)
1929 _, obj, _ = evgens[-2]
1930 self.assertEqual(obj.vlen, 1 + data_len - len(evgens[:-2]) * 999)
1934 def octet_string_values_strategy(draw, do_expl=False):
1935 bound_min, bound_max = sorted(draw(sets(
1936 integers(min_value=0, max_value=1 << 7),
1940 value = draw(one_of(
1942 binary(min_size=bound_min, max_size=bound_max),
1944 default = draw(one_of(
1946 binary(min_size=bound_min, max_size=bound_max),
1949 if draw(booleans()):
1950 bounds = (bound_min, bound_max)
1954 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1956 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1957 optional = draw(one_of(none(), booleans()))
1959 draw(integers(min_value=0)),
1960 draw(integers(min_value=0)),
1961 draw(integers(min_value=0)),
1963 return (value, bounds, impl, expl, default, optional, _decoded)
1966 class OctetStringInherited(OctetString):
1970 class TestOctetString(CommonMixin, TestCase):
1971 base_klass = OctetString
1973 def test_invalid_value_type(self):
1974 with self.assertRaises(InvalidValueType) as err:
1975 OctetString(str(123))
1979 def test_optional(self, optional):
1980 obj = OctetString(default=OctetString(b""), optional=optional)
1981 self.assertTrue(obj.optional)
1984 def test_ready(self, value):
1986 self.assertFalse(obj.ready)
1989 pprint(obj, big_blobs=True, with_decode_path=True)
1990 with self.assertRaises(ObjNotReady) as err:
1993 with self.assertRaises(ObjNotReady) as err:
1995 obj = OctetString(value)
1996 self.assertTrue(obj.ready)
1999 pprint(obj, big_blobs=True, with_decode_path=True)
2001 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
2002 def test_comparison(self, value1, value2, tag1, tag2):
2003 for klass in (OctetString, OctetStringInherited):
2004 obj1 = klass(value1)
2005 obj2 = klass(value2)
2006 self.assertEqual(obj1 == obj2, value1 == value2)
2007 self.assertEqual(obj1 != obj2, value1 != value2)
2008 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2009 obj1 = klass(value1, impl=tag1)
2010 obj2 = klass(value1, impl=tag2)
2011 self.assertEqual(obj1 == obj2, tag1 == tag2)
2012 self.assertEqual(obj1 != obj2, tag1 != tag2)
2014 @given(lists(binary()))
2015 def test_sorted_works(self, values):
2016 self.assertSequenceEqual(
2017 [bytes(v) for v in sorted(OctetString(v) for v in values)],
2021 @given(data_strategy())
2022 def test_bounds_satisfied(self, d):
2023 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2024 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2025 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
2026 OctetString(value=value, bounds=(bound_min, bound_max))
2028 @given(data_strategy())
2029 def test_bounds_unsatisfied(self, d):
2030 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2031 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2032 value = d.draw(binary(max_size=bound_min - 1))
2033 with self.assertRaises(BoundsError) as err:
2034 OctetString(value=value, bounds=(bound_min, bound_max))
2036 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2037 OctetString(bounds=(bound_min, bound_max)).decode(
2038 OctetString(value).encode()
2041 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2042 OctetString(bounds=(bound_min, bound_max)).decode(
2043 encode2pass(OctetString(value))
2045 value = d.draw(binary(min_size=bound_max + 1))
2046 with self.assertRaises(BoundsError) as err:
2047 OctetString(value=value, bounds=(bound_min, bound_max))
2049 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2050 OctetString(bounds=(bound_min, bound_max)).decode(
2051 OctetString(value).encode()
2054 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2055 OctetString(bounds=(bound_min, bound_max)).decode(
2056 encode2pass(OctetString(value))
2059 @given(data_strategy())
2060 def test_call(self, d):
2061 for klass in (OctetString, OctetStringInherited):
2070 ) = d.draw(octet_string_values_strategy())
2071 obj_initial = klass(
2077 optional_initial or False,
2088 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
2089 if (default is None) and (obj_initial.default is not None):
2092 (bounds is None) and
2093 (value is not None) and
2094 (bounds_initial is not None) and
2095 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2099 (bounds is None) and
2100 (default is not None) and
2101 (bounds_initial is not None) and
2102 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2105 obj = obj_initial(value, bounds, impl, expl, default, optional)
2107 value_expected = default if value is None else value
2109 default_initial if value_expected is None
2112 self.assertEqual(obj, value_expected)
2113 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2114 self.assertEqual(obj.expl_tag, expl or expl_initial)
2117 default_initial if default is None else default,
2119 if obj.default is None:
2120 optional = optional_initial if optional is None else optional
2121 optional = False if optional is None else optional
2124 self.assertEqual(obj.optional, optional)
2126 (obj._bound_min, obj._bound_max),
2127 bounds or bounds_initial or (0, float("+inf")),
2130 @given(octet_string_values_strategy())
2131 def test_copy(self, values):
2132 for klass in (OctetString, OctetStringInherited):
2133 obj = klass(*values)
2134 for copy_func in copy_funcs:
2135 obj_copied = copy_func(obj)
2136 self.assert_copied_basic_fields(obj, obj_copied)
2137 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2138 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2139 self.assertEqual(obj._value, obj_copied._value)
2143 integers(min_value=1).map(tag_encode),
2145 def test_stripped(self, value, tag_impl):
2146 obj = OctetString(value, impl=tag_impl)
2147 with self.assertRaises(NotEnoughData):
2148 obj.decode(obj.encode()[:-1])
2152 integers(min_value=1).map(tag_ctxc),
2154 def test_stripped_expl(self, value, tag_expl):
2155 obj = OctetString(value, expl=tag_expl)
2156 with self.assertRaises(NotEnoughData):
2157 obj.decode(obj.encode()[:-1])
2160 integers(min_value=31),
2161 integers(min_value=0),
2164 def test_bad_tag(self, tag, offset, decode_path):
2165 with self.assertRaises(DecodeError) as err:
2166 OctetString().decode(
2167 tag_encode(tag)[:-1],
2169 decode_path=decode_path,
2172 self.assertEqual(err.exception.offset, offset)
2173 self.assertEqual(err.exception.decode_path, decode_path)
2176 integers(min_value=128),
2177 integers(min_value=0),
2180 def test_bad_len(self, l, offset, decode_path):
2181 with self.assertRaises(DecodeError) as err:
2182 OctetString().decode(
2183 OctetString.tag_default + len_encode(l)[:-1],
2185 decode_path=decode_path,
2188 self.assertEqual(err.exception.offset, offset)
2189 self.assertEqual(err.exception.decode_path, decode_path)
2192 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2193 integers(min_value=0),
2196 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2197 value, bound_min = list(sorted(ints))
2199 class String(OctetString):
2200 bounds = (bound_min, bound_min)
2201 with self.assertRaises(DecodeError) as err:
2203 OctetString(b"\x00" * value).encode(),
2205 decode_path=decode_path,
2208 self.assertEqual(err.exception.offset, offset)
2209 self.assertEqual(err.exception.decode_path, decode_path)
2211 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2213 octet_string_values_strategy(),
2215 integers(min_value=1).map(tag_ctxc),
2216 integers(min_value=0),
2220 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2221 for klass in (OctetString, OctetStringInherited):
2222 _, _, _, _, default, optional, _decoded = values
2231 pprint(obj, big_blobs=True, with_decode_path=True)
2232 self.assertFalse(obj.expled)
2233 obj_encoded = obj.encode()
2234 self.assertEqual(encode2pass(obj), obj_encoded)
2235 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2236 obj_expled = obj(value, expl=tag_expl)
2237 self.assertTrue(obj_expled.expled)
2239 list(obj_expled.pps())
2240 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2241 obj_expled_encoded = obj_expled.encode()
2242 obj_expled_cer = encode_cer(obj_expled)
2243 self.assertNotEqual(obj_expled_cer, obj_encoded)
2244 self.assertSequenceEqual(
2245 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2248 ctx_copied = deepcopy(ctx_dummy)
2249 obj_decoded, tail = obj_expled.decode(
2250 obj_expled_encoded + tail_junk,
2254 self.assertDictEqual(ctx_copied, ctx_dummy)
2256 list(obj_decoded.pps())
2257 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2258 self.assertEqual(tail, tail_junk)
2259 self.assertEqual(obj_decoded, obj_expled)
2260 self.assertNotEqual(obj_decoded, obj)
2261 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2262 self.assertEqual(bytes(obj_decoded), bytes(obj))
2263 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2264 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2265 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2267 obj_decoded.expl_llen,
2268 len(len_encode(len(obj_encoded))),
2270 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2271 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2274 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2276 self.assertEqual(obj_decoded.expl_offset, offset)
2277 assert_exceeding_data(
2279 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2283 evgens = list(obj_expled.decode_evgen(
2284 obj_expled_encoded + tail_junk,
2286 decode_path=decode_path,
2289 self.assertEqual(len(evgens), 1)
2290 _decode_path, obj, tail = evgens[0]
2291 self.assertSequenceEqual(tail, tail_junk)
2292 self.assertEqual(_decode_path, decode_path)
2293 self.assertEqual(obj.expl_offset, offset)
2297 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2299 integers(min_value=1, max_value=30),
2302 binary(min_size=1, max_size=5),
2304 binary(min_size=1, max_size=5),
2315 def test_constructed(self, impl, chunk_inputs, junk, decode_path):
2316 def chunk_constructed(contents):
2318 tag_encode(form=TagFormConstructed, num=4) +
2320 b"".join(OctetString(content).encode() for content in contents) +
2324 chunks_len_expected = []
2325 payload_expected = b""
2326 for chunk_input in chunk_inputs:
2327 if isinstance(chunk_input, bytes):
2328 chunks.append(OctetString(chunk_input).encode())
2329 payload_expected += chunk_input
2330 chunks_len_expected.append(len(chunk_input))
2332 chunks.append(chunk_constructed(chunk_input))
2333 payload = b"".join(chunk_input)
2334 payload_expected += payload
2335 for c in chunk_input:
2336 chunks_len_expected.append(len(c))
2337 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
2338 encoded_indefinite = (
2339 tag_encode(form=TagFormConstructed, num=impl) +
2344 encoded_definite = (
2345 tag_encode(form=TagFormConstructed, num=impl) +
2346 len_encode(len(b"".join(chunks))) +
2349 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
2350 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2351 for lenindef_expected, encoded in (
2352 (True, encoded_indefinite),
2353 (False, encoded_definite),
2355 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2357 ctx={"bered": True},
2359 self.assertSequenceEqual(tail, junk)
2360 self.assertSequenceEqual(bytes(obj), payload_expected)
2361 self.assertTrue(obj.ber_encoded)
2362 self.assertEqual(obj.lenindef, lenindef_expected)
2363 self.assertTrue(obj.bered)
2365 self.assertTrue(obj.ber_encoded)
2366 self.assertEqual(obj.lenindef, lenindef_expected)
2367 self.assertTrue(obj.bered)
2368 self.assertEqual(len(encoded), obj.tlvlen)
2371 pprint(obj, big_blobs=True, with_decode_path=True)
2373 evgens = list(OctetString(impl=tag_encode(impl)).decode_evgen(
2375 decode_path=decode_path,
2376 ctx={"bered": True},
2378 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
2379 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
2380 self.assertGreater(len(dp), len(decode_path))
2381 self.assertEqual(obj.vlen, chunk_len_expected)
2384 integers(min_value=0),
2387 def test_ber_definite_too_short(self, offset, decode_path):
2388 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
2389 OctetString().decode(
2390 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2392 decode_path=decode_path,
2393 ctx={"bered": True},
2395 self.assertEqual(err.exception.decode_path, decode_path)
2396 self.assertEqual(err.exception.offset, offset)
2399 integers(min_value=0),
2401 integers(min_value=1, max_value=3),
2403 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2404 bs = OctetString(b"data").encode()
2405 with self.assertRaises(NotEnoughData) as err:
2406 OctetString().decode(
2407 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2409 decode_path=decode_path,
2410 ctx={"bered": True},
2412 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2413 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2416 integers(min_value=0),
2418 integers(min_value=1, max_value=3),
2420 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2421 bs = OctetString(b"data").encode()
2422 bs_longer = OctetString(b"data-longer").encode()
2423 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
2424 OctetString().decode(
2426 tag_encode(4, form=TagFormConstructed) +
2427 len_encode((chunks + 1) * len(bs)) +
2432 decode_path=decode_path,
2433 ctx={"bered": True},
2435 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2436 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2438 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2439 @given(integers(min_value=1001, max_value=3000))
2440 def test_cer(self, data_len):
2441 data = urandom(data_len)
2442 encoded = encode_cer(OctetString(data))
2443 ctx = {"bered": True}
2444 self.assertSequenceEqual(bytes(OctetString().decod(encoded, ctx=ctx)), data)
2445 evgens = list(OctetString().decode_evgen(encoded, ctx=ctx))
2446 evgens_expected = data_len // 1000
2447 if evgens_expected * 1000 != data_len:
2448 evgens_expected += 1
2449 evgens_expected += 1
2450 self.assertEqual(len(evgens), evgens_expected)
2451 for (_, obj, _) in evgens[:-2]:
2452 self.assertEqual(obj.vlen, 1000)
2453 _, obj, _ = evgens[-2]
2454 self.assertEqual(obj.vlen, data_len - len(evgens[:-2]) * 1000)
2458 def null_values_strategy(draw, do_expl=False):
2462 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2464 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2465 optional = draw(one_of(none(), booleans()))
2467 draw(integers(min_value=0)),
2468 draw(integers(min_value=0)),
2469 draw(integers(min_value=0)),
2471 return (impl, expl, optional, _decoded)
2474 class NullInherited(Null):
2478 class TestNull(CommonMixin, TestCase):
2481 def test_ready(self):
2483 self.assertTrue(obj.ready)
2486 pprint(obj, big_blobs=True, with_decode_path=True)
2488 @given(binary(min_size=1), binary(min_size=1))
2489 def test_comparison(self, tag1, tag2):
2490 for klass in (Null, NullInherited):
2491 obj1 = klass(impl=tag1)
2492 obj2 = klass(impl=tag2)
2493 self.assertEqual(obj1 == obj2, tag1 == tag2)
2494 self.assertEqual(obj1 != obj2, tag1 != tag2)
2495 self.assertNotEqual(obj1, tag2)
2497 @given(data_strategy())
2498 def test_call(self, d):
2499 for klass in (Null, NullInherited):
2505 ) = d.draw(null_values_strategy())
2506 obj_initial = klass(
2509 optional=optional_initial or False,
2510 _decoded=_decoded_initial,
2517 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2518 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2519 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2520 self.assertEqual(obj.expl_tag, expl or expl_initial)
2521 optional = optional_initial if optional is None else optional
2522 optional = False if optional is None else optional
2523 self.assertEqual(obj.optional, optional)
2525 @given(null_values_strategy())
2526 def test_copy(self, values):
2527 for klass in (Null, NullInherited):
2528 impl, expl, optional, _decoded = values
2532 optional=optional or False,
2535 for copy_func in copy_funcs:
2536 obj_copied = copy_func(obj)
2537 self.assert_copied_basic_fields(obj, obj_copied)
2539 @given(integers(min_value=1).map(tag_encode))
2540 def test_stripped(self, tag_impl):
2541 obj = Null(impl=tag_impl)
2542 with self.assertRaises(NotEnoughData):
2543 obj.decode(obj.encode()[:-1])
2545 @given(integers(min_value=1).map(tag_ctxc))
2546 def test_stripped_expl(self, tag_expl):
2547 obj = Null(expl=tag_expl)
2548 with self.assertRaises(NotEnoughData):
2549 obj.decode(obj.encode()[:-1])
2552 integers(min_value=31),
2553 integers(min_value=0),
2556 def test_bad_tag(self, tag, offset, decode_path):
2557 with self.assertRaises(DecodeError) as err:
2559 tag_encode(tag)[:-1],
2561 decode_path=decode_path,
2564 self.assertEqual(err.exception.offset, offset)
2565 self.assertEqual(err.exception.decode_path, decode_path)
2568 integers(min_value=128),
2569 integers(min_value=0),
2572 def test_bad_len(self, l, offset, decode_path):
2573 with self.assertRaises(DecodeError) as err:
2575 Null.tag_default + len_encode(l)[:-1],
2577 decode_path=decode_path,
2580 self.assertEqual(err.exception.offset, offset)
2581 self.assertEqual(err.exception.decode_path, decode_path)
2583 @given(binary(min_size=1))
2584 def test_tag_mismatch(self, impl):
2585 assume(impl != Null.tag_default)
2586 with self.assertRaises(TagMismatch):
2587 Null(impl=impl).decode(Null().encode())
2590 null_values_strategy(),
2591 integers(min_value=1).map(tag_ctxc),
2592 integers(min_value=0),
2596 def test_symmetric(self, values, tag_expl, offset, tail_junk, decode_path):
2597 for klass in (Null, NullInherited):
2598 _, _, optional, _decoded = values
2599 obj = klass(optional=optional, _decoded=_decoded)
2602 pprint(obj, big_blobs=True, with_decode_path=True)
2603 self.assertFalse(obj.expled)
2604 obj_encoded = obj.encode()
2605 self.assertEqual(encode2pass(obj), obj_encoded)
2606 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2607 obj_expled = obj(expl=tag_expl)
2608 self.assertTrue(obj_expled.expled)
2610 list(obj_expled.pps())
2611 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2612 obj_expled_encoded = obj_expled.encode()
2613 obj_expled_cer = encode_cer(obj_expled)
2614 self.assertNotEqual(obj_expled_cer, obj_encoded)
2615 self.assertSequenceEqual(
2616 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2619 ctx_copied = deepcopy(ctx_dummy)
2620 obj_decoded, tail = obj_expled.decode(
2621 obj_expled_encoded + tail_junk,
2625 self.assertDictEqual(ctx_copied, ctx_dummy)
2627 list(obj_decoded.pps())
2628 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2629 self.assertEqual(tail, tail_junk)
2630 self.assertEqual(obj_decoded, obj_expled)
2631 self.assertNotEqual(obj_decoded, obj)
2632 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2633 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2634 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2636 obj_decoded.expl_llen,
2637 len(len_encode(len(obj_encoded))),
2639 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2640 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2643 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2645 self.assertEqual(obj_decoded.expl_offset, offset)
2646 assert_exceeding_data(
2648 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2652 evgens = list(obj_expled.decode_evgen(
2653 obj_expled_encoded + tail_junk,
2655 decode_path=decode_path,
2658 self.assertEqual(len(evgens), 1)
2659 _decode_path, obj, tail = evgens[0]
2660 self.assertSequenceEqual(tail, tail_junk)
2661 self.assertEqual(_decode_path, decode_path)
2662 self.assertEqual(obj, obj_decoded)
2663 self.assertEqual(obj.expl_offset, offset)
2667 @given(integers(min_value=1))
2668 def test_invalid_len(self, l):
2669 with self.assertRaises(InvalidLength):
2670 Null().decode(b"".join((
2677 def oid_strategy(draw):
2678 first_arc = draw(integers(min_value=0, max_value=2))
2680 if first_arc in (0, 1):
2681 second_arc = draw(integers(min_value=0, max_value=39))
2683 second_arc = draw(integers(min_value=0, max_value=1 << 63))
2684 other_arcs = draw(lists(integers(min_value=0, max_value=1 << 63)))
2685 return tuple([first_arc, second_arc] + other_arcs)
2689 def oid_values_strategy(draw, do_expl=False):
2690 value = draw(one_of(none(), oid_strategy()))
2694 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2696 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2697 default = draw(one_of(none(), oid_strategy()))
2698 optional = draw(one_of(none(), booleans()))
2700 draw(integers(min_value=0)),
2701 draw(integers(min_value=0)),
2702 draw(integers(min_value=0)),
2704 return (value, impl, expl, default, optional, _decoded)
2707 class ObjectIdentifierInherited(ObjectIdentifier):
2711 class TestObjectIdentifier(CommonMixin, TestCase):
2712 base_klass = ObjectIdentifier
2714 def test_invalid_value_type(self):
2715 with self.assertRaises(InvalidValueType) as err:
2716 ObjectIdentifier(123)
2720 def test_optional(self, optional):
2721 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2722 self.assertTrue(obj.optional)
2724 @given(oid_strategy())
2725 def test_ready(self, value):
2726 obj = ObjectIdentifier()
2727 self.assertFalse(obj.ready)
2730 pprint(obj, big_blobs=True, with_decode_path=True)
2731 with self.assertRaises(ObjNotReady) as err:
2734 with self.assertRaises(ObjNotReady) as err:
2736 obj = ObjectIdentifier(value)
2737 self.assertTrue(obj.ready)
2738 self.assertFalse(obj.ber_encoded)
2741 pprint(obj, big_blobs=True, with_decode_path=True)
2744 @given(oid_strategy(), oid_strategy(), binary(min_size=1), binary(min_size=1))
2745 def test_comparison(self, value1, value2, tag1, tag2):
2746 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2747 obj1 = klass(value1)
2748 obj2 = klass(value2)
2749 self.assertEqual(obj1 == obj2, value1 == value2)
2750 self.assertEqual(obj1 != obj2, value1 != value2)
2751 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2752 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2753 obj1 = klass(value1, impl=tag1)
2754 obj2 = klass(value1, impl=tag2)
2755 self.assertEqual(obj1 == obj2, tag1 == tag2)
2756 self.assertEqual(obj1 != obj2, tag1 != tag2)
2758 @given(lists(oid_strategy()))
2759 def test_sorted_works(self, values):
2760 self.assertSequenceEqual(
2761 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2765 @given(data_strategy())
2766 def test_call(self, d):
2767 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2775 ) = d.draw(oid_values_strategy())
2776 obj_initial = klass(
2777 value=value_initial,
2780 default=default_initial,
2781 optional=optional_initial or False,
2782 _decoded=_decoded_initial,
2791 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2800 value_expected = default if value is None else value
2802 default_initial if value_expected is None
2805 self.assertEqual(obj, value_expected)
2806 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2807 self.assertEqual(obj.expl_tag, expl or expl_initial)
2810 default_initial if default is None else default,
2812 if obj.default is None:
2813 optional = optional_initial if optional is None else optional
2814 optional = False if optional is None else optional
2817 self.assertEqual(obj.optional, optional)
2819 @given(oid_values_strategy())
2820 def test_copy(self, values):
2821 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2838 for copy_func in copy_funcs:
2839 obj_copied = copy_func(obj)
2840 self.assert_copied_basic_fields(obj, obj_copied)
2841 self.assertEqual(obj._value, obj_copied._value)
2843 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2846 integers(min_value=1).map(tag_encode),
2848 def test_stripped(self, value, tag_impl):
2849 obj = ObjectIdentifier(value, impl=tag_impl)
2850 with self.assertRaises(NotEnoughData):
2851 obj.decode(obj.encode()[:-1])
2855 integers(min_value=1).map(tag_ctxc),
2857 def test_stripped_expl(self, value, tag_expl):
2858 obj = ObjectIdentifier(value, expl=tag_expl)
2859 with self.assertRaises(NotEnoughData):
2860 obj.decode(obj.encode()[:-1])
2863 integers(min_value=31),
2864 integers(min_value=0),
2867 def test_bad_tag(self, tag, offset, decode_path):
2868 with self.assertRaises(DecodeError) as err:
2869 ObjectIdentifier().decode(
2870 tag_encode(tag)[:-1],
2872 decode_path=decode_path,
2875 self.assertEqual(err.exception.offset, offset)
2876 self.assertEqual(err.exception.decode_path, decode_path)
2879 integers(min_value=128),
2880 integers(min_value=0),
2883 def test_bad_len(self, l, offset, decode_path):
2884 with self.assertRaises(DecodeError) as err:
2885 ObjectIdentifier().decode(
2886 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2888 decode_path=decode_path,
2891 self.assertEqual(err.exception.offset, offset)
2892 self.assertEqual(err.exception.decode_path, decode_path)
2894 def test_zero_oid(self):
2895 with self.assertRaises(NotEnoughData):
2896 ObjectIdentifier().decode(
2897 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2900 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2901 @given(oid_strategy())
2902 def test_unfinished_oid(self, value):
2903 assume(list(value)[-1] > 255)
2904 obj_encoded = ObjectIdentifier(value).encode()
2905 obj, _ = ObjectIdentifier().decode(obj_encoded)
2906 data = obj_encoded[obj.tlen + obj.llen:-1]
2908 ObjectIdentifier.tag_default,
2909 len_encode(len(data)),
2912 with self.assertRaisesRegex(DecodeError, "unfinished OID"):
2915 @given(integers(min_value=0, max_value=1 << 63))
2916 def test_invalid_short(self, value):
2917 with self.assertRaises(InvalidOID):
2918 ObjectIdentifier((value,))
2919 with self.assertRaises(InvalidOID):
2920 ObjectIdentifier("%d" % value)
2923 integers(min_value=3, max_value=1 << 63),
2924 integers(min_value=0, max_value=1 << 63),
2926 def test_invalid_first_arc(self, first_arc, second_arc):
2927 with self.assertRaises(InvalidOID):
2928 ObjectIdentifier((first_arc, second_arc))
2929 with self.assertRaises(InvalidOID):
2930 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2933 integers(min_value=0, max_value=1),
2934 integers(min_value=40, max_value=1 << 63),
2936 def test_invalid_second_arc(self, first_arc, second_arc):
2937 with self.assertRaises(InvalidOID):
2938 ObjectIdentifier((first_arc, second_arc))
2939 with self.assertRaises(InvalidOID):
2940 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2942 @given(text(alphabet=ascii_letters + ".", min_size=1))
2943 def test_junk(self, oid):
2944 with self.assertRaises(InvalidOID):
2945 ObjectIdentifier(oid)
2947 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2948 @given(oid_strategy())
2949 def test_validness(self, oid):
2950 obj = ObjectIdentifier(oid)
2951 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2954 pprint(obj, big_blobs=True, with_decode_path=True)
2956 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2958 oid_values_strategy(),
2960 integers(min_value=1).map(tag_ctxc),
2961 integers(min_value=0),
2965 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2966 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2967 _, _, _, default, optional, _decoded = values
2976 pprint(obj, big_blobs=True, with_decode_path=True)
2977 self.assertFalse(obj.expled)
2978 obj_encoded = obj.encode()
2979 self.assertEqual(encode2pass(obj), obj_encoded)
2980 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2981 obj_expled = obj(value, expl=tag_expl)
2982 self.assertTrue(obj_expled.expled)
2984 list(obj_expled.pps())
2985 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2986 obj_expled_encoded = obj_expled.encode()
2987 obj_expled_cer = encode_cer(obj_expled)
2988 self.assertNotEqual(obj_expled_cer, obj_encoded)
2989 self.assertSequenceEqual(
2990 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2993 ctx_copied = deepcopy(ctx_dummy)
2994 obj_decoded, tail = obj_expled.decode(
2995 obj_expled_encoded + tail_junk,
2999 self.assertDictEqual(ctx_copied, ctx_dummy)
3001 list(obj_decoded.pps())
3002 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3003 self.assertEqual(tail, tail_junk)
3004 self.assertEqual(obj_decoded, obj_expled)
3005 self.assertNotEqual(obj_decoded, obj)
3006 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
3007 self.assertEqual(tuple(obj_decoded), tuple(obj))
3008 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3009 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3010 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3012 obj_decoded.expl_llen,
3013 len(len_encode(len(obj_encoded))),
3015 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3016 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3019 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3021 self.assertEqual(obj_decoded.expl_offset, offset)
3022 assert_exceeding_data(
3024 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3028 evgens = list(obj_expled.decode_evgen(
3029 obj_expled_encoded + tail_junk,
3031 decode_path=decode_path,
3034 self.assertEqual(len(evgens), 1)
3035 _decode_path, obj, tail = evgens[0]
3036 self.assertSequenceEqual(tail, tail_junk)
3037 self.assertEqual(_decode_path, decode_path)
3038 self.assertEqual(obj, obj_decoded)
3039 self.assertEqual(obj.expl_offset, offset)
3044 oid_strategy().map(ObjectIdentifier),
3045 oid_strategy().map(ObjectIdentifier),
3047 def test_add(self, oid1, oid2):
3048 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
3049 for oid_to_add in (oid2, tuple(oid2)):
3050 self.assertEqual(oid1 + oid_to_add, oid_expect)
3051 with self.assertRaises(InvalidValueType):
3054 def test_go_vectors_valid(self):
3055 for data, expect in (
3057 (b"\x55\x02", (2, 5, 2)),
3058 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
3059 (b"\x81\x34\x03", (2, 100, 3)),
3062 ObjectIdentifier().decode(b"".join((
3063 ObjectIdentifier.tag_default,
3064 len_encode(len(data)),
3070 def test_go_vectors_invalid(self):
3071 data = b"\x55\x02\xc0\x80\x80\x80\x80"
3072 with self.assertRaises(DecodeError):
3073 ObjectIdentifier().decode(b"".join((
3074 Integer.tag_default,
3075 len_encode(len(data)),
3079 def test_go_non_minimal_encoding(self):
3080 with self.assertRaises(DecodeError):
3081 ObjectIdentifier().decode(hexdec("060a2a80864886f70d01010b"))
3083 def test_x690_vector(self):
3085 ObjectIdentifier().decode(hexdec("0603883703"))[0],
3086 ObjectIdentifier((2, 999, 3)),
3089 def test_nonnormalized_first_arc(self):
3091 ObjectIdentifier.tag_default +
3094 ObjectIdentifier((1, 0)).encode()[-1:]
3096 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3097 self.assertTrue(obj.ber_encoded)
3098 self.assertTrue(obj.bered)
3100 self.assertTrue(obj.ber_encoded)
3101 self.assertTrue(obj.bered)
3102 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3103 ObjectIdentifier().decode(tampered)
3105 @given(data_strategy())
3106 def test_negative_arcs(self, d):
3107 oid = list(d.draw(oid_strategy()))
3110 idx = d.draw(integers(min_value=3, max_value=len(oid)))
3112 if oid[idx - 1] == 0:
3114 with self.assertRaises(InvalidOID):
3115 ObjectIdentifier(tuple(oid))
3116 with self.assertRaises(InvalidOID):
3117 ObjectIdentifier(".".join(str(i) for i in oid))
3119 @given(data_strategy())
3120 def test_plused_arcs(self, d):
3121 oid = [str(arc) for arc in d.draw(oid_strategy())]
3122 idx = d.draw(integers(min_value=0, max_value=len(oid)))
3123 oid[idx - 1] = "+" + oid[idx - 1]
3124 with self.assertRaises(InvalidOID):
3125 ObjectIdentifier(".".join(str(i) for i in oid))
3127 @given(data_strategy())
3128 def test_nonnormalized_arcs(self, d):
3129 arcs = d.draw(lists(
3130 integers(min_value=0, max_value=100),
3134 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
3135 _, _, lv = tag_strip(dered)
3136 _, _, v = len_decode(lv)
3137 v_no_first_arc = v[1:]
3138 idx_for_tamper = d.draw(integers(
3140 max_value=len(v_no_first_arc) - 1,
3142 tampered = list(bytearray(v_no_first_arc))
3143 for _ in range(d.draw(integers(min_value=1, max_value=3))):
3144 tampered.insert(idx_for_tamper, 0x80)
3145 tampered = bytes(bytearray(tampered))
3147 ObjectIdentifier.tag_default +
3148 len_encode(len(tampered)) +
3151 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3152 self.assertTrue(obj.ber_encoded)
3153 self.assertTrue(obj.bered)
3155 self.assertTrue(obj.ber_encoded)
3156 self.assertTrue(obj.bered)
3157 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3158 ObjectIdentifier().decode(tampered)
3162 def enumerated_values_strategy(draw, schema=None, do_expl=False):
3164 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
3165 values = list(draw(sets(
3167 min_size=len(schema),
3168 max_size=len(schema),
3170 schema = list(zip(schema, values))
3171 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
3175 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3177 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3178 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
3179 optional = draw(one_of(none(), booleans()))
3181 draw(integers(min_value=0)),
3182 draw(integers(min_value=0)),
3183 draw(integers(min_value=0)),
3185 return (schema, value, impl, expl, default, optional, _decoded)
3188 class TestEnumerated(CommonMixin, TestCase):
3189 class EWhatever(Enumerated):
3190 schema = (("whatever", 0),)
3192 base_klass = EWhatever
3194 def test_schema_required(self):
3195 with self.assertRaisesRegex(ValueError, "schema must be specified"):
3198 def test_invalid_value_type(self):
3199 with self.assertRaises(InvalidValueType) as err:
3200 self.base_klass((1, 2))
3203 @given(sets(text_letters(), min_size=2))
3204 def test_unknown_name(self, schema_input):
3205 missing = schema_input.pop()
3207 class E(Enumerated):
3208 schema = [(n, 123) for n in schema_input]
3209 with self.assertRaises(ObjUnknown) as err:
3214 sets(text_letters(), min_size=2),
3215 sets(integers(), min_size=2),
3217 def test_unknown_value(self, schema_input, values_input):
3219 missing_value = values_input.pop()
3220 _input = list(zip(schema_input, values_input))
3222 class E(Enumerated):
3224 with self.assertRaises(DecodeError) as err:
3229 def test_optional(self, optional):
3230 obj = self.base_klass(default="whatever", optional=optional)
3231 self.assertTrue(obj.optional)
3233 def test_ready(self):
3234 obj = self.base_klass()
3235 self.assertFalse(obj.ready)
3238 pprint(obj, big_blobs=True, with_decode_path=True)
3239 with self.assertRaises(ObjNotReady) as err:
3242 obj = self.base_klass("whatever")
3243 self.assertTrue(obj.ready)
3246 pprint(obj, big_blobs=True, with_decode_path=True)
3248 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
3249 def test_comparison(self, value1, value2, tag1, tag2):
3250 class E(Enumerated):
3252 ("whatever0", value1),
3253 ("whatever1", value2),
3256 class EInherited(E):
3258 for klass in (E, EInherited):
3259 obj1 = klass(value1)
3260 obj2 = klass(value2)
3261 self.assertEqual(obj1 == obj2, value1 == value2)
3262 self.assertEqual(obj1 != obj2, value1 != value2)
3263 self.assertEqual(obj1 == int(obj2), value1 == value2)
3264 obj1 = klass(value1, impl=tag1)
3265 obj2 = klass(value1, impl=tag2)
3266 self.assertEqual(obj1 == obj2, tag1 == tag2)
3267 self.assertEqual(obj1 != obj2, tag1 != tag2)
3269 @given(data_strategy())
3270 def test_call(self, d):
3279 ) = d.draw(enumerated_values_strategy())
3281 class E(Enumerated):
3282 schema = schema_initial
3284 value=value_initial,
3287 default=default_initial,
3288 optional=optional_initial or False,
3289 _decoded=_decoded_initial,
3299 ) = d.draw(enumerated_values_strategy(
3300 schema=schema_initial,
3301 do_expl=impl_initial is None,
3311 value_expected = default if value is None else value
3313 default_initial if value_expected is None
3318 dict(schema_initial).get(value_expected, value_expected),
3320 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3321 self.assertEqual(obj.expl_tag, expl or expl_initial)
3324 default_initial if default is None else default,
3326 if obj.default is None:
3327 optional = optional_initial if optional is None else optional
3328 optional = False if optional is None else optional
3331 self.assertEqual(obj.optional, optional)
3332 self.assertEqual(obj.specs, dict(schema_initial))
3334 @given(enumerated_values_strategy())
3335 def test_copy(self, values):
3336 schema_input, value, impl, expl, default, optional, _decoded = values
3338 class E(Enumerated):
3339 schema = schema_input
3349 for copy_func in copy_funcs:
3350 obj_copied = copy_func(obj)
3351 self.assert_copied_basic_fields(obj, obj_copied)
3352 self.assertEqual(obj.specs, obj_copied.specs)
3354 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3355 @given(data_strategy())
3356 def test_symmetric(self, d):
3357 schema_input, _, _, _, default, optional, _decoded = d.draw(
3358 enumerated_values_strategy(),
3360 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3361 offset = d.draw(integers(min_value=0))
3362 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3363 tail_junk = d.draw(binary(max_size=5))
3364 decode_path = d.draw(decode_path_strat)
3366 class E(Enumerated):
3367 schema = schema_input
3376 pprint(obj, big_blobs=True, with_decode_path=True)
3377 self.assertFalse(obj.expled)
3378 obj_encoded = obj.encode()
3379 self.assertEqual(encode2pass(obj), obj_encoded)
3380 obj_expled = obj(value, expl=tag_expl)
3381 self.assertTrue(obj_expled.expled)
3383 list(obj_expled.pps())
3384 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3385 obj_expled_encoded = obj_expled.encode()
3386 ctx_copied = deepcopy(ctx_dummy)
3387 obj_decoded, tail = obj_expled.decode(
3388 obj_expled_encoded + tail_junk,
3392 self.assertDictEqual(ctx_copied, ctx_dummy)
3394 list(obj_decoded.pps())
3395 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3396 self.assertEqual(tail, tail_junk)
3397 self.assertEqual(obj_decoded, obj_expled)
3398 self.assertNotEqual(obj_decoded, obj)
3399 self.assertEqual(int(obj_decoded), int(obj_expled))
3400 self.assertEqual(int(obj_decoded), int(obj))
3401 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3402 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3403 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3405 obj_decoded.expl_llen,
3406 len(len_encode(len(obj_encoded))),
3408 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3409 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3412 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3414 self.assertEqual(obj_decoded.expl_offset, offset)
3415 assert_exceeding_data(
3417 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3421 evgens = list(obj_expled.decode_evgen(
3422 obj_expled_encoded + tail_junk,
3424 decode_path=decode_path,
3427 self.assertEqual(len(evgens), 1)
3428 _decode_path, obj, tail = evgens[0]
3429 self.assertSequenceEqual(tail, tail_junk)
3430 self.assertEqual(_decode_path, decode_path)
3431 self.assertEqual(obj, obj_decoded)
3432 self.assertEqual(obj.expl_offset, offset)
3438 def string_values_strategy(draw, alphabet, do_expl=False):
3439 bound_min, bound_max = sorted(draw(sets(
3440 integers(min_value=0, max_value=1 << 7),
3444 value = draw(one_of(
3446 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3448 default = draw(one_of(
3450 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3453 if draw(booleans()):
3454 bounds = (bound_min, bound_max)
3458 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3460 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3461 optional = draw(one_of(none(), booleans()))
3463 draw(integers(min_value=0)),
3464 draw(integers(min_value=0)),
3465 draw(integers(min_value=0)),
3467 return (value, bounds, impl, expl, default, optional, _decoded)
3470 class StringMixin(object):
3471 def test_invalid_value_type(self):
3472 with self.assertRaises(InvalidValueType) as err:
3473 self.base_klass((1, 2))
3476 def text_alphabet(self):
3477 return "".join(chr(c) for c in range(256))
3480 def test_optional(self, optional):
3481 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3482 self.assertTrue(obj.optional)
3484 @given(data_strategy())
3485 def test_ready(self, d):
3486 obj = self.base_klass()
3487 self.assertFalse(obj.ready)
3490 pprint(obj, big_blobs=True, with_decode_path=True)
3492 with self.assertRaises(ObjNotReady) as err:
3495 with self.assertRaises(ObjNotReady) as err:
3497 value = d.draw(text(alphabet=self.text_alphabet()))
3498 obj = self.base_klass(value)
3499 self.assertTrue(obj.ready)
3502 pprint(obj, big_blobs=True, with_decode_path=True)
3505 @given(data_strategy())
3506 def test_comparison(self, d):
3507 value1 = d.draw(text(alphabet=self.text_alphabet()))
3508 value2 = d.draw(text(alphabet=self.text_alphabet()))
3509 tag1 = d.draw(binary(min_size=1))
3510 tag2 = d.draw(binary(min_size=1))
3511 obj1 = self.base_klass(value1)
3512 obj2 = self.base_klass(value2)
3513 self.assertEqual(obj1 == obj2, value1 == value2)
3514 self.assertEqual(obj1 != obj2, value1 != value2)
3515 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3516 self.assertEqual(obj1 == str(obj2), value1 == value2)
3517 obj1 = self.base_klass(value1, impl=tag1)
3518 obj2 = self.base_klass(value1, impl=tag2)
3519 self.assertEqual(obj1 == obj2, tag1 == tag2)
3520 self.assertEqual(obj1 != obj2, tag1 != tag2)
3522 @given(data_strategy())
3523 def test_bounds_satisfied(self, d):
3524 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3525 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3526 value = d.draw(text(
3527 alphabet=self.text_alphabet(),
3531 self.base_klass(value=value, bounds=(bound_min, bound_max))
3533 @given(data_strategy())
3534 def test_bounds_unsatisfied(self, d):
3535 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3536 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3537 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3538 with self.assertRaises(BoundsError) as err:
3539 self.base_klass(value=value, bounds=(bound_min, bound_max))
3541 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3542 self.base_klass(bounds=(bound_min, bound_max)).decode(
3543 self.base_klass(value).encode()
3546 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3547 self.base_klass(bounds=(bound_min, bound_max)).decode(
3548 encode2pass(self.base_klass(value))
3550 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3551 with self.assertRaises(BoundsError) as err:
3552 self.base_klass(value=value, bounds=(bound_min, bound_max))
3554 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3555 self.base_klass(bounds=(bound_min, bound_max)).decode(
3556 self.base_klass(value).encode()
3559 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3560 self.base_klass(bounds=(bound_min, bound_max)).decode(
3561 encode2pass(self.base_klass(value))
3564 @given(data_strategy())
3565 def test_call(self, d):
3574 ) = d.draw(string_values_strategy(self.text_alphabet()))
3575 obj_initial = self.base_klass(
3581 optional_initial or False,
3592 ) = d.draw(string_values_strategy(
3593 self.text_alphabet(),
3594 do_expl=impl_initial is None,
3596 if (default is None) and (obj_initial.default is not None):
3599 (bounds is None) and
3600 (value is not None) and
3601 (bounds_initial is not None) and
3602 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3606 (bounds is None) and
3607 (default is not None) and
3608 (bounds_initial is not None) and
3609 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3612 obj = obj_initial(value, bounds, impl, expl, default, optional)
3614 value_expected = default if value is None else value
3616 default_initial if value_expected is None
3619 self.assertEqual(obj, value_expected)
3620 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3621 self.assertEqual(obj.expl_tag, expl or expl_initial)
3624 default_initial if default is None else default,
3626 if obj.default is None:
3627 optional = optional_initial if optional is None else optional
3628 optional = False if optional is None else optional
3631 self.assertEqual(obj.optional, optional)
3633 (obj._bound_min, obj._bound_max),
3634 bounds or bounds_initial or (0, float("+inf")),
3637 @given(data_strategy())
3638 def test_copy(self, d):
3639 values = d.draw(string_values_strategy(self.text_alphabet()))
3640 obj = self.base_klass(*values)
3641 for copy_func in copy_funcs:
3642 obj_copied = copy_func(obj)
3643 self.assert_copied_basic_fields(obj, obj_copied)
3644 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3645 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3646 self.assertEqual(obj._value, obj_copied._value)
3648 @given(data_strategy())
3649 def test_stripped(self, d):
3650 value = d.draw(text(alphabet=self.text_alphabet()))
3651 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3652 obj = self.base_klass(value, impl=tag_impl)
3653 with self.assertRaises(NotEnoughData):
3654 obj.decode(obj.encode()[:-1])
3656 @given(data_strategy())
3657 def test_stripped_expl(self, d):
3658 value = d.draw(text(alphabet=self.text_alphabet()))
3659 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3660 obj = self.base_klass(value, expl=tag_expl)
3661 with self.assertRaises(NotEnoughData):
3662 obj.decode(obj.encode()[:-1])
3665 integers(min_value=31),
3666 integers(min_value=0),
3669 def test_bad_tag(self, tag, offset, decode_path):
3670 with self.assertRaises(DecodeError) as err:
3671 self.base_klass().decode(
3672 tag_encode(tag)[:-1],
3674 decode_path=decode_path,
3677 self.assertEqual(err.exception.offset, offset)
3678 self.assertEqual(err.exception.decode_path, decode_path)
3681 integers(min_value=128),
3682 integers(min_value=0),
3685 def test_bad_len(self, l, offset, decode_path):
3686 with self.assertRaises(DecodeError) as err:
3687 self.base_klass().decode(
3688 self.base_klass.tag_default + len_encode(l)[:-1],
3690 decode_path=decode_path,
3693 self.assertEqual(err.exception.offset, offset)
3694 self.assertEqual(err.exception.decode_path, decode_path)
3697 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3698 integers(min_value=0),
3701 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3702 value, bound_min = list(sorted(ints))
3704 class String(self.base_klass):
3705 # Multiply this value by four, to satisfy UTF-32 bounds
3706 # (4 bytes per character) validation
3707 bounds = (bound_min * 4, bound_min * 4)
3708 with self.assertRaises(DecodeError) as err:
3710 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3712 decode_path=decode_path,
3715 self.assertEqual(err.exception.offset, offset)
3716 self.assertEqual(err.exception.decode_path, decode_path)
3718 @given(data_strategy())
3719 def test_symmetric(self, d):
3720 values = d.draw(string_values_strategy(self.text_alphabet()))
3721 value = d.draw(text(alphabet=self.text_alphabet()))
3722 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3723 offset = d.draw(integers(min_value=0))
3724 tail_junk = d.draw(binary(max_size=5))
3725 decode_path = d.draw(decode_path_strat)
3726 _, _, _, _, default, optional, _decoded = values
3727 obj = self.base_klass(
3735 pprint(obj, big_blobs=True, with_decode_path=True)
3736 self.assertFalse(obj.expled)
3737 obj_encoded = obj.encode()
3738 self.assertEqual(encode2pass(obj), obj_encoded)
3739 obj_expled = obj(value, expl=tag_expl)
3740 self.assertTrue(obj_expled.expled)
3742 list(obj_expled.pps())
3743 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3744 obj_expled_encoded = obj_expled.encode()
3745 ctx_copied = deepcopy(ctx_dummy)
3746 obj_decoded, tail = obj_expled.decode(
3747 obj_expled_encoded + tail_junk,
3751 self.assertDictEqual(ctx_copied, ctx_dummy)
3753 list(obj_decoded.pps())
3754 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3755 self.assertEqual(tail, tail_junk)
3756 self.assertEqual(obj_decoded, obj_expled)
3757 self.assertNotEqual(obj_decoded, obj)
3758 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3759 self.assertEqual(bytes(obj_decoded), bytes(obj))
3760 self.assertEqual(str(obj_decoded), str(obj_expled))
3761 self.assertEqual(str(obj_decoded), str(obj))
3762 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3763 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3764 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3766 obj_decoded.expl_llen,
3767 len(len_encode(len(obj_encoded))),
3769 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3770 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3773 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3775 self.assertEqual(obj_decoded.expl_offset, offset)
3776 assert_exceeding_data(
3778 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3782 evgens = list(obj_expled.decode_evgen(
3783 obj_expled_encoded + tail_junk,
3785 decode_path=decode_path,
3788 self.assertEqual(len(evgens), 1)
3789 _decode_path, obj, tail = evgens[0]
3790 self.assertSequenceEqual(tail, tail_junk)
3791 self.assertEqual(_decode_path, decode_path)
3792 if not getattr(self, "evgen_mode_skip_value", True):
3793 self.assertEqual(obj, obj_decoded)
3794 self.assertEqual(obj.expl_offset, offset)
3799 cyrillic_letters = text(
3800 alphabet="".join(chr(i) for i in list(range(0x0410, 0x044f + 1))),
3806 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3807 base_klass = UTF8String
3809 @given(cyrillic_letters)
3810 def test_byte_per_primitive(self, chars):
3812 char_raw = char.encode("utf-8")
3813 encoded = b"".join((
3814 self.base_klass().tag_constructed,
3816 OctetString(char_raw[:1]).encode(),
3817 OctetString(char_raw[1:2]).encode(),
3821 self.base_klass().decod(encoded, ctx={"bered": True}),
3826 class UnicodeDecodeErrorMixin(object):
3827 @given(cyrillic_letters)
3828 def test_unicode_decode_error(self, cyrillic_text):
3829 with self.assertRaises(DecodeError):
3830 self.base_klass(cyrillic_text)
3833 class TestNumericString(StringMixin, CommonMixin, TestCase):
3834 base_klass = NumericString
3836 def text_alphabet(self):
3839 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3840 def test_non_numeric(self, non_numeric_text):
3841 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3842 self.base_klass(non_numeric_text)
3845 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3846 integers(min_value=0),
3849 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3850 value, bound_min = list(sorted(ints))
3852 class String(self.base_klass):
3853 bounds = (bound_min, bound_min)
3854 with self.assertRaises(DecodeError) as err:
3856 self.base_klass(b"1" * value).encode(),
3858 decode_path=decode_path,
3861 self.assertEqual(err.exception.offset, offset)
3862 self.assertEqual(err.exception.decode_path, decode_path)
3864 def test_byte_per_primitive(self):
3865 encoded = b"".join((
3866 self.base_klass().tag_constructed,
3868 OctetString(b"1").encode(),
3869 OctetString(b"2").encode(),
3873 self.base_klass().decod(encoded, ctx={"bered": True}),
3878 class TestPrintableString(
3879 UnicodeDecodeErrorMixin,
3884 base_klass = PrintableString
3886 def text_alphabet(self):
3887 return ascii_letters + digits + " '()+,-./:=?"
3889 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3890 def test_non_printable(self, non_printable_text):
3891 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3892 self.base_klass(non_printable_text)
3895 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3896 integers(min_value=0),
3899 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3900 value, bound_min = list(sorted(ints))
3902 class String(self.base_klass):
3903 bounds = (bound_min, bound_min)
3904 with self.assertRaises(DecodeError) as err:
3906 self.base_klass(b"1" * value).encode(),
3908 decode_path=decode_path,
3911 self.assertEqual(err.exception.offset, offset)
3912 self.assertEqual(err.exception.decode_path, decode_path)
3914 def test_allowable_invalid_chars(self):
3916 ("*", {"allow_asterisk": True}),
3917 ("&", {"allow_ampersand": True}),
3918 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3921 obj = self.base_klass(s)
3922 for prop in kwargs.keys():
3923 self.assertFalse(getattr(obj, prop))
3925 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3927 self.base_klass(s, **kwargs)
3928 klass = self.base_klass(**kwargs)
3930 for prop in kwargs.keys():
3931 self.assertTrue(getattr(obj, prop))
3934 for prop in kwargs.keys():
3935 self.assertTrue(getattr(obj, prop))
3938 class TestTeletexString(
3939 UnicodeDecodeErrorMixin,
3944 base_klass = TeletexString
3947 class TestVideotexString(
3948 UnicodeDecodeErrorMixin,
3953 base_klass = VideotexString
3956 class TestIA5String(
3957 UnicodeDecodeErrorMixin,
3962 base_klass = IA5String
3964 def text_alphabet(self):
3965 return "".join(chr(c) for c in range(128))
3967 @given(integers(min_value=128, max_value=255))
3968 def test_alphabet_bad(self, code):
3969 with self.assertRaises(DecodeError):
3970 self.base_klass().decod(
3971 self.base_klass.tag_default +
3973 bytes(bytearray([code])),
3977 class TestGraphicString(
3978 UnicodeDecodeErrorMixin,
3983 base_klass = GraphicString
3986 class TestVisibleString(
3987 UnicodeDecodeErrorMixin,
3992 base_klass = VisibleString
3994 def text_alphabet(self):
3995 return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
3997 def test_x690_vector(self):
3998 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3999 self.assertSequenceEqual(tail, b"")
4000 self.assertEqual(str(obj), "Jones")
4001 self.assertFalse(obj.ber_encoded)
4002 self.assertFalse(obj.lenindef)
4003 self.assertFalse(obj.bered)
4005 obj, tail = VisibleString().decode(
4006 hexdec("3A0904034A6F6E04026573"),
4007 ctx={"bered": True},
4009 self.assertSequenceEqual(tail, b"")
4010 self.assertEqual(str(obj), "Jones")
4011 self.assertTrue(obj.ber_encoded)
4012 self.assertFalse(obj.lenindef)
4013 self.assertTrue(obj.bered)
4015 self.assertTrue(obj.ber_encoded)
4016 self.assertFalse(obj.lenindef)
4017 self.assertTrue(obj.bered)
4019 obj, tail = VisibleString().decode(
4020 hexdec("3A8004034A6F6E040265730000"),
4021 ctx={"bered": True},
4023 self.assertSequenceEqual(tail, b"")
4024 self.assertEqual(str(obj), "Jones")
4025 self.assertTrue(obj.ber_encoded)
4026 self.assertTrue(obj.lenindef)
4027 self.assertTrue(obj.bered)
4029 self.assertTrue(obj.ber_encoded)
4030 self.assertTrue(obj.lenindef)
4031 self.assertTrue(obj.bered)
4034 integers(min_value=0, max_value=ord(" ") - 1),
4035 integers(min_value=ord("~") + 1, max_value=255),
4037 def test_alphabet_bad(self, code):
4038 with self.assertRaises(DecodeError):
4039 self.base_klass().decod(
4040 self.base_klass.tag_default +
4042 bytes(bytearray([code])),
4046 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
4047 integers(min_value=0),
4050 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
4051 value, bound_min = list(sorted(ints))
4053 class String(self.base_klass):
4054 bounds = (bound_min, bound_min)
4055 with self.assertRaises(DecodeError) as err:
4057 self.base_klass(b"1" * value).encode(),
4059 decode_path=decode_path,
4062 self.assertEqual(err.exception.offset, offset)
4063 self.assertEqual(err.exception.decode_path, decode_path)
4066 class TestGeneralString(
4067 UnicodeDecodeErrorMixin,
4072 base_klass = GeneralString
4075 class TestUniversalString(StringMixin, CommonMixin, TestCase):
4076 base_klass = UniversalString
4079 class TestBMPString(StringMixin, CommonMixin, TestCase):
4080 base_klass = BMPString
4084 def generalized_time_values_strategy(
4092 if draw(booleans()):
4093 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4095 value = value.replace(microsecond=0)
4097 if draw(booleans()):
4098 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4100 default = default.replace(microsecond=0)
4104 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4106 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4107 optional = draw(one_of(none(), booleans()))
4109 draw(integers(min_value=0)),
4110 draw(integers(min_value=0)),
4111 draw(integers(min_value=0)),
4113 return (value, impl, expl, default, optional, _decoded)
4116 class TimeMixin(object):
4117 def test_invalid_value_type(self):
4118 with self.assertRaises(InvalidValueType) as err:
4119 self.base_klass(datetime.now().timetuple())
4122 @given(data_strategy())
4123 def test_optional(self, d):
4124 default = d.draw(datetimes(
4125 min_value=self.min_datetime,
4126 max_value=self.max_datetime,
4128 optional = d.draw(booleans())
4129 obj = self.base_klass(default=default, optional=optional)
4130 self.assertTrue(obj.optional)
4132 @given(data_strategy())
4133 def test_ready(self, d):
4134 obj = self.base_klass()
4135 self.assertFalse(obj.ready)
4138 pprint(obj, big_blobs=True, with_decode_path=True)
4139 with self.assertRaises(ObjNotReady) as err:
4142 with self.assertRaises(ObjNotReady) as err:
4144 value = d.draw(datetimes(
4145 min_value=self.min_datetime,
4146 max_value=self.max_datetime,
4148 obj = self.base_klass(value)
4149 self.assertTrue(obj.ready)
4152 pprint(obj, big_blobs=True, with_decode_path=True)
4154 @given(data_strategy())
4155 def test_comparison(self, d):
4156 value1 = d.draw(datetimes(
4157 min_value=self.min_datetime,
4158 max_value=self.max_datetime,
4160 value2 = d.draw(datetimes(
4161 min_value=self.min_datetime,
4162 max_value=self.max_datetime,
4164 tag1 = d.draw(binary(min_size=1))
4165 tag2 = d.draw(binary(min_size=1))
4167 value1 = value1.replace(microsecond=0)
4168 value2 = value2.replace(microsecond=0)
4169 obj1 = self.base_klass(value1)
4170 obj2 = self.base_klass(value2)
4171 self.assertEqual(obj1 == obj2, value1 == value2)
4172 self.assertEqual(obj1 != obj2, value1 != value2)
4173 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
4174 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4175 obj1 = self.base_klass(value1, impl=tag1)
4176 obj2 = self.base_klass(value1, impl=tag2)
4177 self.assertEqual(obj1 == obj2, tag1 == tag2)
4178 self.assertEqual(obj1 != obj2, tag1 != tag2)
4180 @given(data_strategy())
4181 def test_call(self, d):
4189 ) = d.draw(generalized_time_values_strategy(
4190 min_datetime=self.min_datetime,
4191 max_datetime=self.max_datetime,
4192 omit_ms=self.omit_ms,
4194 obj_initial = self.base_klass(
4195 value=value_initial,
4198 default=default_initial,
4199 optional=optional_initial or False,
4200 _decoded=_decoded_initial,
4209 ) = d.draw(generalized_time_values_strategy(
4210 min_datetime=self.min_datetime,
4211 max_datetime=self.max_datetime,
4212 omit_ms=self.omit_ms,
4213 do_expl=impl_initial is None,
4223 value_expected = default if value is None else value
4225 default_initial if value_expected is None
4228 self.assertEqual(obj, value_expected)
4229 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4230 self.assertEqual(obj.expl_tag, expl or expl_initial)
4233 default_initial if default is None else default,
4235 if obj.default is None:
4236 optional = optional_initial if optional is None else optional
4237 optional = False if optional is None else optional
4240 self.assertEqual(obj.optional, optional)
4242 @given(data_strategy())
4243 def test_copy(self, d):
4244 values = d.draw(generalized_time_values_strategy(
4245 min_datetime=self.min_datetime,
4246 max_datetime=self.max_datetime,
4248 obj = self.base_klass(*values)
4249 for copy_func in copy_funcs:
4250 obj_copied = copy_func(obj)
4251 self.assert_copied_basic_fields(obj, obj_copied)
4252 self.assertEqual(obj._value, obj_copied._value)
4254 @given(data_strategy())
4255 def test_stripped(self, d):
4256 value = d.draw(datetimes(
4257 min_value=self.min_datetime,
4258 max_value=self.max_datetime,
4260 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4261 obj = self.base_klass(value, impl=tag_impl)
4262 with self.assertRaises(NotEnoughData):
4263 obj.decode(obj.encode()[:-1])
4265 @given(data_strategy())
4266 def test_stripped_expl(self, d):
4267 value = d.draw(datetimes(
4268 min_value=self.min_datetime,
4269 max_value=self.max_datetime,
4271 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4272 obj = self.base_klass(value, expl=tag_expl)
4273 with self.assertRaises(NotEnoughData):
4274 obj.decode(obj.encode()[:-1])
4276 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4277 @given(data_strategy())
4278 def test_symmetric(self, d):
4279 values = d.draw(generalized_time_values_strategy(
4280 min_datetime=self.min_datetime,
4281 max_datetime=self.max_datetime,
4283 value = d.draw(datetimes(
4284 min_value=self.min_datetime,
4285 max_value=self.max_datetime,
4287 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4288 offset = d.draw(integers(min_value=0))
4289 tail_junk = d.draw(binary(max_size=5))
4290 _, _, _, default, optional, _decoded = values
4291 obj = self.base_klass(
4299 pprint(obj, big_blobs=True, with_decode_path=True)
4300 self.assertFalse(obj.expled)
4301 obj_encoded = obj.encode()
4302 self.assertEqual(encode2pass(obj), obj_encoded)
4303 self.additional_symmetric_check(value, obj_encoded)
4304 obj_expled = obj(value, expl=tag_expl)
4305 self.assertTrue(obj_expled.expled)
4307 list(obj_expled.pps())
4308 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4309 obj_expled_encoded = obj_expled.encode()
4310 ctx_copied = deepcopy(ctx_dummy)
4311 obj_decoded, tail = obj_expled.decode(
4312 obj_expled_encoded + tail_junk,
4316 self.assertDictEqual(ctx_copied, ctx_dummy)
4318 list(obj_decoded.pps())
4319 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4320 self.assertEqual(tail, tail_junk)
4321 self.assertEqual(obj_decoded, obj_expled)
4322 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
4323 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
4324 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4325 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4326 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4328 obj_decoded.expl_llen,
4329 len(len_encode(len(obj_encoded))),
4331 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4332 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4335 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4337 self.assertEqual(obj_decoded.expl_offset, offset)
4338 assert_exceeding_data(
4340 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4345 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
4346 base_klass = GeneralizedTime
4348 min_datetime = datetime(1900, 1, 1)
4349 max_datetime = datetime(9999, 12, 31)
4350 evgen_mode_skip_value = False
4352 def additional_symmetric_check(self, value, obj_encoded):
4353 if value.microsecond > 0:
4354 self.assertFalse(obj_encoded.endswith(b"0Z"))
4356 def test_repr_not_ready(self):
4357 str(GeneralizedTime())
4358 repr(GeneralizedTime())
4360 def test_x690_vector_valid(self):
4364 b"19920722132100.3Z",
4366 GeneralizedTime(data)
4368 def test_x690_vector_invalid(self):
4371 b"19920622123421.0Z",
4372 b"19920722132100.30Z",
4374 with self.assertRaises(DecodeError) as err:
4375 GeneralizedTime(data)
4378 def test_go_vectors_invalid(self):
4390 b"-20100102030410Z",
4391 b"2010-0102030410Z",
4392 b"2010-0002030410Z",
4393 b"201001-02030410Z",
4394 b"20100102-030410Z",
4395 b"2010010203-0410Z",
4396 b"201001020304-10Z",
4397 # These ones are INVALID in *DER*, but accepted
4398 # by Go's encoding/asn1
4399 b"20100102030405+0607",
4400 b"20100102030405-0607",
4402 with self.assertRaises(DecodeError) as err:
4403 GeneralizedTime(data)
4406 def test_go_vectors_valid(self):
4408 GeneralizedTime(b"20100102030405Z").todatetime(),
4409 datetime(2010, 1, 2, 3, 4, 5, 0),
4412 def test_go_vectors_valid_ber(self):
4414 b"20100102030405+0607",
4415 b"20100102030405-0607",
4417 GeneralizedTime(data, ctx={"bered": True})
4419 def test_utc_offsets(self):
4420 """Some know equal UTC offsets
4423 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4427 "200101011130-0700",
4428 "200101011500-03:30",
4431 self.assertEqual(dts[0], dts[1])
4432 self.assertEqual(dts[0], dts[2])
4433 self.assertEqual(dts[0], dts[3])
4435 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4436 @given(data_strategy())
4437 def test_valid_ber(self, d):
4438 year = d.draw(integers(min_value=2, max_value=9999))
4439 month = d.draw(integers(min_value=1, max_value=12))
4440 day = d.draw(integers(min_value=1, max_value=28))
4441 hours = d.draw(integers(min_value=0, max_value=23))
4442 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4443 dt = datetime(year, month, day, hours)
4444 fractions_sign = d.draw(sampled_from(" ,."))
4446 if fractions_sign != " ":
4447 fractions = random()
4448 if d.draw(booleans()):
4449 minutes = d.draw(integers(min_value=0, max_value=59))
4450 data += "%02d" % minutes
4451 dt += timedelta(seconds=60 * minutes)
4452 if d.draw(booleans()):
4453 seconds = d.draw(integers(min_value=0, max_value=59))
4454 data += "%02d" % seconds
4455 dt += timedelta(seconds=seconds)
4456 if fractions is not None:
4457 dt += timedelta(microseconds=10**6 * fractions)
4458 elif fractions is not None:
4459 dt += timedelta(seconds=60 * fractions)
4460 elif fractions is not None:
4461 dt += timedelta(seconds=3600 * fractions)
4462 if fractions is not None:
4463 data += fractions_sign + str(fractions)[2:]
4464 if d.draw(booleans()):
4466 elif d.draw(booleans()):
4467 offset_hour = d.draw(integers(min_value=0, max_value=13))
4469 if d.draw(booleans()):
4474 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4475 data += "%02d" % offset_hour
4476 minutes_separator = d.draw(sampled_from((None, "", ":")))
4477 if minutes_separator is not None:
4478 offset_minute = d.draw(integers(min_value=0, max_value=59))
4479 dt -= timedelta(seconds=sign * 60 * offset_minute)
4480 data += "%s%02d" % (minutes_separator, offset_minute)
4481 data = data.encode("ascii")
4482 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4484 GeneralizedTime().decod(data_der)
4489 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4492 mktime(obj.todatetime().timetuple()),
4493 mktime(dt.timetuple()),
4497 obj.todatetime().timestamp()
4501 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4502 self.assertEqual(obj.ber_encoded, not dered)
4503 self.assertEqual(obj.bered, not dered)
4504 self.assertEqual(obj.ber_raw, None if dered else data)
4505 self.assertEqual(obj.encode() == data_der, dered)
4510 def test_invalid_ber(self):
4512 # "00010203040506.07",
4513 "-0010203040506.07",
4514 "0001-203040506.07",
4515 "000102-3040506.07",
4516 "00010203-40506.07",
4517 "0001020304-506.07",
4518 "000102030405-6.07",
4519 "00010203040506.-7",
4520 "+0010203040506.07",
4521 "0001+203040506.07",
4522 "000102+3040506.07",
4523 "00010203+40506.07",
4524 "0001020304+506.07",
4525 "000102030405+6.07",
4526 "00010203040506.+7",
4527 " 0010203040506.07",
4528 "0001 203040506.07",
4529 "000102 3040506.07",
4530 "00010203 40506.07",
4531 "0001020304 506.07",
4532 "000102030405 6.07",
4533 "00010203040506. 7",
4534 "001 0203040506.07",
4535 "00012 03040506.07",
4536 "0001023 040506.07",
4537 "000102034 0506.07",
4538 "00010203045 06.07",
4539 "0001020304056 .07",
4540 "00010203040506.7 ",
4620 "00010203040506.07+15",
4621 "00010203040506.07-15",
4622 "00010203040506.07+14:60",
4623 "00010203040506.07+1460",
4624 "00010203040506.07-1460",
4625 "00010203040506.07+00:60",
4626 "00010203040506.07-00:60",
4628 "00010203040506+15",
4629 "00010203040506-15",
4630 "00010203040506+14:60",
4631 "00010203040506+1460",
4632 "00010203040506-1460",
4633 "00010203040506+00:60",
4634 "00010203040506-00:60",
4643 with self.assertRaises(DecodeError):
4644 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4645 data = data.replace(".", ",")
4646 with self.assertRaises(DecodeError):
4647 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4651 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4652 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4654 binary(min_size=1, max_size=1),
4656 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4657 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4660 def test_junk(self, part0, part1, part2):
4661 junk = part0 + part1 + part2
4662 assume(not (set(junk) <= set(digits.encode("ascii"))))
4663 with self.assertRaises(DecodeError):
4664 GeneralizedTime().decode(
4665 GeneralizedTime.tag_default +
4666 len_encode(len(junk)) +
4672 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4673 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4675 binary(min_size=1, max_size=1),
4677 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4678 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4681 def test_junk_dm(self, part0, part1, part2):
4682 junk = part0 + part1 + part2
4683 assume(not (set(junk) <= set(digits.encode("ascii"))))
4684 with self.assertRaises(DecodeError):
4685 GeneralizedTime().decode(
4686 GeneralizedTime.tag_default +
4687 len_encode(len(junk)) +
4691 def test_ns_fractions(self):
4692 GeneralizedTime(b"20010101000000.000001Z")
4693 with self.assertRaisesRegex(DecodeError, "only microsecond fractions"):
4694 GeneralizedTime(b"20010101000000.0000001Z")
4696 def test_non_pure_integers(self):
4698 # b"20000102030405Z,
4705 b"20000102030405.+6Z",
4706 b"20000102030405.-6Z",
4713 b"20000102030405._6Z",
4714 b"20000102030405.6_Z",
4721 b"20000102030405. 6Z",
4728 b"20000102030405.6 Z",
4730 with self.assertRaises(DecodeError):
4731 GeneralizedTime(data)
4733 def test_aware(self):
4734 with self.assertRaisesRegex(ValueError, "only naive"):
4735 GeneralizedTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
4738 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4739 base_klass = UTCTime
4741 min_datetime = datetime(2000, 1, 1)
4742 max_datetime = datetime(2049, 12, 31)
4743 evgen_mode_skip_value = False
4745 def additional_symmetric_check(self, value, obj_encoded):
4748 def test_repr_not_ready(self):
4749 str(GeneralizedTime())
4752 def test_x690_vector_valid(self):
4760 def test_x690_vector_invalid(self):
4765 with self.assertRaises(DecodeError) as err:
4769 def test_go_vectors_invalid(self):
4795 # These ones are INVALID in *DER*, but accepted
4796 # by Go's encoding/asn1
4797 b"910506164540-0700",
4798 b"910506164540+0730",
4802 with self.assertRaises(DecodeError) as err:
4806 def test_go_vectors_valid(self):
4808 UTCTime(b"910506234540Z").todatetime(),
4809 datetime(1991, 5, 6, 23, 45, 40, 0),
4812 def test_non_pure_integers(self):
4841 with self.assertRaises(DecodeError):
4844 def test_x680_vector_valid_ber(self):
4846 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4847 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4848 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4849 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4851 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4852 obj = UTCTime().decod(data_der, ctx={"bered": True})
4853 self.assertEqual(obj, dt)
4854 self.assertEqual(obj.todatetime(), dt)
4855 self.assertTrue(obj.ber_encoded)
4856 self.assertTrue(obj.bered)
4857 self.assertEqual(obj.ber_raw, data)
4858 self.assertNotEqual(obj.encode(), data_der)
4861 def test_go_vectors_valid_ber(self):
4863 b"910506164540-0700",
4864 b"910506164540+0730",
4868 data = UTCTime.tag_default + len_encode(len(data)) + data
4869 obj = UTCTime().decod(data, ctx={"bered": True})
4870 self.assertTrue(obj.ber_encoded)
4871 self.assertTrue(obj.bered)
4872 self.assertNotEqual(obj.encode(), data)
4875 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4876 @given(data_strategy())
4877 def test_valid_ber(self, d):
4878 year = d.draw(integers(min_value=0, max_value=99))
4879 month = d.draw(integers(min_value=1, max_value=12))
4880 day = d.draw(integers(min_value=1, max_value=28))
4881 hours = d.draw(integers(min_value=0, max_value=23))
4882 minute = d.draw(integers(min_value=0, max_value=59))
4883 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4885 year + (2000 if year < 50 else 1900),
4892 if d.draw(booleans()):
4894 seconds = d.draw(integers(min_value=0, max_value=59))
4895 data += "%02d" % seconds
4896 dt += timedelta(seconds=seconds)
4897 if d.draw(booleans()):
4901 offset_hour = d.draw(integers(min_value=0, max_value=13))
4902 offset_minute = d.draw(integers(min_value=0, max_value=59))
4903 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4904 if d.draw(booleans()):
4910 data += "%02d%02d" % (offset_hour, offset_minute)
4911 data = data.encode("ascii")
4912 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4913 obj = UTCTime().decod(data_der, ctx={"bered": True})
4914 self.assertEqual(obj, dt)
4915 self.assertEqual(obj.todatetime(), dt)
4916 self.assertEqual(obj.ber_encoded, not dered)
4917 self.assertEqual(obj.bered, not dered)
4918 self.assertEqual(obj.ber_raw, None if dered else data)
4919 self.assertEqual(obj.encode() == data_der, dered)
4924 def test_invalid_ber(self):
4965 b"0001020304+0000Z",
4974 with self.assertRaises(DecodeError):
4975 UTCTime(data, ctx={"bered": True})
4976 data = data[:8] + data[8+2:]
4977 with self.assertRaises(DecodeError):
4978 UTCTime(data, ctx={"bered": True})
5023 b"000102030405+000",
5024 b"000102030405+000Z",
5025 b"000102030405+0000Z",
5026 b"000102030405+-101",
5027 b"000102030405+01-1",
5028 b"000102030405+0060",
5029 b"000102030405+1401",
5030 b"500101000002+0003",
5032 with self.assertRaises(DecodeError):
5033 UTCTime(data, ctx={"bered": True})
5035 @given(integers(min_value=0, max_value=49))
5036 def test_pre50(self, year):
5038 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5042 @given(integers(min_value=50, max_value=99))
5043 def test_post50(self, year):
5045 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5051 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5052 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5054 binary(min_size=1, max_size=1),
5056 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5057 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5060 def test_junk(self, part0, part1, part2):
5061 junk = part0 + part1 + part2
5062 assume(not (set(junk) <= set(digits.encode("ascii"))))
5063 with self.assertRaises(DecodeError):
5065 UTCTime.tag_default +
5066 len_encode(len(junk)) +
5070 def test_aware(self):
5071 with self.assertRaisesRegex(ValueError, "only naive"):
5072 UTCTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
5074 def test_raises_if_no_dateutil(self):
5075 with patch("pyderasn.tzUTC", new="missing"):
5076 with self.assertRaisesRegex(NotImplementedError, "dateutil"):
5077 UTCTime(datetime.now()).totzdatetime()
5079 def test_tzinfo_gives_datetime_with_tzutc_tzinfo(self):
5080 self.assertEqual(UTCTime(datetime.now()).totzdatetime().tzinfo, UTC)
5084 def tlv_value_strategy(draw):
5085 tag_num = draw(integers(min_value=1))
5086 data = draw(binary())
5087 return b"".join((tag_encode(tag_num), len_encode(len(data)), data))
5091 def any_values_strategy(draw, do_expl=False):
5092 value = draw(one_of(none(), tlv_value_strategy()))
5095 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5096 optional = draw(one_of(none(), booleans()))
5098 draw(integers(min_value=0)),
5099 draw(integers(min_value=0)),
5100 draw(integers(min_value=0)),
5102 return (value, expl, optional, _decoded)
5105 class AnyInherited(Any):
5109 class TestAny(CommonMixin, TestCase):
5112 def test_invalid_value_type(self):
5113 with self.assertRaises(InvalidValueType) as err:
5118 def test_optional(self, optional):
5119 obj = Any(optional=optional)
5120 self.assertEqual(obj.optional, optional)
5122 @given(tlv_value_strategy())
5123 def test_ready(self, value):
5125 self.assertFalse(obj.ready)
5128 pprint(obj, big_blobs=True, with_decode_path=True)
5129 with self.assertRaises(ObjNotReady) as err:
5132 with self.assertRaises(ObjNotReady) as err:
5135 self.assertTrue(obj.ready)
5138 pprint(obj, big_blobs=True, with_decode_path=True)
5141 def test_basic(self, value):
5142 integer_encoded = Integer(value).encode()
5144 Any(integer_encoded),
5145 Any(Integer(value)),
5146 Any(Any(Integer(value))),
5148 self.assertSequenceEqual(bytes(obj), integer_encoded)
5150 obj.decode(obj.encode())[0].vlen,
5151 len(integer_encoded),
5155 pprint(obj, big_blobs=True, with_decode_path=True)
5156 self.assertSequenceEqual(obj.encode(), integer_encoded)
5158 @given(tlv_value_strategy(), tlv_value_strategy())
5159 def test_comparison(self, value1, value2):
5160 for klass in (Any, AnyInherited):
5161 obj1 = klass(value1)
5162 obj2 = klass(value2)
5163 self.assertEqual(obj1 == obj2, value1 == value2)
5164 self.assertEqual(obj1 != obj2, value1 != value2)
5165 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
5167 @given(data_strategy())
5168 def test_call(self, d):
5169 for klass in (Any, AnyInherited):
5175 ) = d.draw(any_values_strategy())
5176 obj_initial = klass(
5179 optional_initial or False,
5187 ) = d.draw(any_values_strategy(do_expl=True))
5188 obj = obj_initial(value, expl, optional)
5190 value_expected = None if value is None else value
5191 self.assertEqual(obj, value_expected)
5192 self.assertEqual(obj.expl_tag, expl or expl_initial)
5193 if obj.default is None:
5194 optional = optional_initial if optional is None else optional
5195 optional = False if optional is None else optional
5196 self.assertEqual(obj.optional, optional)
5198 def test_simultaneous_impl_expl(self):
5199 # override it, as Any does not have implicit tag
5202 def test_decoded(self):
5203 # override it, as Any does not have implicit tag
5206 @given(any_values_strategy())
5207 def test_copy(self, values):
5208 for klass in (Any, AnyInherited):
5209 obj = klass(*values)
5210 for copy_func in copy_funcs:
5211 obj_copied = copy_func(obj)
5212 self.assert_copied_basic_fields(obj, obj_copied)
5213 self.assertEqual(obj._value, obj_copied._value)
5215 @given(binary().map(OctetString))
5216 def test_stripped(self, value):
5218 with self.assertRaises(NotEnoughData):
5219 obj.decode(obj.encode()[:-1])
5222 tlv_value_strategy(),
5223 integers(min_value=1).map(tag_ctxc),
5225 def test_stripped_expl(self, value, tag_expl):
5226 obj = Any(value, expl=tag_expl)
5227 with self.assertRaises(NotEnoughData):
5228 obj.decode(obj.encode()[:-1])
5231 integers(min_value=31),
5232 integers(min_value=0),
5235 def test_bad_tag(self, tag, offset, decode_path):
5236 with self.assertRaises(DecodeError) as err:
5238 tag_encode(tag)[:-1],
5240 decode_path=decode_path,
5243 self.assertEqual(err.exception.offset, offset)
5244 self.assertEqual(err.exception.decode_path, decode_path)
5247 integers(min_value=128),
5248 integers(min_value=0),
5251 def test_bad_len(self, l, offset, decode_path):
5252 with self.assertRaises(DecodeError) as err:
5254 Any.tag_default + len_encode(l)[:-1],
5256 decode_path=decode_path,
5259 self.assertEqual(err.exception.offset, offset)
5260 self.assertEqual(err.exception.decode_path, decode_path)
5262 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5264 any_values_strategy(),
5265 integers().map(lambda x: Integer(x).encode()),
5266 integers(min_value=1).map(tag_ctxc),
5267 integers(min_value=0),
5271 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
5272 for klass in (Any, AnyInherited):
5273 _, _, optional, _decoded = values
5274 obj = klass(value=value, optional=optional, _decoded=_decoded)
5277 pprint(obj, big_blobs=True, with_decode_path=True)
5278 self.assertFalse(obj.expled)
5279 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5280 self.assertEqual(obj.tag_order, (tag_class, tag_num))
5281 obj_encoded = obj.encode()
5282 self.assertEqual(encode2pass(obj), obj_encoded)
5283 obj_expled = obj(value, expl=tag_expl)
5284 self.assertTrue(obj_expled.expled)
5285 tag_class, _, tag_num = tag_decode(tag_expl)
5286 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5288 list(obj_expled.pps())
5289 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5290 obj_expled_encoded = obj_expled.encode()
5291 ctx_copied = deepcopy(ctx_dummy)
5292 obj_decoded, tail = obj_expled.decode(
5293 obj_expled_encoded + tail_junk,
5297 self.assertDictEqual(ctx_copied, ctx_dummy)
5299 list(obj_decoded.pps())
5300 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5301 self.assertEqual(tail, tail_junk)
5302 self.assertEqual(obj_decoded, obj_expled)
5303 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
5304 self.assertEqual(bytes(obj_decoded), bytes(obj))
5305 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5306 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5307 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5309 obj_decoded.expl_llen,
5310 len(len_encode(len(obj_encoded))),
5312 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5313 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5316 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5318 self.assertEqual(obj_decoded.expl_offset, offset)
5319 self.assertEqual(obj_decoded.tlen, 0)
5320 self.assertEqual(obj_decoded.llen, 0)
5321 self.assertEqual(obj_decoded.vlen, len(value))
5322 assert_exceeding_data(
5324 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5328 evgens = list(obj_expled.decode_evgen(
5329 obj_expled_encoded + tail_junk,
5331 decode_path=decode_path,
5334 self.assertEqual(len(evgens), 1)
5335 _decode_path, obj, tail = evgens[0]
5336 self.assertSequenceEqual(tail, tail_junk)
5337 self.assertEqual(_decode_path, decode_path)
5338 self.assertEqual(obj.expl_offset, offset)
5343 integers(min_value=1).map(tag_ctxc),
5344 integers(min_value=0, max_value=3),
5345 integers(min_value=0),
5349 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
5350 chunk = Boolean(False, expl=expl).encode()
5352 OctetString.tag_default +
5354 b"".join([chunk] * chunks) +
5357 with self.assertRaises(LenIndefForm):
5361 decode_path=decode_path,
5363 obj, tail = Any().decode(
5366 decode_path=decode_path,
5367 ctx={"bered": True},
5369 self.assertSequenceEqual(tail, junk)
5370 self.assertEqual(obj.offset, offset)
5371 self.assertEqual(obj.tlvlen, len(encoded))
5372 self.assertTrue(obj.lenindef)
5373 self.assertFalse(obj.ber_encoded)
5374 self.assertTrue(obj.bered)
5376 self.assertTrue(obj.lenindef)
5377 self.assertFalse(obj.ber_encoded)
5378 self.assertTrue(obj.bered)
5381 pprint(obj, big_blobs=True, with_decode_path=True)
5382 with self.assertRaises(NotEnoughData) as err:
5386 decode_path=decode_path,
5387 ctx={"bered": True},
5389 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
5390 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
5392 class SeqOf(SequenceOf):
5393 schema = Boolean(expl=expl)
5395 class Seq(Sequence):
5397 ("type", ObjectIdentifier(defines=((("value",), {
5398 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
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)
5416 chunk = chunk[:-1] + b"\x01"
5417 chunks = b"".join([chunk] * (chunks + 1))
5418 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
5420 ("type", ObjectIdentifier("1.2.3")),
5421 ("value", Any(encoded)),
5423 seq_encoded = seq.encode()
5424 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5425 self.assertIsNotNone(seq_decoded["value"].defined)
5427 list(seq_decoded.pps())
5428 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5429 self.assertTrue(seq_decoded.bered)
5430 self.assertFalse(seq_decoded["type"].bered)
5431 self.assertTrue(seq_decoded["value"].bered)
5435 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
5437 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
5438 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
5440 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
5441 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
5443 min_size=len(names),
5444 max_size=len(names),
5447 (name, Integer(**tag_kwargs))
5448 for name, tag_kwargs in zip(names, tags)
5451 if value_required or draw(booleans()):
5452 value = draw(tuples(
5453 sampled_from([name for name, _ in schema]),
5454 integers().map(Integer),
5458 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5459 default = draw(one_of(
5461 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5463 optional = draw(one_of(none(), booleans()))
5465 draw(integers(min_value=0)),
5466 draw(integers(min_value=0)),
5467 draw(integers(min_value=0)),
5469 return (schema, value, expl, default, optional, _decoded)
5472 class ChoiceInherited(Choice):
5476 class TestChoice(CommonMixin, TestCase):
5478 schema = (("whatever", Boolean()),)
5481 def test_schema_required(self):
5482 with self.assertRaisesRegex(ValueError, "schema must be specified"):
5485 def test_impl_forbidden(self):
5486 with self.assertRaisesRegex(ValueError, "no implicit tag allowed"):
5487 Choice(impl=b"whatever")
5489 def test_invalid_value_type(self):
5490 with self.assertRaises(InvalidValueType) as err:
5491 self.base_klass(123)
5493 with self.assertRaises(ObjUnknown) as err:
5494 self.base_klass(("whenever", Boolean(False)))
5496 with self.assertRaises(InvalidValueType) as err:
5497 self.base_klass(("whatever", Integer(123)))
5501 def test_optional(self, optional):
5502 obj = self.base_klass(
5503 default=self.base_klass(("whatever", Boolean(False))),
5506 self.assertTrue(obj.optional)
5509 def test_ready(self, value):
5510 obj = self.base_klass()
5511 self.assertFalse(obj.ready)
5514 pprint(obj, big_blobs=True, with_decode_path=True)
5515 self.assertIsNone(obj["whatever"])
5516 with self.assertRaises(ObjNotReady) as err:
5519 with self.assertRaises(ObjNotReady) as err:
5521 obj["whatever"] = Boolean()
5522 self.assertFalse(obj.ready)
5525 pprint(obj, big_blobs=True, with_decode_path=True)
5526 obj["whatever"] = Boolean(value)
5527 self.assertTrue(obj.ready)
5530 pprint(obj, big_blobs=True, with_decode_path=True)
5532 @given(booleans(), booleans())
5533 def test_comparison(self, value1, value2):
5534 class WahlInherited(self.base_klass):
5536 for klass in (self.base_klass, WahlInherited):
5537 obj1 = klass(("whatever", Boolean(value1)))
5538 obj2 = klass(("whatever", Boolean(value2)))
5539 self.assertEqual(obj1 == obj2, value1 == value2)
5540 self.assertEqual(obj1 != obj2, value1 != value2)
5541 self.assertEqual(obj1 == obj2._value, value1 == value2)
5542 self.assertFalse(obj1 == obj2._value[1])
5544 @given(data_strategy())
5545 def test_call(self, d):
5546 for klass in (Choice, ChoiceInherited):
5554 ) = d.draw(choice_values_strategy())
5557 schema = schema_initial
5559 value=value_initial,
5561 default=default_initial,
5562 optional=optional_initial or False,
5563 _decoded=_decoded_initial,
5572 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5573 obj = obj_initial(value, expl, default, optional)
5575 value_expected = default if value is None else value
5577 default_initial if value_expected is None
5580 self.assertEqual(obj.choice, value_expected[0])
5581 self.assertEqual(obj.value, int(value_expected[1]))
5582 self.assertEqual(obj.expl_tag, expl or expl_initial)
5583 default_expect = default_initial if default is None else default
5584 if default_expect is not None:
5585 self.assertEqual(obj.default.choice, default_expect[0])
5586 self.assertEqual(obj.default.value, int(default_expect[1]))
5587 if obj.default is None:
5588 optional = optional_initial if optional is None else optional
5589 optional = False if optional is None else optional
5592 self.assertEqual(obj.optional, optional)
5593 self.assertEqual(obj.specs, obj_initial.specs)
5595 def test_simultaneous_impl_expl(self):
5596 # override it, as Any does not have implicit tag
5599 def test_decoded(self):
5600 # override it, as Any does not have implicit tag
5603 @given(choice_values_strategy())
5604 def test_copy(self, values):
5605 _schema, value, expl, default, optional, _decoded = values
5607 class Wahl(self.base_klass):
5609 register_class(Wahl)
5614 optional=optional or False,
5617 for copy_func in copy_funcs:
5618 obj_copied = copy_func(obj)
5619 self.assertIsNone(obj.tag)
5620 self.assertIsNone(obj_copied.tag)
5621 # hack for assert_copied_basic_fields
5622 obj.tag = "whatever"
5623 obj_copied.tag = "whatever"
5624 self.assert_copied_basic_fields(obj, obj_copied)
5626 self.assertEqual(obj._value, obj_copied._value)
5627 self.assertEqual(obj.specs, obj_copied.specs)
5630 def test_stripped(self, value):
5631 obj = self.base_klass(("whatever", Boolean(value)))
5632 with self.assertRaises(NotEnoughData):
5633 obj.decode(obj.encode()[:-1])
5637 integers(min_value=1).map(tag_ctxc),
5639 def test_stripped_expl(self, value, tag_expl):
5640 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5641 with self.assertRaises(NotEnoughData):
5642 obj.decode(obj.encode()[:-1])
5644 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5645 @given(data_strategy())
5646 def test_symmetric(self, d):
5647 _schema, value, _, default, optional, _decoded = d.draw(
5648 choice_values_strategy(value_required=True)
5650 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5651 offset = d.draw(integers(min_value=0))
5652 tail_junk = d.draw(binary(max_size=5))
5653 decode_path = d.draw(decode_path_strat)
5655 class Wahl(self.base_klass):
5665 pprint(obj, big_blobs=True, with_decode_path=True)
5666 self.assertFalse(obj.expled)
5667 self.assertEqual(obj.tag_order, obj.value.tag_order)
5668 obj_encoded = obj.encode()
5669 self.assertEqual(encode2pass(obj), obj_encoded)
5670 obj_expled = obj(value, expl=tag_expl)
5671 self.assertTrue(obj_expled.expled)
5672 tag_class, _, tag_num = tag_decode(tag_expl)
5673 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5675 list(obj_expled.pps())
5676 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5677 obj_expled_encoded = obj_expled.encode()
5678 ctx_copied = deepcopy(ctx_dummy)
5679 obj_decoded, tail = obj_expled.decode(
5680 obj_expled_encoded + tail_junk,
5684 self.assertDictEqual(ctx_copied, ctx_dummy)
5686 list(obj_decoded.pps())
5687 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5688 self.assertEqual(tail, tail_junk)
5689 self.assertEqual(obj_decoded, obj_expled)
5690 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5691 self.assertEqual(obj_decoded.value, obj_expled.value)
5692 self.assertEqual(obj_decoded.choice, obj.choice)
5693 self.assertEqual(obj_decoded.value, obj.value)
5694 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5695 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5696 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5698 obj_decoded.expl_llen,
5699 len(len_encode(len(obj_encoded))),
5701 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5702 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5705 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5707 self.assertEqual(obj_decoded.expl_offset, offset)
5708 self.assertSequenceEqual(
5710 obj_decoded.value.fulloffset - offset:
5711 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5715 assert_exceeding_data(
5717 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5721 evgens = list(obj_expled.decode_evgen(
5722 obj_expled_encoded + tail_junk,
5724 decode_path=decode_path,
5727 self.assertEqual(len(evgens), 2)
5728 _decode_path, obj, tail = evgens[0]
5729 self.assertEqual(_decode_path, decode_path + (obj_decoded.choice,))
5730 _decode_path, obj, tail = evgens[1]
5731 self.assertSequenceEqual(tail, tail_junk)
5732 self.assertEqual(_decode_path, decode_path)
5733 self.assertEqual(obj.expl_offset, offset)
5738 def test_set_get(self, value):
5741 ("erste", Boolean()),
5742 ("zweite", Integer()),
5745 with self.assertRaises(ObjUnknown) as err:
5746 obj["whatever"] = "whenever"
5747 with self.assertRaises(InvalidValueType) as err:
5748 obj["zweite"] = Boolean(False)
5749 obj["zweite"] = Integer(value)
5751 with self.assertRaises(ObjUnknown) as err:
5754 self.assertIsNone(obj["erste"])
5755 self.assertEqual(obj["zweite"], Integer(value))
5757 def test_tag_mismatch(self):
5760 ("erste", Boolean()),
5762 int_encoded = Integer(123).encode()
5763 bool_encoded = Boolean(False).encode()
5765 obj.decode(bool_encoded)
5766 with self.assertRaises(TagMismatch):
5767 obj.decode(int_encoded)
5769 def test_tag_mismatch_underlying(self):
5770 class SeqOfBoolean(SequenceOf):
5773 class SeqOfInteger(SequenceOf):
5778 ("erste", SeqOfBoolean()),
5781 int_encoded = SeqOfInteger((Integer(123),)).encode()
5782 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5784 obj.decode(bool_encoded)
5785 with self.assertRaises(TagMismatch) as err:
5786 obj.decode(int_encoded)
5787 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5791 def seq_values_strategy(draw, seq_klass, do_expl=False):
5793 if draw(booleans()):
5795 value._value = draw(dictionaries(
5798 booleans().map(Boolean),
5799 integers().map(Integer),
5803 if draw(booleans()):
5804 schema = list(draw(dictionaries(
5807 booleans().map(Boolean),
5808 integers().map(Integer),
5814 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5816 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5818 if draw(booleans()):
5819 default = seq_klass()
5820 default._value = draw(dictionaries(
5823 booleans().map(Boolean),
5824 integers().map(Integer),
5827 optional = draw(one_of(none(), booleans()))
5829 draw(integers(min_value=0)),
5830 draw(integers(min_value=0)),
5831 draw(integers(min_value=0)),
5833 return (value, schema, impl, expl, default, optional, _decoded)
5837 def sequence_strategy(draw, seq_klass):
5838 inputs = draw(lists(
5840 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5841 tuples(just(Integer), integers(), one_of(none(), integers())),
5846 integers(min_value=1),
5847 min_size=len(inputs),
5848 max_size=len(inputs),
5851 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5852 for tag, expled in zip(tags, draw(lists(
5854 min_size=len(inputs),
5855 max_size=len(inputs),
5859 for i, optional in enumerate(draw(lists(
5860 sampled_from(("required", "optional", "empty")),
5861 min_size=len(inputs),
5862 max_size=len(inputs),
5864 if optional in ("optional", "empty"):
5865 inits[i]["optional"] = True
5866 if optional == "empty":
5868 empties = set(empties)
5869 names = list(draw(sets(
5871 min_size=len(inputs),
5872 max_size=len(inputs),
5875 for i, (klass, value, default) in enumerate(inputs):
5876 schema.append((names[i], klass(default=default, **inits[i])))
5877 seq_name = draw(text_letters())
5878 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5881 for i, (klass, value, default) in enumerate(inputs):
5888 "default_value": None if spec.default is None else default,
5892 expect["optional"] = True
5894 expect["presented"] = True
5895 expect["value"] = value
5897 expect["optional"] = True
5898 if default is not None and default == value:
5899 expect["presented"] = False
5900 seq[name] = klass(value)
5901 expects.append(expect)
5906 def sequences_strategy(draw, seq_klass):
5907 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5909 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5910 for tag, expled in zip(tags, draw(lists(
5917 i for i, is_default in enumerate(draw(lists(
5923 names = list(draw(sets(
5928 seq_expectses = draw(lists(
5929 sequence_strategy(seq_klass=seq_klass),
5933 seqs = [seq for seq, _ in seq_expectses]
5935 for i, (name, seq) in enumerate(zip(names, seqs)):
5938 seq(default=(seq if i in defaulted else None), **inits[i]),
5940 seq_name = draw(text_letters())
5941 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5944 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5947 "expects": expects_inner,
5950 seq_outer[name] = seq_inner
5951 if seq_outer.specs[name].default is None:
5952 expect["presented"] = True
5953 expect_outers.append(expect)
5954 return seq_outer, expect_outers
5957 class SeqMixin(object):
5958 def test_invalid_value_type(self):
5959 with self.assertRaises(InvalidValueType) as err:
5960 self.base_klass(123)
5963 def test_invalid_value_type_set(self):
5964 class Seq(self.base_klass):
5965 schema = (("whatever", Boolean()),)
5967 with self.assertRaises(InvalidValueType) as err:
5968 seq["whatever"] = Integer(123)
5972 def test_optional(self, optional):
5973 obj = self.base_klass(default=self.base_klass(), optional=optional)
5974 self.assertTrue(obj.optional)
5976 @given(data_strategy())
5977 def test_ready(self, d):
5979 str(i): v for i, v in enumerate(d.draw(lists(
5986 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5993 for name in d.draw(permutations(
5994 list(ready.keys()) + list(non_ready.keys()),
5996 schema_input.append((name, Boolean()))
5998 class Seq(self.base_klass):
5999 schema = tuple(schema_input)
6001 for name in ready.keys():
6003 seq[name] = Boolean()
6004 self.assertFalse(seq.ready)
6007 pprint(seq, big_blobs=True, with_decode_path=True)
6008 for name, value in ready.items():
6009 seq[name] = Boolean(value)
6010 self.assertFalse(seq.ready)
6013 pprint(seq, big_blobs=True, with_decode_path=True)
6014 with self.assertRaises(ObjNotReady) as err:
6017 with self.assertRaises(ObjNotReady) as err:
6019 for name, value in non_ready.items():
6020 seq[name] = Boolean(value)
6021 self.assertTrue(seq.ready)
6024 pprint(seq, big_blobs=True, with_decode_path=True)
6026 @given(data_strategy())
6027 def test_call(self, d):
6028 class SeqInherited(self.base_klass):
6030 for klass in (self.base_klass, SeqInherited):
6039 ) = d.draw(seq_values_strategy(seq_klass=klass))
6040 obj_initial = klass(
6046 optional_initial or False,
6057 ) = d.draw(seq_values_strategy(
6059 do_expl=impl_initial is None,
6061 obj = obj_initial(value, impl, expl, default, optional)
6062 value_expected = default if value is None else value
6064 default_initial if value_expected is None
6067 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
6068 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6069 self.assertEqual(obj.expl_tag, expl or expl_initial)
6071 {} if obj.default is None else obj.default._value,
6072 getattr(default_initial if default is None else default, "_value", {}),
6074 if obj.default is None:
6075 optional = optional_initial if optional is None else optional
6076 optional = False if optional is None else optional
6079 self.assertEqual(list(obj.specs.items()), schema_initial or [])
6080 self.assertEqual(obj.optional, optional)
6082 @given(data_strategy())
6083 def test_copy(self, d):
6084 class SeqInherited(self.base_klass):
6086 register_class(SeqInherited)
6087 for klass in (self.base_klass, SeqInherited):
6088 values = d.draw(seq_values_strategy(seq_klass=klass))
6089 obj = klass(*values)
6090 for copy_func in copy_funcs:
6091 obj_copied = copy_func(obj)
6092 self.assert_copied_basic_fields(obj, obj_copied)
6093 self.assertEqual(obj.specs, obj_copied.specs)
6094 self.assertEqual(obj._value, obj_copied._value)
6096 @given(data_strategy())
6097 def test_stripped(self, d):
6098 value = d.draw(integers())
6099 tag_impl = tag_encode(d.draw(integers(min_value=1)))
6101 class Seq(self.base_klass):
6103 schema = (("whatever", Integer()),)
6105 seq["whatever"] = Integer(value)
6106 with self.assertRaises(NotEnoughData):
6107 seq.decode(seq.encode()[:-1])
6109 @given(data_strategy())
6110 def test_stripped_expl(self, d):
6111 value = d.draw(integers())
6112 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
6114 class Seq(self.base_klass):
6116 schema = (("whatever", Integer()),)
6118 seq["whatever"] = Integer(value)
6119 with self.assertRaises(NotEnoughData):
6120 seq.decode(seq.encode()[:-1])
6122 @given(integers(min_value=3), binary(min_size=2))
6123 def test_non_tag_mismatch_raised(self, junk_tag_num, junk):
6124 junk = tag_encode(junk_tag_num) + junk
6126 _, _, len_encoded = tag_strip(memoryview(junk))
6127 len_decode(len_encoded)
6133 class Seq(self.base_klass):
6135 ("whatever", Integer()),
6137 ("whenever", Integer()),
6140 seq["whatever"] = Integer(123)
6141 seq["junk"] = Any(junk)
6142 seq["whenever"] = Integer(123)
6143 with self.assertRaises(DecodeError):
6144 seq.decode(seq.encode())
6147 integers(min_value=31),
6148 integers(min_value=0),
6151 def test_bad_tag(self, tag, offset, decode_path):
6152 with self.assertRaises(DecodeError) as err:
6153 self.base_klass().decode(
6154 tag_encode(tag)[:-1],
6156 decode_path=decode_path,
6159 self.assertEqual(err.exception.offset, offset)
6160 self.assertEqual(err.exception.decode_path, decode_path)
6163 integers(min_value=128),
6164 integers(min_value=0),
6167 def test_bad_len(self, l, offset, decode_path):
6168 with self.assertRaises(DecodeError) as err:
6169 self.base_klass().decode(
6170 self.base_klass.tag_default + len_encode(l)[:-1],
6172 decode_path=decode_path,
6175 self.assertEqual(err.exception.offset, offset)
6176 self.assertEqual(err.exception.decode_path, decode_path)
6178 def _assert_expects(self, seq, expects):
6179 for expect in expects:
6181 seq.specs[expect["name"]].optional,
6184 if expect["default_value"] is not None:
6186 seq.specs[expect["name"]].default,
6187 expect["default_value"],
6189 if expect["presented"]:
6190 self.assertIn(expect["name"], seq)
6191 self.assertEqual(seq[expect["name"]], expect["value"])
6193 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6194 @given(data_strategy())
6195 def test_symmetric(self, d):
6196 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
6197 tail_junk = d.draw(binary(max_size=5))
6198 decode_path = d.draw(decode_path_strat)
6199 self.assertTrue(seq.ready)
6200 self.assertFalse(seq.decoded)
6201 self._assert_expects(seq, expects)
6204 pprint(seq, big_blobs=True, with_decode_path=True)
6205 self.assertTrue(seq.ready)
6206 seq_encoded = seq.encode()
6207 self.assertEqual(encode2pass(seq), seq_encoded)
6208 seq_encoded_cer = encode_cer(seq)
6209 self.assertNotEqual(seq_encoded_cer, seq_encoded)
6210 self.assertSequenceEqual(
6211 seq.decod(seq_encoded_cer, ctx={"bered": True}).encode(),
6214 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
6215 self.assertFalse(seq_decoded.lenindef)
6216 self.assertFalse(seq_decoded.ber_encoded)
6217 self.assertFalse(seq_decoded.bered)
6219 t, _, lv = tag_strip(seq_encoded)
6220 _, _, v = len_decode(lv)
6221 seq_encoded_lenindef = t + LENINDEF + v + EOC
6222 with self.assertRaises(DecodeError):
6223 seq.decode(seq_encoded_lenindef)
6224 ctx_copied = deepcopy(ctx_dummy)
6225 ctx_copied["bered"] = True
6226 seq_decoded_lenindef, tail_lenindef = seq.decode(
6227 seq_encoded_lenindef + tail_junk,
6230 del ctx_copied["bered"]
6231 self.assertDictEqual(ctx_copied, ctx_dummy)
6232 self.assertTrue(seq_decoded_lenindef.lenindef)
6233 self.assertTrue(seq_decoded_lenindef.bered)
6234 seq_decoded_lenindef = copy(seq_decoded_lenindef)
6235 self.assertTrue(seq_decoded_lenindef.lenindef)
6236 self.assertTrue(seq_decoded_lenindef.bered)
6237 with self.assertRaises(DecodeError):
6238 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
6239 with self.assertRaises(DecodeError):
6240 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
6241 repr(seq_decoded_lenindef)
6242 list(seq_decoded_lenindef.pps())
6243 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
6244 self.assertTrue(seq_decoded_lenindef.ready)
6246 for decoded, decoded_tail, encoded in (
6247 (seq_decoded, tail, seq_encoded),
6248 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
6250 self.assertEqual(decoded_tail, tail_junk)
6251 self._assert_expects(decoded, expects)
6252 self.assertEqual(seq, decoded)
6253 self.assertEqual(decoded.encode(), seq_encoded)
6254 self.assertEqual(decoded.tlvlen, len(encoded))
6255 for expect in expects:
6256 if not expect["presented"]:
6257 self.assertNotIn(expect["name"], decoded)
6259 self.assertIn(expect["name"], decoded)
6260 obj = decoded[expect["name"]]
6261 self.assertTrue(obj.decoded)
6262 offset = obj.expl_offset if obj.expled else obj.offset
6263 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6264 self.assertSequenceEqual(
6265 seq_encoded[offset:offset + tlvlen],
6269 evgens = list(seq.decode_evgen(
6270 encoded + decoded_tail,
6271 decode_path=decode_path,
6272 ctx={"bered": True},
6274 self.assertEqual(len(evgens), len(list(decoded._values_for_encoding())) + 1)
6275 for _decode_path, obj, _ in evgens[:-1]:
6276 self.assertEqual(_decode_path[:-1], decode_path)
6279 _decode_path, obj, tail = evgens[-1]
6280 self.assertEqual(_decode_path, decode_path)
6284 assert_exceeding_data(
6286 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
6290 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6291 @given(data_strategy())
6292 def test_symmetric_with_seq(self, d):
6293 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
6294 self.assertTrue(seq.ready)
6295 seq_encoded = seq.encode()
6296 self.assertEqual(encode2pass(seq), seq_encoded)
6297 seq_decoded, tail = seq.decode(seq_encoded)
6298 self.assertEqual(tail, b"")
6299 self.assertTrue(seq.ready)
6300 self.assertEqual(seq, seq_decoded)
6301 self.assertEqual(seq_decoded.encode(), seq_encoded)
6302 for expect_outer in expect_outers:
6303 if not expect_outer["presented"]:
6304 self.assertNotIn(expect_outer["name"], seq_decoded)
6306 self.assertIn(expect_outer["name"], seq_decoded)
6307 obj = seq_decoded[expect_outer["name"]]
6308 self.assertTrue(obj.decoded)
6309 offset = obj.expl_offset if obj.expled else obj.offset
6310 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6311 self.assertSequenceEqual(
6312 seq_encoded[offset:offset + tlvlen],
6315 self._assert_expects(obj, expect_outer["expects"])
6317 @given(data_strategy())
6318 def test_default_disappears(self, d):
6319 _schema = list(d.draw(dictionaries(
6321 sets(integers(), min_size=2, max_size=2),
6325 class Seq(self.base_klass):
6327 (n, Integer(default=d))
6328 for n, (_, d) in _schema
6331 for name, (value, _) in _schema:
6332 seq[name] = Integer(value)
6333 self.assertEqual(len(seq._value), len(_schema))
6334 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
6335 self.assertGreater(len(seq.encode()), len(empty_seq))
6336 for name, (_, default) in _schema:
6337 seq[name] = Integer(default)
6338 self.assertEqual(len(seq._value), 0)
6339 self.assertSequenceEqual(seq.encode(), empty_seq)
6341 @given(data_strategy())
6342 def test_encoded_default_not_accepted(self, d):
6343 _schema = list(d.draw(dictionaries(
6348 tags = [tag_encode(tag) for tag in d.draw(sets(
6349 integers(min_value=1),
6350 min_size=len(_schema),
6351 max_size=len(_schema),
6355 schema = (("int", Integer()),)
6357 class SeqWithoutDefault(self.base_klass):
6360 for (n, _), t in zip(_schema, tags)
6362 seq_without_default = SeqWithoutDefault()
6363 for name, value in _schema:
6364 seq_without_default[name] = Wahl(("int", Integer(value)))
6365 seq_encoded = seq_without_default.encode()
6366 seq_without_default.decode(seq_encoded)
6368 len(list(seq_without_default.decode_evgen(seq_encoded))),
6369 len(_schema) * 2 + 1,
6372 class SeqWithDefault(self.base_klass):
6374 (n, Wahl(default=Wahl(("int", Integer(v))), expl=t))
6375 for (n, v), t in zip(_schema, tags)
6377 seq_with_default = SeqWithDefault()
6378 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6379 seq_with_default.decode(seq_encoded)
6380 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6381 list(seq_with_default.decode_evgen(seq_encoded))
6382 for ctx in ({"bered": True}, {"allow_default_values": True}):
6383 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
6384 self.assertTrue(seq_decoded.ber_encoded)
6385 self.assertTrue(seq_decoded.bered)
6386 seq_decoded = copy(seq_decoded)
6387 self.assertTrue(seq_decoded.ber_encoded)
6388 self.assertTrue(seq_decoded.bered)
6389 for name, value in _schema:
6390 self.assertEqual(seq_decoded[name], seq_with_default[name])
6391 self.assertEqual(seq_decoded[name].value, value)
6393 len(list(seq_with_default.decode_evgen(seq_encoded, ctx=ctx))),
6397 seq_without_default = SeqWithoutDefault()
6398 for name, value in _schema:
6399 seq_without_default[name] = Wahl(("int", Integer(value + 1)))
6400 seq_encoded = seq_without_default.encode()
6401 seq_with_default.decode(seq_encoded)
6403 len(list(seq_with_default.decode_evgen(seq_encoded))),
6407 @given(data_strategy())
6408 def test_missing_from_spec(self, d):
6409 names = list(d.draw(sets(text_letters(), min_size=2)))
6410 tags = [tag_encode(tag) for tag in d.draw(sets(
6411 integers(min_value=1),
6412 min_size=len(names),
6413 max_size=len(names),
6415 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
6417 class SeqFull(self.base_klass):
6418 schema = [(n, Integer(impl=t)) for n, t in names_tags]
6419 seq_full = SeqFull()
6420 for i, name in enumerate(names):
6421 seq_full[name] = Integer(i)
6422 seq_encoded = seq_full.encode()
6423 altered = names_tags[:-2] + names_tags[-1:]
6425 class SeqMissing(self.base_klass):
6426 schema = [(n, Integer(impl=t)) for n, t in altered]
6427 seq_missing = SeqMissing()
6428 with self.assertRaises(TagMismatch):
6429 seq_missing.decode(seq_encoded)
6430 with self.assertRaises(TagMismatch):
6431 list(seq_missing.decode_evgen(seq_encoded))
6433 def test_bered(self):
6434 class Seq(self.base_klass):
6435 schema = (("underlying", Boolean()),)
6436 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
6437 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6438 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6439 self.assertFalse(decoded.ber_encoded)
6440 self.assertFalse(decoded.lenindef)
6441 self.assertTrue(decoded.bered)
6442 decoded = copy(decoded)
6443 self.assertFalse(decoded.ber_encoded)
6444 self.assertFalse(decoded.lenindef)
6445 self.assertTrue(decoded.bered)
6447 class Seq(self.base_klass):
6448 schema = (("underlying", OctetString()),)
6450 tag_encode(form=TagFormConstructed, num=4) +
6452 OctetString(b"whatever").encode() +
6455 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6456 with self.assertRaises(DecodeError):
6457 Seq().decode(encoded)
6458 with self.assertRaises(DecodeError):
6459 list(Seq().decode_evgen(encoded))
6460 list(Seq().decode_evgen(encoded, ctx={"bered": True}))
6461 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6462 self.assertFalse(decoded.ber_encoded)
6463 self.assertFalse(decoded.lenindef)
6464 self.assertTrue(decoded.bered)
6465 decoded = copy(decoded)
6466 self.assertFalse(decoded.ber_encoded)
6467 self.assertFalse(decoded.lenindef)
6468 self.assertTrue(decoded.bered)
6471 class TestSequence(SeqMixin, CommonMixin, TestCase):
6472 base_klass = Sequence
6478 def test_remaining(self, value, junk):
6479 class Seq(Sequence):
6481 ("whatever", Integer()),
6483 int_encoded = Integer(value).encode()
6485 Sequence.tag_default,
6486 len_encode(len(int_encoded + junk)),
6489 with self.assertRaisesRegex(DecodeError, "remaining"):
6490 Seq().decode(junked)
6492 @given(sets(text_letters(), min_size=2))
6493 def test_obj_unknown(self, names):
6494 missing = names.pop()
6496 class Seq(Sequence):
6497 schema = [(n, Boolean()) for n in names]
6499 with self.assertRaises(ObjUnknown) as err:
6502 with self.assertRaises(ObjUnknown) as err:
6503 seq[missing] = Boolean()
6506 def test_x690_vector(self):
6507 class Seq(Sequence):
6509 ("name", IA5String()),
6512 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
6513 self.assertEqual(seq["name"], "Smith")
6514 self.assertEqual(seq["ok"], True)
6517 class TestSet(SeqMixin, CommonMixin, TestCase):
6520 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6521 @given(data_strategy())
6522 def test_sorted(self, d):
6523 class DummySeq(Sequence):
6524 schema = (("null", Null()),)
6526 tag_nums = d.draw(sets(integers(min_value=1), min_size=1, max_size=50))
6527 _, _, dummy_seq_tag_num = tag_decode(DummySeq.tag_default)
6528 assume(any(i > dummy_seq_tag_num for i in tag_nums))
6529 tag_nums -= set([dummy_seq_tag_num])
6530 _schema = [(str(i), OctetString(impl=tag_encode(i))) for i in tag_nums]
6531 _schema.append(("seq", DummySeq()))
6534 schema = d.draw(permutations(_schema))
6536 for name, _ in _schema:
6538 seq[name] = OctetString(name.encode("ascii"))
6539 seq["seq"] = DummySeq((("null", Null()),))
6541 seq_encoded = seq.encode()
6542 seq_decoded, _ = seq.decode(seq_encoded)
6543 seq_encoded_expected = []
6544 for tag_num in sorted(tag_nums | set([dummy_seq_tag_num])):
6545 if tag_num == dummy_seq_tag_num:
6546 seq_encoded_expected.append(seq["seq"].encode())
6548 seq_encoded_expected.append(seq[str(tag_num)].encode())
6549 self.assertSequenceEqual(
6550 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6551 b"".join(seq_encoded_expected),
6554 encoded = b"".join(seq[str(i)].encode() for i in tag_nums)
6555 encoded += seq["seq"].encode()
6556 seq_encoded = b"".join((
6558 len_encode(len(encoded)),
6561 with self.assertRaisesRegex(DecodeError, "unordered SET"):
6562 seq.decode(seq_encoded)
6563 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6564 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6565 self.assertTrue(seq_decoded.ber_encoded)
6566 self.assertTrue(seq_decoded.bered)
6567 seq_decoded = copy(seq_decoded)
6568 self.assertTrue(seq_decoded.ber_encoded)
6569 self.assertTrue(seq_decoded.bered)
6571 def test_same_value_twice(self):
6574 ("bool", Boolean()),
6578 encoded = b"".join((
6579 Integer(123).encode(),
6580 Integer(234).encode(),
6581 Boolean(True).encode(),
6583 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6584 with self.assertRaises(TagMismatch):
6585 Seq().decod(encoded, ctx={"allow_unordered_set": True})
6589 def seqof_values_strategy(draw, schema=None, do_expl=False):
6591 schema = draw(sampled_from((Boolean(), Integer())))
6592 bound_min, bound_max = sorted(draw(sets(
6593 integers(min_value=0, max_value=10),
6597 if isinstance(schema, Boolean):
6598 values_generator = booleans().map(Boolean)
6599 elif isinstance(schema, Integer):
6600 values_generator = integers().map(Integer)
6601 values_generator = lists(
6606 values = draw(one_of(none(), values_generator))
6610 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6612 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6613 default = draw(one_of(none(), values_generator))
6614 optional = draw(one_of(none(), booleans()))
6616 draw(integers(min_value=0)),
6617 draw(integers(min_value=0)),
6618 draw(integers(min_value=0)),
6623 (bound_min, bound_max),
6632 class SeqOfMixin(object):
6633 def test_invalid_value_type(self):
6634 with self.assertRaises(InvalidValueType) as err:
6635 self.base_klass(123)
6638 def test_invalid_values_type(self):
6639 class SeqOf(self.base_klass):
6641 with self.assertRaises(InvalidValueType) as err:
6642 SeqOf([Integer(123), Boolean(False), Integer(234)])
6645 def test_schema_required(self):
6646 with self.assertRaisesRegex(ValueError, "schema must be specified"):
6647 self.base_klass.__mro__[1]()
6649 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6650 def test_comparison(self, value1, value2, tag1, tag2):
6651 class SeqOf(self.base_klass):
6653 obj1 = SeqOf([Boolean(value1)])
6654 obj2 = SeqOf([Boolean(value2)])
6655 self.assertEqual(obj1 == obj2, value1 == value2)
6656 self.assertEqual(obj1 != obj2, value1 != value2)
6657 self.assertEqual(obj1 == list(obj2), value1 == value2)
6658 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6659 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6660 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6661 self.assertEqual(obj1 == obj2, tag1 == tag2)
6662 self.assertEqual(obj1 != obj2, tag1 != tag2)
6664 @given(lists(booleans()))
6665 def test_iter(self, values):
6666 class SeqOf(self.base_klass):
6668 obj = SeqOf([Boolean(value) for value in values])
6669 self.assertEqual(len(obj), len(values))
6670 for i, value in enumerate(obj):
6671 self.assertEqual(value, values[i])
6673 @given(data_strategy())
6674 def test_ready(self, d):
6675 ready = [Integer(v) for v in d.draw(lists(
6682 range(d.draw(integers(min_value=1, max_value=5)))
6685 class SeqOf(self.base_klass):
6687 values = d.draw(permutations(ready + non_ready))
6689 for value in values:
6691 self.assertFalse(seqof.ready)
6694 pprint(seqof, big_blobs=True, with_decode_path=True)
6695 with self.assertRaises(ObjNotReady) as err:
6698 with self.assertRaises(ObjNotReady) as err:
6700 for i, value in enumerate(values):
6701 self.assertEqual(seqof[i], value)
6702 if not seqof[i].ready:
6703 seqof[i] = Integer(i)
6704 self.assertTrue(seqof.ready)
6707 pprint(seqof, big_blobs=True, with_decode_path=True)
6709 def test_spec_mismatch(self):
6710 class SeqOf(self.base_klass):
6713 seqof.append(Integer(123))
6714 with self.assertRaises(ValueError):
6715 seqof.append(Boolean(False))
6716 with self.assertRaises(ValueError):
6717 seqof[0] = Boolean(False)
6719 @given(data_strategy())
6720 def test_bounds_satisfied(self, d):
6721 class SeqOf(self.base_klass):
6723 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6724 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6725 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6726 SeqOf(value=value, bounds=(bound_min, bound_max))
6728 @given(data_strategy())
6729 def test_bounds_unsatisfied(self, d):
6730 class SeqOf(self.base_klass):
6732 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6733 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6734 value = [Boolean(False)] * d.draw(integers(min_value=0, max_value=bound_min - 1))
6735 with self.assertRaises(BoundsError) as err:
6736 SeqOf(value=value, bounds=(bound_min, bound_max))
6738 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6739 SeqOf(bounds=(bound_min, bound_max)).decode(
6740 SeqOf(value).encode()
6743 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6744 SeqOf(bounds=(bound_min, bound_max)).decode(
6745 encode2pass(SeqOf(value))
6747 value = [Boolean(True)] * d.draw(integers(
6748 min_value=bound_max + 1,
6749 max_value=bound_max + 10,
6751 with self.assertRaises(BoundsError) as err:
6752 SeqOf(value=value, bounds=(bound_min, bound_max))
6754 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6755 SeqOf(bounds=(bound_min, bound_max)).decode(
6756 SeqOf(value).encode()
6759 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6760 SeqOf(bounds=(bound_min, bound_max)).decode(
6761 encode2pass(SeqOf(value))
6764 @given(integers(min_value=1, max_value=10))
6765 def test_out_of_bounds(self, bound_max):
6766 class SeqOf(self.base_klass):
6768 bounds = (0, bound_max)
6770 for _ in range(bound_max):
6771 seqof.append(Integer(123))
6772 with self.assertRaises(BoundsError):
6773 seqof.append(Integer(123))
6775 @given(data_strategy())
6776 def test_call(self, d):
6786 ) = d.draw(seqof_values_strategy())
6788 class SeqOf(self.base_klass):
6789 schema = schema_initial
6790 obj_initial = SeqOf(
6791 value=value_initial,
6792 bounds=bounds_initial,
6795 default=default_initial,
6796 optional=optional_initial or False,
6797 _decoded=_decoded_initial,
6808 ) = d.draw(seqof_values_strategy(
6809 schema=schema_initial,
6810 do_expl=impl_initial is None,
6812 if (default is None) and (obj_initial.default is not None):
6815 (bounds is None) and
6816 (value is not None) and
6817 (bounds_initial is not None) and
6818 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6822 (bounds is None) and
6823 (default is not None) and
6824 (bounds_initial is not None) and
6825 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6837 value_expected = default if value is None else value
6839 default_initial if value_expected is None
6842 value_expected = () if value_expected is None else value_expected
6843 self.assertEqual(obj, value_expected)
6844 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6845 self.assertEqual(obj.expl_tag, expl or expl_initial)
6848 default_initial if default is None else default,
6850 if obj.default is None:
6851 optional = optional_initial if optional is None else optional
6852 optional = False if optional is None else optional
6855 self.assertEqual(obj.optional, optional)
6857 (obj._bound_min, obj._bound_max),
6858 bounds or bounds_initial or (0, float("+inf")),
6861 @given(seqof_values_strategy())
6862 def test_copy(self, values):
6863 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6865 class SeqOf(self.base_klass):
6867 register_class(SeqOf)
6874 optional=optional or False,
6877 for copy_func in copy_funcs:
6878 obj_copied = copy_func(obj)
6879 self.assert_copied_basic_fields(obj, obj_copied)
6880 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6881 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6882 self.assertEqual(obj._value, obj_copied._value)
6886 integers(min_value=1).map(tag_encode),
6888 def test_stripped(self, values, tag_impl):
6889 class SeqOf(self.base_klass):
6890 schema = OctetString()
6891 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6892 with self.assertRaises(NotEnoughData):
6893 obj.decode(obj.encode()[:-1])
6897 integers(min_value=1).map(tag_ctxc),
6899 def test_stripped_expl(self, values, tag_expl):
6900 class SeqOf(self.base_klass):
6901 schema = OctetString()
6902 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6903 with self.assertRaises(NotEnoughData):
6904 obj.decode(obj.encode()[:-1])
6907 integers(min_value=31),
6908 integers(min_value=0),
6911 def test_bad_tag(self, tag, offset, decode_path):
6912 with self.assertRaises(DecodeError) as err:
6913 self.base_klass().decode(
6914 tag_encode(tag)[:-1],
6916 decode_path=decode_path,
6919 self.assertEqual(err.exception.offset, offset)
6920 self.assertEqual(err.exception.decode_path, decode_path)
6923 integers(min_value=128),
6924 integers(min_value=0),
6927 def test_bad_len(self, l, offset, decode_path):
6928 with self.assertRaises(DecodeError) as err:
6929 self.base_klass().decode(
6930 self.base_klass.tag_default + len_encode(l)[:-1],
6932 decode_path=decode_path,
6935 self.assertEqual(err.exception.offset, offset)
6936 self.assertEqual(err.exception.decode_path, decode_path)
6938 @given(binary(min_size=1))
6939 def test_tag_mismatch(self, impl):
6940 assume(impl != self.base_klass.tag_default)
6941 with self.assertRaises(TagMismatch):
6942 self.base_klass(impl=impl).decode(self.base_klass().encode())
6944 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6946 seqof_values_strategy(schema=Integer()),
6947 lists(integers().map(Integer)),
6948 integers(min_value=1).map(tag_ctxc),
6949 integers(min_value=0),
6953 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
6954 _, _, _, _, _, default, optional, _decoded = values
6956 class SeqOf(self.base_klass):
6966 pprint(obj, big_blobs=True, with_decode_path=True)
6967 self.assertFalse(obj.expled)
6968 obj_encoded = obj.encode()
6969 self.assertEqual(encode2pass(obj), obj_encoded)
6970 obj_encoded_cer = encode_cer(obj)
6971 self.assertNotEqual(obj_encoded_cer, obj_encoded)
6972 self.assertSequenceEqual(
6973 obj.decod(obj_encoded_cer, ctx={"bered": True}).encode(),
6976 obj_expled = obj(value, expl=tag_expl)
6977 self.assertTrue(obj_expled.expled)
6979 list(obj_expled.pps())
6980 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6981 obj_expled_encoded = obj_expled.encode()
6982 ctx_copied = deepcopy(ctx_dummy)
6983 obj_decoded, tail = obj_expled.decode(
6984 obj_expled_encoded + tail_junk,
6988 self.assertDictEqual(ctx_copied, ctx_dummy)
6990 list(obj_decoded.pps())
6991 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6992 self.assertEqual(tail, tail_junk)
6993 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6994 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6995 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6996 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6998 obj_decoded.expl_llen,
6999 len(len_encode(len(obj_encoded))),
7001 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
7002 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
7005 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
7007 self.assertEqual(obj_decoded.expl_offset, offset)
7008 for obj_inner in obj_decoded:
7009 self.assertIn(obj_inner, obj_decoded)
7010 self.assertSequenceEqual(
7013 obj_inner.offset - offset:
7014 obj_inner.offset + obj_inner.tlvlen - offset
7018 t, _, lv = tag_strip(obj_encoded)
7019 _, _, v = len_decode(lv)
7020 obj_encoded_lenindef = t + LENINDEF + v + EOC
7021 with self.assertRaises(DecodeError):
7022 obj.decode(obj_encoded_lenindef)
7023 obj_decoded_lenindef, tail_lenindef = obj.decode(
7024 obj_encoded_lenindef + tail_junk,
7025 ctx={"bered": True},
7027 self.assertTrue(obj_decoded_lenindef.lenindef)
7028 self.assertTrue(obj_decoded_lenindef.bered)
7029 obj_decoded_lenindef = copy(obj_decoded_lenindef)
7030 self.assertTrue(obj_decoded_lenindef.lenindef)
7031 self.assertTrue(obj_decoded_lenindef.bered)
7032 repr(obj_decoded_lenindef)
7033 list(obj_decoded_lenindef.pps())
7034 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
7035 self.assertEqual(tail_lenindef, tail_junk)
7036 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
7037 with self.assertRaises(DecodeError):
7038 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
7039 with self.assertRaises(DecodeError):
7040 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
7042 evgens = list(obj.decode_evgen(
7043 obj_encoded_lenindef + tail_junk,
7044 decode_path=decode_path,
7045 ctx={"bered": True},
7047 self.assertEqual(len(evgens), len(obj_decoded_lenindef) + 1)
7048 for i, (_decode_path, obj, _) in enumerate(evgens[:-1]):
7049 self.assertEqual(_decode_path, decode_path + (str(i),))
7052 _decode_path, obj, tail = evgens[-1]
7053 self.assertEqual(_decode_path, decode_path)
7057 assert_exceeding_data(
7059 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
7063 def test_bered(self):
7064 class SeqOf(self.base_klass):
7066 encoded = Boolean(False).encode()
7067 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
7068 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7069 with self.assertRaises(DecodeError):
7070 SeqOf().decode(encoded)
7071 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7072 self.assertFalse(decoded.ber_encoded)
7073 self.assertFalse(decoded.lenindef)
7074 self.assertTrue(decoded.bered)
7075 decoded = copy(decoded)
7076 self.assertFalse(decoded.ber_encoded)
7077 self.assertFalse(decoded.lenindef)
7078 self.assertTrue(decoded.bered)
7080 class SeqOf(self.base_klass):
7081 schema = OctetString()
7082 encoded = OctetString(b"whatever").encode()
7084 tag_encode(form=TagFormConstructed, num=4) +
7086 OctetString(b"whatever").encode() +
7089 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7090 with self.assertRaises(DecodeError):
7091 SeqOf().decode(encoded)
7092 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7093 self.assertFalse(decoded.ber_encoded)
7094 self.assertFalse(decoded.lenindef)
7095 self.assertTrue(decoded.bered)
7096 decoded = copy(decoded)
7097 self.assertFalse(decoded.ber_encoded)
7098 self.assertFalse(decoded.lenindef)
7099 self.assertTrue(decoded.bered)
7102 class TestSequenceOf(SeqOfMixin, CommonMixin, TestCase):
7103 class SeqOf(SequenceOf):
7107 def _test_symmetric_compare_objs(self, obj1, obj2):
7108 self.assertEqual(obj1, obj2)
7109 self.assertSequenceEqual(list(obj1), list(obj2))
7111 def test_iterator_pickling(self):
7112 class SeqOf(SequenceOf):
7114 register_class(SeqOf)
7117 seqof = seqof(iter(range(10)))
7118 with self.assertRaisesRegex(ValueError, "iterator"):
7121 def test_iterator_bounds(self):
7122 class SeqOf(SequenceOf):
7131 seqof = SeqOf(gen(n))
7132 self.assertTrue(seqof.ready)
7133 with self.assertRaises(BoundsError):
7135 self.assertFalse(seqof.ready)
7136 seqof = seqof(gen(n))
7137 self.assertTrue(seqof.ready)
7138 with self.assertRaises(BoundsError):
7140 self.assertFalse(seqof.ready)
7142 def test_iterator_twice(self):
7143 class SeqOf(SequenceOf):
7145 bounds = (1, float("+inf"))
7150 seqof = SeqOf(gen())
7151 self.assertTrue(seqof.ready)
7153 self.assertFalse(seqof.ready)
7154 register_class(SeqOf)
7157 def test_iterator_2pass(self):
7158 class SeqOf(SequenceOf):
7160 bounds = (1, float("+inf"))
7165 seqof = SeqOf(gen())
7166 self.assertTrue(seqof.ready)
7167 _, state = seqof.encode1st()
7168 self.assertFalse(seqof.ready)
7169 seqof = seqof(gen())
7170 self.assertTrue(seqof.ready)
7172 seqof.encode2nd(buf.write, iter(state))
7173 self.assertSequenceEqual(
7174 [int(i) for i in seqof.decod(buf.getvalue())],
7178 def test_non_ready_bound_min(self):
7179 class SeqOf(SequenceOf):
7181 bounds = (1, float("+inf"))
7183 self.assertFalse(seqof.ready)
7186 class TestSetOf(SeqOfMixin, CommonMixin, TestCase):
7191 def _test_symmetric_compare_objs(self, obj1, obj2):
7192 self.assertSetEqual(
7193 set(int(v) for v in obj1),
7194 set(int(v) for v in obj2),
7197 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7198 @given(data_strategy())
7199 def test_sorted(self, d):
7200 values = [OctetString(v) for v in d.draw(lists(binary()))]
7203 schema = OctetString()
7205 seq_encoded = seq.encode()
7206 seq_decoded, _ = seq.decode(seq_encoded)
7207 self.assertSequenceEqual(
7208 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
7209 b"".join(sorted([v.encode() for v in values])),
7212 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7213 @given(data_strategy())
7214 def test_unsorted(self, d):
7215 values = [OctetString(v).encode() for v in d.draw(sets(
7216 binary(min_size=1, max_size=5),
7220 values = d.draw(permutations(values))
7221 assume(values != sorted(values))
7222 encoded = b"".join(values)
7223 seq_encoded = b"".join((
7225 len_encode(len(encoded)),
7230 schema = OctetString()
7232 with self.assertRaisesRegex(DecodeError, "unordered SET OF"):
7233 seq.decode(seq_encoded)
7235 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
7236 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
7237 self.assertTrue(seq_decoded.ber_encoded)
7238 self.assertTrue(seq_decoded.bered)
7239 seq_decoded = copy(seq_decoded)
7240 self.assertTrue(seq_decoded.ber_encoded)
7241 self.assertTrue(seq_decoded.bered)
7242 self.assertSequenceEqual(
7243 [obj.encode() for obj in seq_decoded],
7248 class TestGoMarshalVectors(TestCase):
7250 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
7251 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
7252 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
7253 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
7254 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
7256 class Seq(Sequence):
7258 ("erste", Integer()),
7259 ("zweite", Integer(optional=True))
7262 seq["erste"] = Integer(64)
7263 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7264 seq["erste"] = Integer(0x123456)
7265 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
7266 seq["erste"] = Integer(64)
7267 seq["zweite"] = Integer(65)
7268 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
7270 class NestedSeq(Sequence):
7274 seq["erste"] = Integer(127)
7275 seq["zweite"] = None
7276 nested = NestedSeq()
7277 nested["nest"] = seq
7278 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
7280 self.assertSequenceEqual(
7281 OctetString(b"\x01\x02\x03").encode(),
7282 hexdec("0403010203"),
7285 class Seq(Sequence):
7287 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
7290 seq["erste"] = Integer(64)
7291 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
7293 class Seq(Sequence):
7295 ("erste", Integer(expl=tag_ctxc(5))),
7298 seq["erste"] = Integer(64)
7299 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
7301 class Seq(Sequence):
7304 impl=tag_encode(0, klass=TagClassContext),
7309 seq["erste"] = Null()
7310 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
7312 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7314 self.assertSequenceEqual(
7315 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
7316 hexdec("170d3730303130313030303030305a"),
7318 self.assertSequenceEqual(
7319 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
7320 hexdec("170d3039313131353232353631365a"),
7322 self.assertSequenceEqual(
7323 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
7324 hexdec("180f32313030303430353132303130315a"),
7327 class Seq(Sequence):
7329 ("erste", GeneralizedTime()),
7332 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
7333 self.assertSequenceEqual(
7335 hexdec("3011180f32303039313131353232353631365a"),
7338 self.assertSequenceEqual(
7339 BitString((1, b"\x80")).encode(),
7342 self.assertSequenceEqual(
7343 BitString((12, b"\x81\xF0")).encode(),
7344 hexdec("03030481f0"),
7347 self.assertSequenceEqual(
7348 ObjectIdentifier("1.2.3.4").encode(),
7349 hexdec("06032a0304"),
7351 self.assertSequenceEqual(
7352 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
7353 hexdec("06092a864888932d010105"),
7355 self.assertSequenceEqual(
7356 ObjectIdentifier("2.100.3").encode(),
7357 hexdec("0603813403"),
7360 self.assertSequenceEqual(
7361 PrintableString("test").encode(),
7362 hexdec("130474657374"),
7364 self.assertSequenceEqual(
7365 PrintableString("x" * 127).encode(),
7366 hexdec("137F" + "78" * 127),
7368 self.assertSequenceEqual(
7369 PrintableString("x" * 128).encode(),
7370 hexdec("138180" + "78" * 128),
7372 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
7374 class Seq(Sequence):
7376 ("erste", IA5String()),
7379 seq["erste"] = IA5String("test")
7380 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
7382 class Seq(Sequence):
7384 ("erste", PrintableString()),
7387 seq["erste"] = PrintableString("test")
7388 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
7389 # Asterisk is actually not allowable
7390 pyderasn.PRINTABLE_ALLOWABLE_CHARS |= set(b"*")
7391 seq["erste"] = PrintableString("test*")
7392 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
7393 pyderasn.PRINTABLE_ALLOWABLE_CHARS -= set(b"*")
7395 class Seq(Sequence):
7397 ("erste", Any(optional=True)),
7398 ("zweite", Integer()),
7401 seq["zweite"] = Integer(64)
7402 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7407 seq.append(Integer(10))
7408 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
7410 class _SeqOf(SequenceOf):
7411 schema = PrintableString()
7413 class SeqOf(SequenceOf):
7416 _seqof.append(PrintableString("1"))
7418 seqof.append(_seqof)
7419 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
7421 class Seq(Sequence):
7423 ("erste", Integer(default=1)),
7426 seq["erste"] = Integer(0)
7427 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
7428 seq["erste"] = Integer(1)
7429 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7430 seq["erste"] = Integer(2)
7431 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
7434 class TestPP(TestCase):
7435 @given(data_strategy())
7436 def test_oid_printing(self, d):
7438 str(ObjectIdentifier(k)): v * 2
7439 for k, v in d.draw(dictionaries(
7445 chosen = d.draw(sampled_from(sorted(oids)))
7446 chosen_id = oids[chosen]
7447 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
7448 self.assertNotIn(chosen_id, pp_console_row(pp))
7451 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
7455 class TestAutoAddSlots(TestCase):
7457 class Inher(Integer):
7460 with self.assertRaises(AttributeError):
7462 inher.unexistent = "whatever"
7465 class TestOIDDefines(TestCase):
7466 @given(data_strategy())
7467 def runTest(self, d):
7468 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
7469 value_name_chosen = d.draw(sampled_from(value_names))
7471 ObjectIdentifier(oid)
7472 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
7474 oid_chosen = d.draw(sampled_from(oids))
7475 values = d.draw(lists(
7477 min_size=len(value_names),
7478 max_size=len(value_names),
7480 for definable_class in (Any, OctetString, BitString):
7482 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
7483 oid: Integer() for oid in oids[:-1]
7486 for i, value_name in enumerate(value_names):
7487 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
7489 class Seq(Sequence):
7492 for value_name, value in zip(value_names, values):
7493 seq[value_name] = definable_class(Integer(value).encode())
7494 seq["type"] = oid_chosen
7495 seq, _ = Seq().decode(seq.encode())
7496 for value_name in value_names:
7497 if value_name == value_name_chosen:
7499 self.assertIsNone(seq[value_name].defined)
7500 if value_name_chosen in oids[:-1]:
7501 self.assertIsNotNone(seq[value_name_chosen].defined)
7502 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
7503 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
7506 pprint(seq, big_blobs=True, with_decode_path=True)
7509 class TestDefinesByPath(TestCase):
7510 def test_generated(self):
7511 class Seq(Sequence):
7513 ("type", ObjectIdentifier()),
7514 ("value", OctetString(expl=tag_ctxc(123))),
7517 class SeqInner(Sequence):
7519 ("typeInner", ObjectIdentifier()),
7520 ("valueInner", Any()),
7523 class PairValue(SetOf):
7526 class Pair(Sequence):
7528 ("type", ObjectIdentifier()),
7529 ("value", PairValue()),
7532 class Pairs(SequenceOf):
7539 type_octet_stringed,
7541 ObjectIdentifier(oid)
7542 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
7544 seq_integered = Seq()
7545 seq_integered["type"] = type_integered
7546 seq_integered["value"] = OctetString(Integer(123).encode())
7547 seq_integered_raw = seq_integered.encode()
7551 (type_octet_stringed, OctetString(b"whatever")),
7552 (type_integered, Integer(123)),
7553 (type_octet_stringed, OctetString(b"whenever")),
7554 (type_integered, Integer(234)),
7556 for t, v in pairs_input:
7559 ("value", PairValue((Any(v),))),
7561 seq_inner = SeqInner()
7562 seq_inner["typeInner"] = type_innered
7563 seq_inner["valueInner"] = Any(pairs)
7564 seq_sequenced = Seq()
7565 seq_sequenced["type"] = type_sequenced
7566 seq_sequenced["value"] = OctetString(seq_inner.encode())
7567 seq_sequenced_raw = seq_sequenced.encode()
7569 list(seq_sequenced.pps())
7570 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7572 defines_by_path = []
7573 ctx_copied = deepcopy(ctx_dummy)
7574 seq_integered, _ = Seq().decode(
7578 self.assertDictEqual(ctx_copied, ctx_dummy)
7579 self.assertIsNone(seq_integered["value"].defined)
7580 defines_by_path.append(
7581 (("type",), ((("value",), {
7582 type_integered: Integer(),
7583 type_sequenced: SeqInner(),
7586 ctx_copied["defines_by_path"] = defines_by_path
7587 seq_integered, _ = Seq().decode(
7591 del ctx_copied["defines_by_path"]
7592 self.assertDictEqual(ctx_copied, ctx_dummy)
7593 self.assertIsNotNone(seq_integered["value"].defined)
7594 self.assertEqual(seq_integered["value"].defined[0], type_integered)
7595 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
7596 self.assertTrue(seq_integered_raw[
7597 seq_integered["value"].defined[1].offset:
7598 ].startswith(Integer(123).encode()))
7600 list(seq_integered.pps())
7601 pprint(seq_integered, big_blobs=True, with_decode_path=True)
7603 ctx_copied["defines_by_path"] = defines_by_path
7604 seq_sequenced, _ = Seq().decode(
7608 del ctx_copied["defines_by_path"]
7609 self.assertDictEqual(ctx_copied, ctx_dummy)
7610 self.assertIsNotNone(seq_sequenced["value"].defined)
7611 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7612 seq_inner = seq_sequenced["value"].defined[1]
7613 self.assertIsNone(seq_inner["valueInner"].defined)
7615 list(seq_sequenced.pps())
7616 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7618 defines_by_path.append((
7619 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
7620 ((("valueInner",), {type_innered: Pairs()}),),
7622 ctx_copied["defines_by_path"] = defines_by_path
7623 seq_sequenced, _ = Seq().decode(
7627 del ctx_copied["defines_by_path"]
7628 self.assertDictEqual(ctx_copied, ctx_dummy)
7629 self.assertIsNotNone(seq_sequenced["value"].defined)
7630 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7631 seq_inner = seq_sequenced["value"].defined[1]
7632 self.assertIsNotNone(seq_inner["valueInner"].defined)
7633 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7634 pairs = seq_inner["valueInner"].defined[1]
7636 self.assertIsNone(pair["value"][0].defined)
7638 list(seq_sequenced.pps())
7639 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7641 defines_by_path.append((
7644 DecodePathDefBy(type_sequenced),
7646 DecodePathDefBy(type_innered),
7651 type_integered: Integer(),
7652 type_octet_stringed: OctetString(),
7655 ctx_copied["defines_by_path"] = defines_by_path
7656 seq_sequenced, _ = Seq().decode(
7660 del ctx_copied["defines_by_path"]
7661 self.assertDictEqual(ctx_copied, ctx_dummy)
7662 self.assertIsNotNone(seq_sequenced["value"].defined)
7663 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7664 seq_inner = seq_sequenced["value"].defined[1]
7665 self.assertIsNotNone(seq_inner["valueInner"].defined)
7666 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7667 pairs_got = seq_inner["valueInner"].defined[1]
7668 for pair_input, pair_got in zip(pairs_input, pairs_got):
7669 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7670 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7672 list(seq_sequenced.pps())
7673 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7675 @given(oid_strategy(), integers())
7676 def test_simple(self, oid, tgt):
7677 class Inner(Sequence):
7679 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7680 ObjectIdentifier(oid): Integer(),
7684 class Outer(Sequence):
7687 ("tgt", OctetString()),
7691 inner["oid"] = ObjectIdentifier(oid)
7693 outer["inner"] = inner
7694 outer["tgt"] = OctetString(Integer(tgt).encode())
7695 decoded, _ = Outer().decode(outer.encode())
7696 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7698 def test_remaining_data(self):
7699 oid = ObjectIdentifier("1.2.3")
7701 class Seq(Sequence):
7703 ("oid", ObjectIdentifier(defines=((("tgt",), {
7706 ("tgt", OctetString()),
7711 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7713 with self.assertRaisesRegex(DecodeError, "remaining data"):
7714 Seq().decode(seq.encode())
7716 def test_remaining_data_seqof(self):
7717 oid = ObjectIdentifier("1.2.3")
7720 schema = OctetString()
7722 class Seq(Sequence):
7724 ("oid", ObjectIdentifier(defines=((("tgt",), {
7732 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7734 with self.assertRaisesRegex(DecodeError, "remaining data"):
7735 Seq().decode(seq.encode())
7738 class TestAbsDecodePath(TestCase):
7740 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7741 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7743 def test_concat(self, decode_path, rel_path):
7744 dp = abs_decode_path(decode_path, rel_path)
7745 self.assertSequenceEqual(dp, decode_path + rel_path)
7749 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7750 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7752 def test_abs(self, decode_path, rel_path):
7753 self.assertSequenceEqual(
7754 abs_decode_path(decode_path, ("/",) + rel_path),
7759 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7760 integers(min_value=1, max_value=3),
7761 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7763 def test_dots(self, decode_path, number_of_dots, rel_path):
7764 self.assertSequenceEqual(
7765 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7766 decode_path[:-number_of_dots] + rel_path,
7770 class TestStrictDefaultExistence(TestCase):
7771 @given(data_strategy())
7772 def runTest(self, d):
7773 count = d.draw(integers(min_value=1, max_value=10))
7774 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7776 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7777 for i in range(count)
7779 for klass in (Sequence, Set):
7783 for i in range(count):
7784 seq["int%d" % i] = Integer(123)
7786 chosen_choice = "int%d" % chosen
7787 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7788 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
7790 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7791 self.assertTrue(decoded.ber_encoded)
7792 self.assertTrue(decoded.bered)
7793 decoded = copy(decoded)
7794 self.assertTrue(decoded.ber_encoded)
7795 self.assertTrue(decoded.bered)
7796 decoded, _ = seq.decode(raw, ctx={"bered": True})
7797 self.assertTrue(decoded.ber_encoded)
7798 self.assertTrue(decoded.bered)
7799 decoded = copy(decoded)
7800 self.assertTrue(decoded.ber_encoded)
7801 self.assertTrue(decoded.bered)
7804 class TestX690PrefixedType(TestCase):
7806 self.assertSequenceEqual(
7807 VisibleString("Jones").encode(),
7808 hexdec("1A054A6F6E6573"),
7812 self.assertSequenceEqual(
7815 impl=tag_encode(3, klass=TagClassApplication),
7817 hexdec("43054A6F6E6573"),
7821 self.assertSequenceEqual(
7825 impl=tag_encode(3, klass=TagClassApplication),
7829 hexdec("A20743054A6F6E6573"),
7833 self.assertSequenceEqual(
7837 impl=tag_encode(3, klass=TagClassApplication),
7839 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7841 hexdec("670743054A6F6E6573"),
7845 self.assertSequenceEqual(
7846 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7847 hexdec("82054A6F6E6573"),
7851 class TestExplOOB(TestCase):
7853 expl = tag_ctxc(123)
7854 raw = Integer(123).encode() + Integer(234).encode()
7855 raw = b"".join((expl, len_encode(len(raw)), raw))
7856 with self.assertRaisesRegex(DecodeError, "explicit tag out-of-bound"):
7857 Integer(expl=expl).decode(raw)
7858 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7861 class TestPickleDifferentVersion(TestCase):
7863 pickled = pickle_dumps(Integer(123), pickle_proto)
7865 version_orig = pyderasn.__version__
7866 pyderasn.__version__ += "different"
7867 with self.assertRaisesRegex(ValueError, "different PyDERASN version"):
7868 pickle_loads(pickled)
7869 pyderasn.__version__ = version_orig
7870 pickle_loads(pickled)
7873 class TestCERSetOrdering(TestCase):
7874 def test_vectors(self):
7875 """Taken from X.690-201508
7879 ("c", Integer(impl=tag_ctxp(2))),
7880 ("d", Integer(impl=tag_ctxp(4))),
7885 ("g", Integer(impl=tag_ctxp(5))),
7886 ("h", Integer(impl=tag_ctxp(6))),
7891 ("j", Integer(impl=tag_ctxp(0))),
7902 ("a", Integer(impl=tag_ctxp(3))),
7903 ("b", B(expl=tag_ctxc(1))),
7908 ("a", Integer(123)),
7909 ("b", B(("d", Integer(234)))),
7910 ("e", E(("f", F(("g", Integer(345)))))),
7912 order = sorted(a._values_for_encoding(), key=attrgetter("tag_order_cer"))
7913 self.assertSequenceEqual(
7914 [i.__class__.__name__ for i in order],
7915 ("E", "B", "Integer"),