2 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures
3 # Copyright (C) 2017-2021 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, version 3 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this program. If not, see
16 # <http://www.gnu.org/licenses/>.
19 from copy import deepcopy
20 from datetime import datetime
21 from datetime import timedelta
22 from importlib import import_module
23 from io import BytesIO
24 from operator import attrgetter
25 from os import environ
26 from os import urandom
27 from random import random
28 from string import ascii_letters
29 from string import digits
30 from string import printable
31 from string import whitespace
32 from time import mktime
34 from unittest import TestCase
35 from unittest.mock import patch
37 from dateutil.tz import tzutc
38 from dateutil.tz import UTC
39 from hypothesis import assume
40 from hypothesis import given
41 from hypothesis import settings
42 from hypothesis.strategies import binary
43 from hypothesis.strategies import booleans
44 from hypothesis.strategies import composite
45 from hypothesis.strategies import data as data_strategy
46 from hypothesis.strategies import datetimes
47 from hypothesis.strategies import dictionaries
48 from hypothesis.strategies import integers
49 from hypothesis.strategies import just
50 from hypothesis.strategies import lists
51 from hypothesis.strategies import none
52 from hypothesis.strategies import one_of
53 from hypothesis.strategies import permutations
54 from hypothesis.strategies import sampled_from
55 from hypothesis.strategies import sets
56 from hypothesis.strategies import text
57 from hypothesis.strategies import tuples
58 from pickle import dumps as pickle_dumps
59 from pickle import HIGHEST_PROTOCOL as pickle_proto
60 from pickle import loads as pickle_loads
62 from pyderasn import _pp
63 from pyderasn import abs_decode_path
64 from pyderasn import Any
65 from pyderasn import BitString
66 from pyderasn import BMPString
67 from pyderasn import Boolean
68 from pyderasn import BoundsError
69 from pyderasn import Choice
70 from pyderasn import DecodeError
71 from pyderasn import DecodePathDefBy
72 from pyderasn import encode2pass
73 from pyderasn import encode_cer
74 from pyderasn import Enumerated
75 from pyderasn import EOC
76 from pyderasn import EOC_LEN
77 from pyderasn import ExceedingData
78 from pyderasn import GeneralizedTime
79 from pyderasn import GeneralString
80 from pyderasn import GraphicString
81 from pyderasn import hexdec
82 from pyderasn import hexenc
83 from pyderasn import IA5String
84 from pyderasn import Integer
85 from pyderasn import InvalidLength
86 from pyderasn import InvalidOID
87 from pyderasn import InvalidValueType
88 from pyderasn import len_decode
89 from pyderasn import len_encode
90 from pyderasn import LEN_YYMMDDHHMMSSZ
91 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
92 from pyderasn import LEN_YYYYMMDDHHMMSSZ
93 from pyderasn import LENINDEF
94 from pyderasn import LenIndefForm
95 from pyderasn import NotEnoughData
96 from pyderasn import Null
97 from pyderasn import NumericString
98 from pyderasn import ObjectIdentifier
99 from pyderasn import ObjNotReady
100 from pyderasn import ObjUnknown
101 from pyderasn import OctetString
102 from pyderasn import pp_console_row
103 from pyderasn import pprint
104 from pyderasn import PrintableString
105 from pyderasn import Sequence
106 from pyderasn import SequenceOf
107 from pyderasn import Set
108 from pyderasn import SetOf
109 from pyderasn import tag_ctxc
110 from pyderasn import tag_ctxp
111 from pyderasn import tag_decode
112 from pyderasn import tag_encode
113 from pyderasn import tag_strip
114 from pyderasn import TagClassApplication
115 from pyderasn import TagClassContext
116 from pyderasn import TagClassPrivate
117 from pyderasn import TagClassUniversal
118 from pyderasn import TagFormConstructed
119 from pyderasn import TagFormPrimitive
120 from pyderasn import TagMismatch
121 from pyderasn import TeletexString
122 from pyderasn import UniversalString
123 from pyderasn import UTCTime
124 from pyderasn import UTF8String
125 from pyderasn import VideotexString
126 from pyderasn import VisibleString
130 max_examples = environ.get("MAX_EXAMPLES")
131 settings.register_profile("local", settings(
133 **({"max_examples": int(max_examples)} if max_examples else {})
135 settings.load_profile("local")
136 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
138 tag_classes = sampled_from((
144 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
145 decode_path_strat = lists(integers(), max_size=3).map(
146 lambda decode_path: tuple(str(dp) for dp in decode_path)
148 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
151 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
153 self_module = import_module(__name__)
156 def register_class(klass):
157 klassname = klass.__name__ + str(time()).replace(".", "")
158 klass.__name__ = klassname
159 klass.__qualname__ = klassname
160 setattr(self_module, klassname, klass)
163 def assert_exceeding_data(self, call, junk):
166 with self.assertRaisesRegex(ExceedingData, "%d trailing bytes" % len(junk)) as err:
171 class TestHex(TestCase):
173 def test_symmetric(self, data):
174 self.assertEqual(hexdec(hexenc(data)), data)
177 class TestTagCoder(TestCase):
178 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
182 integers(min_value=0, max_value=30),
185 def test_short(self, klass, form, num, junk):
186 raw = tag_encode(klass=klass, form=form, num=num)
187 self.assertEqual(tag_decode(raw), (klass, form, num))
188 self.assertEqual(len(raw), 1)
190 tag_encode(klass=klass, form=form, num=0)[0],
191 raw[0] & (1 << 7 | 1 << 6 | 1 << 5),
193 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
194 self.assertSequenceEqual(stripped.tobytes(), raw)
195 self.assertEqual(tlen, len(raw))
196 self.assertSequenceEqual(tail, junk)
198 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
202 integers(min_value=31),
205 def test_long(self, klass, form, num, junk):
206 raw = tag_encode(klass=klass, form=form, num=num)
207 self.assertEqual(tag_decode(raw), (klass, form, num))
208 self.assertGreater(len(raw), 1)
210 tag_encode(klass=klass, form=form, num=0)[0] | 31,
213 self.assertEqual(raw[-1] & 0x80, 0)
214 self.assertTrue(all(b & 0x80 > 0 for b in raw[1:-1]))
215 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
216 self.assertSequenceEqual(stripped.tobytes(), raw)
217 self.assertEqual(tlen, len(raw))
218 self.assertSequenceEqual(tail, junk)
220 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
221 @given(integers(min_value=31))
222 def test_unfinished_tag(self, num):
223 raw = bytearray(tag_encode(num=num))
224 for i in range(1, len(raw)):
226 with self.assertRaisesRegex(DecodeError, "unfinished tag"):
227 tag_strip(bytes(raw))
229 def test_go_vectors_valid(self):
230 for data, (eklass, etag, elen, eform) in (
231 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
232 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
233 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
234 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
235 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
236 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
237 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
238 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
239 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
240 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
242 tag, _, len_encoded = tag_strip(memoryview(data))
243 klass, form, num = tag_decode(tag)
244 _len, _, tail = len_decode(len_encoded)
245 self.assertSequenceEqual(tail, b"")
246 self.assertEqual(klass, eklass)
247 self.assertEqual(num, etag)
248 self.assertEqual(_len, elen)
249 self.assertEqual(form, eform)
251 def test_go_vectors_invalid(self):
259 with self.assertRaises(DecodeError):
260 _, _, len_encoded = tag_strip(memoryview(data))
261 len_decode(len_encoded)
264 integers(min_value=0, max_value=127),
265 integers(min_value=0, max_value=2),
267 def test_long_instead_of_short(self, l, dummy_num):
268 octets = (b"\x00" * dummy_num) + bytes([l])
269 octets = bytes([(dummy_num + 1) | 0x80]) + octets
270 with self.assertRaises(DecodeError):
273 @given(tag_classes, tag_forms, integers(min_value=31))
274 def test_leading_zero_byte(self, klass, form, num):
275 raw = tag_encode(klass=klass, form=form, num=num)
276 raw = b"".join((raw[:1], b"\x80", raw[1:]))
277 with self.assertRaisesRegex(DecodeError, "leading zero byte"):
280 @given(tag_classes, tag_forms, integers(max_value=30, min_value=0))
281 def test_unexpected_long_form(self, klass, form, num):
282 raw = bytes([klass | form | 31, num])
283 with self.assertRaisesRegex(DecodeError, "unexpected long form"):
287 class TestLenCoder(TestCase):
288 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
290 integers(min_value=0, max_value=127),
293 def test_short(self, l, junk):
294 raw = len_encode(l) + junk
295 decoded, llen, tail = len_decode(memoryview(raw))
296 self.assertEqual(decoded, l)
297 self.assertEqual(llen, 1)
298 self.assertEqual(len(raw), 1 + len(junk))
299 self.assertEqual(tail.tobytes(), junk)
301 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
303 integers(min_value=128),
306 def test_long(self, l, junk):
307 raw = len_encode(l) + junk
308 decoded, llen, tail = len_decode(memoryview(raw))
309 self.assertEqual(decoded, l)
310 self.assertEqual((llen - 1) | 0x80, raw[0])
311 self.assertEqual(llen, len(raw) - len(junk))
312 self.assertNotEqual(raw[1], 0)
313 self.assertSequenceEqual(tail.tobytes(), junk)
315 def test_empty(self):
316 with self.assertRaises(NotEnoughData):
319 @given(integers(min_value=128))
320 def test_stripped(self, _len):
321 with self.assertRaises(NotEnoughData):
322 len_decode(len_encode(_len)[:-1])
325 text_printable = text(alphabet=printable, min_size=1)
329 def text_letters(draw):
330 result = draw(text(alphabet=ascii_letters, min_size=1))
334 class CommonMixin(object):
335 def test_tag_default(self):
336 obj = self.base_klass()
337 self.assertEqual(obj.tag, obj.tag_default)
339 def test_simultaneous_impl_expl(self):
340 with self.assertRaises(ValueError):
341 self.base_klass(impl=b"whatever", expl=b"whenever")
343 @given(binary(min_size=1), integers(), integers(), integers())
344 def test_decoded(self, impl, offset, llen, vlen):
345 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
346 self.assertEqual(obj.offset, offset)
347 self.assertEqual(obj.llen, llen)
348 self.assertEqual(obj.vlen, vlen)
349 self.assertEqual(obj.tlen, len(impl))
350 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
352 @given(binary(min_size=1))
353 def test_impl_inherited(self, impl_tag):
354 class Inherited(self.base_klass):
357 self.assertSequenceEqual(obj.impl, impl_tag)
358 self.assertFalse(obj.expled)
360 tag_class, _, tag_num = tag_decode(impl_tag)
361 self.assertEqual(obj.tag_order, (tag_class, tag_num))
363 @given(binary(min_size=1))
364 def test_expl_inherited(self, expl_tag):
365 class Inherited(self.base_klass):
368 self.assertSequenceEqual(obj.expl, expl_tag)
369 self.assertTrue(obj.expled)
371 tag_class, _, tag_num = tag_decode(expl_tag)
372 self.assertEqual(obj.tag_order, (tag_class, tag_num))
374 def assert_copied_basic_fields(self, obj, obj_copied):
375 self.assertEqual(obj, obj_copied)
376 self.assertSequenceEqual(obj.tag, obj_copied.tag)
377 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
378 self.assertEqual(obj.default, obj_copied.default)
379 self.assertEqual(obj.optional, obj_copied.optional)
380 self.assertEqual(obj.offset, obj_copied.offset)
381 self.assertEqual(obj.llen, obj_copied.llen)
382 self.assertEqual(obj.vlen, obj_copied.vlen)
384 self.assertEqual(obj.tag_order, obj_copied.tag_order)
388 def boolean_values_strategy(draw, do_expl=False):
389 value = draw(one_of(none(), booleans()))
393 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
395 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
396 default = draw(one_of(none(), booleans()))
397 optional = draw(one_of(none(), booleans()))
399 draw(integers(min_value=0)),
400 draw(integers(min_value=0)),
401 draw(integers(min_value=0)),
403 return (value, impl, expl, default, optional, _decoded)
406 class BooleanInherited(Boolean):
410 class TestBoolean(CommonMixin, TestCase):
413 def test_invalid_value_type(self):
414 with self.assertRaises(InvalidValueType) as err:
419 def test_optional(self, optional):
420 obj = Boolean(default=Boolean(False), optional=optional)
421 self.assertTrue(obj.optional)
424 def test_ready(self, value):
426 self.assertFalse(obj.ready)
429 pprint(obj, big_blobs=True, with_decode_path=True)
430 with self.assertRaises(ObjNotReady) as err:
432 with self.assertRaises(ObjNotReady) as err:
436 self.assertTrue(obj.ready)
439 pprint(obj, big_blobs=True, with_decode_path=True)
441 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
442 def test_comparison(self, value1, value2, tag1, tag2):
443 for klass in (Boolean, BooleanInherited):
446 self.assertEqual(obj1 == obj2, value1 == value2)
447 self.assertEqual(obj1 != obj2, value1 != value2)
448 self.assertEqual(obj1 == bool(obj2), value1 == value2)
449 obj1 = klass(value1, impl=tag1)
450 obj2 = klass(value1, impl=tag2)
451 self.assertEqual(obj1 == obj2, tag1 == tag2)
452 self.assertEqual(obj1 != obj2, tag1 != tag2)
454 @given(data_strategy())
455 def test_call(self, d):
456 for klass in (Boolean, BooleanInherited):
464 ) = d.draw(boolean_values_strategy())
470 optional_initial or False,
480 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
481 obj = obj_initial(value, impl, expl, default, optional)
483 value_expected = default if value is None else value
485 default_initial if value_expected is None
488 self.assertEqual(obj, value_expected)
489 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
490 self.assertEqual(obj.expl_tag, expl or expl_initial)
493 default_initial if default is None else default,
495 if obj.default is None:
496 optional = optional_initial if optional is None else optional
497 optional = False if optional is None else optional
500 self.assertEqual(obj.optional, optional)
502 @given(boolean_values_strategy())
503 def test_copy(self, values):
504 for klass in (Boolean, BooleanInherited):
506 for copy_func in copy_funcs:
507 obj_copied = copy_func(obj)
508 self.assert_copied_basic_fields(obj, obj_copied)
512 integers(min_value=1).map(tag_encode),
514 def test_stripped(self, value, tag_impl):
515 obj = Boolean(value, impl=tag_impl)
516 with self.assertRaises(NotEnoughData):
517 obj.decode(obj.encode()[:-1])
518 with self.assertRaises(NotEnoughData):
519 obj.decode(encode2pass(obj)[:-1])
523 integers(min_value=1).map(tag_ctxc),
525 def test_stripped_expl(self, value, tag_expl):
526 obj = Boolean(value, expl=tag_expl)
527 with self.assertRaises(NotEnoughData):
528 obj.decode(obj.encode()[:-1])
529 with self.assertRaises(NotEnoughData):
530 obj.decode(encode2pass(obj)[:-1])
533 integers(min_value=31),
534 integers(min_value=0),
537 def test_bad_tag(self, tag, offset, decode_path):
538 with self.assertRaises(DecodeError) as err:
540 tag_encode(tag)[:-1],
542 decode_path=decode_path,
545 self.assertEqual(err.exception.offset, offset)
546 self.assertEqual(err.exception.decode_path, decode_path)
549 integers(min_value=31),
550 integers(min_value=0),
553 def test_bad_expl_tag(self, tag, offset, decode_path):
554 with self.assertRaises(DecodeError) as err:
555 Boolean(expl=Boolean.tag_default).decode(
556 tag_encode(tag)[:-1],
558 decode_path=decode_path,
561 self.assertEqual(err.exception.offset, offset)
562 self.assertEqual(err.exception.decode_path, decode_path)
565 integers(min_value=128),
566 integers(min_value=0),
569 def test_bad_len(self, l, offset, decode_path):
570 with self.assertRaises(DecodeError) as err:
572 Boolean.tag_default + len_encode(l)[:-1],
574 decode_path=decode_path,
577 self.assertEqual(err.exception.offset, offset)
578 self.assertEqual(err.exception.decode_path, decode_path)
581 integers(min_value=128),
582 integers(min_value=0),
585 def test_bad_expl_len(self, l, offset, decode_path):
586 with self.assertRaises(DecodeError) as err:
587 Boolean(expl=Boolean.tag_default).decode(
588 Boolean.tag_default + len_encode(l)[:-1],
590 decode_path=decode_path,
593 self.assertEqual(err.exception.offset, offset)
594 self.assertEqual(err.exception.decode_path, decode_path)
596 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
598 boolean_values_strategy(),
600 integers(min_value=1).map(tag_ctxc),
601 integers(min_value=0),
605 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
606 for klass in (Boolean, BooleanInherited):
607 _, _, _, default, optional, _decoded = values
616 pprint(obj, big_blobs=True, with_decode_path=True)
617 self.assertFalse(obj.expled)
618 obj_encoded = obj.encode()
619 self.assertEqual(encode2pass(obj), obj_encoded)
620 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
621 obj_expled = obj(value, expl=tag_expl)
622 self.assertTrue(obj_expled.expled)
624 list(obj_expled.pps())
625 pprint(obj_expled, big_blobs=True, with_decode_path=True)
626 obj_expled_cer = encode_cer(obj_expled)
627 self.assertNotEqual(obj_expled_cer, obj_encoded)
628 self.assertSequenceEqual(
629 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
632 obj_expled_hex_encoded = obj_expled.hexencode()
633 ctx_copied = deepcopy(ctx_dummy)
634 obj_decoded, tail = obj_expled.hexdecode(
635 obj_expled_hex_encoded + hexenc(tail_junk),
639 self.assertDictEqual(ctx_copied, ctx_dummy)
641 list(obj_decoded.pps())
642 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
643 self.assertEqual(tail, tail_junk)
644 self.assertEqual(obj_decoded, obj_expled)
645 self.assertNotEqual(obj_decoded, obj)
646 self.assertEqual(bool(obj_decoded), bool(obj_expled))
647 self.assertEqual(bool(obj_decoded), bool(obj))
648 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
649 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
650 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
652 obj_decoded.expl_llen,
653 len(len_encode(len(obj_encoded))),
655 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
656 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
659 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
661 self.assertEqual(obj_decoded.expl_offset, offset)
662 assert_exceeding_data(
664 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
668 evgens = list(obj_expled.decode_evgen(
669 hexdec(obj_expled_hex_encoded) + tail_junk,
671 decode_path=decode_path,
674 self.assertEqual(len(evgens), 1)
675 _decode_path, obj, tail = evgens[0]
676 self.assertSequenceEqual(tail, tail_junk)
677 self.assertEqual(_decode_path, decode_path)
678 self.assertEqual(obj, obj_decoded)
679 self.assertEqual(obj.expl_offset, offset)
683 @given(integers(min_value=2))
684 def test_invalid_len(self, l):
685 with self.assertRaises(InvalidLength):
686 Boolean().decode(b"".join((
692 @given(integers(min_value=0 + 1, max_value=255 - 1))
693 def test_ber_value(self, value):
694 with self.assertRaisesRegex(DecodeError, "unacceptable Boolean value"):
695 Boolean().decode(b"".join((
700 encoded = b"".join((Boolean.tag_default, len_encode(1), bytes([value])))
701 obj, _ = Boolean().decode(encoded, ctx={"bered": True})
702 list(Boolean().decode_evgen(encoded, ctx={"bered": True}))
703 self.assertTrue(bool(obj))
704 self.assertTrue(obj.ber_encoded)
705 self.assertFalse(obj.lenindef)
706 self.assertTrue(obj.bered)
708 self.assertTrue(obj.ber_encoded)
709 self.assertFalse(obj.lenindef)
710 self.assertTrue(obj.bered)
713 integers(min_value=1).map(tag_ctxc),
714 binary().filter(lambda x: not x.startswith(EOC)),
716 def test_ber_expl_no_eoc(self, expl, junk):
717 encoded = expl + LENINDEF + Boolean(False).encode()
718 with self.assertRaises(LenIndefForm):
719 Boolean(expl=expl).decode(encoded + junk)
720 with self.assertRaisesRegex(DecodeError, "no EOC"):
721 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
722 obj, tail = Boolean(expl=expl).decode(
723 encoded + EOC + junk,
726 self.assertTrue(obj.expl_lenindef)
727 self.assertFalse(obj.lenindef)
728 self.assertFalse(obj.ber_encoded)
729 self.assertTrue(obj.bered)
731 self.assertTrue(obj.expl_lenindef)
732 self.assertFalse(obj.lenindef)
733 self.assertFalse(obj.ber_encoded)
734 self.assertTrue(obj.bered)
735 self.assertSequenceEqual(tail, junk)
738 pprint(obj, big_blobs=True, with_decode_path=True)
741 integers(min_value=1).map(tag_ctxc),
748 def test_ber_expl(self, expl, values):
754 Boolean(value).encode() +
757 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
759 class SeqOf(SequenceOf):
760 schema = Boolean(expl=expl)
761 with self.assertRaises(LenIndefForm):
762 SeqOf().decode(encoded)
763 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
764 list(SeqOf().decode_evgen(encoded, ctx={"bered": True}))
765 self.assertSequenceEqual(tail, b"")
766 self.assertSequenceEqual([bool(v) for v in seqof], values)
782 len(expl) + 1 + 3 + EOC_LEN,
793 pprint(seqof, big_blobs=True, with_decode_path=True)
797 def integer_values_strategy(draw, do_expl=False):
798 bound_min, value, default, bound_max = sorted(draw(sets(
807 _specs = draw(sets(text_letters()))
810 min_size=len(_specs),
811 max_size=len(_specs),
813 _specs = list(zip(_specs, values))
816 bounds = (bound_min, bound_max)
820 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
822 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
825 optional = draw(one_of(none(), booleans()))
827 draw(integers(min_value=0)),
828 draw(integers(min_value=0)),
829 draw(integers(min_value=0)),
831 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
834 class IntegerInherited(Integer):
838 class TestInteger(CommonMixin, TestCase):
841 def test_invalid_value_type(self):
842 with self.assertRaises(InvalidValueType) as err:
846 @given(sets(text_letters(), min_size=2))
847 def test_unknown_name(self, names_input):
848 missing = names_input.pop()
851 schema = [(n, 123) for n in names_input]
852 with self.assertRaises(ObjUnknown) as err:
856 @given(sets(text_letters(), min_size=2))
857 def test_known_name(self, names_input):
859 schema = [(n, 123) for n in names_input]
860 Int(names_input.pop())
863 def test_optional(self, optional):
864 obj = Integer(default=Integer(0), optional=optional)
865 self.assertTrue(obj.optional)
868 def test_ready(self, value):
870 self.assertFalse(obj.ready)
873 pprint(obj, big_blobs=True, with_decode_path=True)
874 with self.assertRaises(ObjNotReady) as err:
876 with self.assertRaises(ObjNotReady) as err:
880 self.assertTrue(obj.ready)
883 pprint(obj, big_blobs=True, with_decode_path=True)
886 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
887 def test_comparison(self, value1, value2, tag1, tag2):
888 for klass in (Integer, IntegerInherited):
891 self.assertEqual(obj1 == obj2, value1 == value2)
892 self.assertEqual(obj1 != obj2, value1 != value2)
893 self.assertEqual(obj1 == int(obj2), value1 == value2)
894 obj1 = klass(value1, impl=tag1)
895 obj2 = klass(value1, impl=tag2)
896 self.assertEqual(obj1 == obj2, tag1 == tag2)
897 self.assertEqual(obj1 != obj2, tag1 != tag2)
899 @given(lists(integers()))
900 def test_sorted_works(self, values):
901 self.assertSequenceEqual(
902 [int(v) for v in sorted(Integer(v) for v in values)],
906 @given(data_strategy())
907 def test_named(self, d):
908 names_input = list(d.draw(sets(text_letters(), min_size=1)))
909 values_input = list(d.draw(sets(
911 min_size=len(names_input),
912 max_size=len(names_input),
914 chosen_name = d.draw(sampled_from(names_input))
915 names_input = dict(zip(names_input, values_input))
919 _int = Int(chosen_name)
920 self.assertEqual(_int.named, chosen_name)
921 self.assertEqual(int(_int), names_input[chosen_name])
923 @given(integers(), integers(min_value=0), integers(min_value=0))
924 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
925 value = bound_min + value_delta
926 bound_max = value + bound_delta
927 Integer(value=value, bounds=(bound_min, bound_max))
929 @given(sets(integers(), min_size=3, max_size=3))
930 def test_bounds_unsatisfied(self, values):
931 values = sorted(values)
932 with self.assertRaises(BoundsError) as err:
933 Integer(value=values[0], bounds=(values[1], values[2]))
935 with self.assertRaisesRegex(DecodeError, "bounds") as err:
936 Integer(bounds=(values[1], values[2])).decode(
937 Integer(values[0]).encode()
940 with self.assertRaisesRegex(DecodeError, "bounds") as err:
941 Integer(bounds=(values[1], values[2])).decode(
942 encode2pass(Integer(values[0]))
944 with self.assertRaises(BoundsError) as err:
945 Integer(value=values[2], bounds=(values[0], values[1]))
947 with self.assertRaisesRegex(DecodeError, "bounds") as err:
948 Integer(bounds=(values[0], values[1])).decode(
949 Integer(values[2]).encode()
952 with self.assertRaisesRegex(DecodeError, "bounds") as err:
953 Integer(bounds=(values[0], values[1])).decode(
954 encode2pass(Integer(values[2]))
957 @given(data_strategy())
958 def test_call(self, d):
959 for klass in (Integer, IntegerInherited):
969 ) = d.draw(integer_values_strategy())
976 optional_initial or False,
989 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
990 if (default is None) and (obj_initial.default is not None):
994 (value is not None) and
995 (bounds_initial is not None) and
996 not (bounds_initial[0] <= value <= bounds_initial[1])
1000 (bounds is None) and
1001 (default is not None) and
1002 (bounds_initial is not None) and
1003 not (bounds_initial[0] <= default <= bounds_initial[1])
1006 obj = obj_initial(value, bounds, impl, expl, default, optional)
1008 value_expected = default if value is None else value
1010 default_initial if value_expected is None
1013 self.assertEqual(obj, value_expected)
1014 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1015 self.assertEqual(obj.expl_tag, expl or expl_initial)
1018 default_initial if default is None else default,
1020 if obj.default is None:
1021 optional = optional_initial if optional is None else optional
1022 optional = False if optional is None else optional
1025 self.assertEqual(obj.optional, optional)
1027 (obj._bound_min, obj._bound_max),
1028 bounds or bounds_initial or (float("-inf"), float("+inf")),
1032 {} if _specs_initial is None else dict(_specs_initial),
1035 @given(integer_values_strategy())
1036 def test_copy(self, values):
1037 for klass in (Integer, IntegerInherited):
1038 obj = klass(*values)
1039 for copy_func in copy_funcs:
1040 obj_copied = copy_func(obj)
1041 self.assert_copied_basic_fields(obj, obj_copied)
1042 self.assertEqual(obj.specs, obj_copied.specs)
1043 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1044 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1045 self.assertEqual(obj._value, obj_copied._value)
1049 integers(min_value=1).map(tag_encode),
1051 def test_stripped(self, value, tag_impl):
1052 obj = Integer(value, impl=tag_impl)
1053 with self.assertRaises(NotEnoughData):
1054 obj.decode(obj.encode()[:-1])
1058 integers(min_value=1).map(tag_ctxc),
1060 def test_stripped_expl(self, value, tag_expl):
1061 obj = Integer(value, expl=tag_expl)
1062 with self.assertRaises(NotEnoughData):
1063 obj.decode(obj.encode()[:-1])
1065 def test_zero_len(self):
1066 with self.assertRaises(NotEnoughData):
1067 Integer().decode(b"".join((
1068 Integer.tag_default,
1073 integers(min_value=31),
1074 integers(min_value=0),
1077 def test_bad_tag(self, tag, offset, decode_path):
1078 with self.assertRaises(DecodeError) as err:
1080 tag_encode(tag)[:-1],
1082 decode_path=decode_path,
1085 self.assertEqual(err.exception.offset, offset)
1086 self.assertEqual(err.exception.decode_path, decode_path)
1089 integers(min_value=128),
1090 integers(min_value=0),
1093 def test_bad_len(self, l, offset, decode_path):
1094 with self.assertRaises(DecodeError) as err:
1096 Integer.tag_default + len_encode(l)[:-1],
1098 decode_path=decode_path,
1101 self.assertEqual(err.exception.offset, offset)
1102 self.assertEqual(err.exception.decode_path, decode_path)
1105 sets(integers(), min_size=2, max_size=2),
1106 integers(min_value=0),
1109 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1110 value, bound_min = list(sorted(ints))
1113 bounds = (bound_min, bound_min)
1114 with self.assertRaises(DecodeError) as err:
1116 Integer(value).encode(),
1118 decode_path=decode_path,
1121 self.assertEqual(err.exception.offset, offset)
1122 self.assertEqual(err.exception.decode_path, decode_path)
1124 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1126 integer_values_strategy(),
1128 integers(min_value=1).map(tag_ctxc),
1129 integers(min_value=0),
1133 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
1134 for klass in (Integer, IntegerInherited):
1135 _, _, _, _, default, optional, _, _decoded = values
1144 pprint(obj, big_blobs=True, with_decode_path=True)
1145 self.assertFalse(obj.expled)
1146 obj_encoded = obj.encode()
1147 self.assertEqual(encode2pass(obj), obj_encoded)
1148 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1149 obj_expled = obj(value, expl=tag_expl)
1150 self.assertTrue(obj_expled.expled)
1152 list(obj_expled.pps())
1153 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1154 obj_expled_encoded = obj_expled.encode()
1155 obj_expled_cer = encode_cer(obj_expled)
1156 self.assertNotEqual(obj_expled_cer, obj_encoded)
1157 self.assertSequenceEqual(
1158 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1161 ctx_copied = deepcopy(ctx_dummy)
1162 obj_decoded, tail = obj_expled.decode(
1163 obj_expled_encoded + tail_junk,
1167 self.assertDictEqual(ctx_copied, ctx_dummy)
1169 list(obj_decoded.pps())
1170 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1171 self.assertEqual(tail, tail_junk)
1172 self.assertEqual(obj_decoded, obj_expled)
1173 self.assertNotEqual(obj_decoded, obj)
1174 self.assertEqual(int(obj_decoded), int(obj_expled))
1175 self.assertEqual(int(obj_decoded), int(obj))
1176 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1177 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1178 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1180 obj_decoded.expl_llen,
1181 len(len_encode(len(obj_encoded))),
1183 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1184 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1187 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1189 self.assertEqual(obj_decoded.expl_offset, offset)
1190 assert_exceeding_data(
1192 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1196 evgens = list(obj_expled.decode_evgen(
1197 obj_expled_encoded + tail_junk,
1199 decode_path=decode_path,
1202 self.assertEqual(len(evgens), 1)
1203 _decode_path, obj, tail = evgens[0]
1204 self.assertSequenceEqual(tail, tail_junk)
1205 self.assertEqual(_decode_path, decode_path)
1206 self.assertEqual(obj, obj_decoded)
1207 self.assertEqual(obj.expl_offset, offset)
1211 def test_go_vectors_valid(self):
1212 for data, expect in ((
1216 (b"\xff\x7f", -129),
1220 (b"\xff\x00", -256),
1224 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1225 (b"\x80\x00\x00\x00", -2147483648),
1228 Integer().decode(b"".join((
1229 Integer.tag_default,
1230 len_encode(len(data)),
1236 def test_go_vectors_invalid(self):
1241 with self.assertRaises(DecodeError):
1242 Integer().decode(b"".join((
1243 Integer.tag_default,
1244 len_encode(len(data)),
1250 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1253 if draw(booleans()):
1254 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1256 integers(min_value=0, max_value=255),
1257 min_size=len(schema),
1258 max_size=len(schema),
1260 schema = list(zip(schema, bits))
1262 def _value(value_required):
1263 if not value_required and draw(booleans()):
1265 generation_choice = 0
1267 generation_choice = draw(sampled_from((1, 2, 3)))
1268 if generation_choice == 1 or draw(booleans()):
1269 return "'%s'B" % "".join(draw(lists(
1270 sampled_from(("0", "1")),
1271 max_size=len(schema),
1273 if generation_choice == 2 or draw(booleans()):
1274 return draw(binary(max_size=len(schema) // 8))
1275 if generation_choice == 3 or draw(booleans()):
1276 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1278 value = _value(value_required)
1279 default = _value(value_required=False)
1283 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1285 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1286 optional = draw(one_of(none(), booleans()))
1288 draw(integers(min_value=0)),
1289 draw(integers(min_value=0)),
1290 draw(integers(min_value=0)),
1292 return (schema, value, impl, expl, default, optional, _decoded)
1295 class BitStringInherited(BitString):
1299 class TestBitString(CommonMixin, TestCase):
1300 base_klass = BitString
1302 @given(lists(booleans()))
1303 def test_b_encoding(self, bits):
1304 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1305 self.assertEqual(obj.bit_len, len(bits))
1306 self.assertSequenceEqual(list(obj), bits)
1307 for i, bit in enumerate(bits):
1308 self.assertEqual(obj[i], bit)
1310 @given(lists(booleans()))
1311 def test_out_of_bounds_bits(self, bits):
1312 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1313 for i in range(len(bits), len(bits) * 2):
1314 self.assertFalse(obj[i])
1316 def test_bad_b_encoding(self):
1317 with self.assertRaises(ValueError):
1318 BitString("'010120101'B")
1321 integers(min_value=1, max_value=255),
1322 integers(min_value=1, max_value=255),
1324 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1325 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1326 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1327 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1329 class BS(BitString):
1330 schema = (("whatever", 0),)
1331 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1332 self.assertEqual(obj.bit_len, leading_zeros + 1)
1333 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1335 def test_zero_len(self):
1336 with self.assertRaises(NotEnoughData):
1337 BitString().decode(b"".join((
1338 BitString.tag_default,
1342 def test_invalid_value_type(self):
1343 with self.assertRaises(InvalidValueType) as err:
1346 with self.assertRaises(InvalidValueType) as err:
1350 def test_obj_unknown(self):
1351 with self.assertRaises(ObjUnknown) as err:
1352 BitString(b"whatever")["whenever"]
1355 def test_get_invalid_type(self):
1356 with self.assertRaises(InvalidValueType) as err:
1357 BitString(b"whatever")[(1, 2, 3)]
1360 @given(data_strategy())
1361 def test_unknown_name(self, d):
1362 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1363 missing = _schema.pop()
1365 class BS(BitString):
1366 schema = [(n, i) for i, n in enumerate(_schema)]
1367 with self.assertRaises(ObjUnknown) as err:
1372 def test_optional(self, optional):
1373 obj = BitString(default=BitString(b""), optional=optional)
1374 self.assertTrue(obj.optional)
1377 def test_ready(self, value):
1379 self.assertFalse(obj.ready)
1382 pprint(obj, big_blobs=True, with_decode_path=True)
1383 with self.assertRaises(ObjNotReady) as err:
1386 with self.assertRaises(ObjNotReady) as err:
1388 obj = BitString(value)
1389 self.assertTrue(obj.ready)
1392 pprint(obj, big_blobs=True, with_decode_path=True)
1395 tuples(integers(min_value=0), binary()),
1396 tuples(integers(min_value=0), binary()),
1400 def test_comparison(self, value1, value2, tag1, tag2):
1401 for klass in (BitString, BitStringInherited):
1402 obj1 = klass(value1)
1403 obj2 = klass(value2)
1404 self.assertEqual(obj1 == obj2, value1 == value2)
1405 self.assertEqual(obj1 != obj2, value1 != value2)
1406 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1407 obj1 = klass(value1, impl=tag1)
1408 obj2 = klass(value1, impl=tag2)
1409 self.assertEqual(obj1 == obj2, tag1 == tag2)
1410 self.assertEqual(obj1 != obj2, tag1 != tag2)
1412 @given(data_strategy())
1413 def test_call(self, d):
1414 for klass in (BitString, BitStringInherited):
1423 ) = d.draw(bit_string_values_strategy())
1426 schema = schema_initial
1428 value=value_initial,
1431 default=default_initial,
1432 optional=optional_initial or False,
1433 _decoded=_decoded_initial,
1443 ) = d.draw(bit_string_values_strategy(
1444 schema=schema_initial,
1445 do_expl=impl_initial is None,
1454 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1455 self.assertEqual(obj.expl_tag, expl or expl_initial)
1456 if obj.default is None:
1457 optional = optional_initial if optional is None else optional
1458 optional = False if optional is None else optional
1461 self.assertEqual(obj.optional, optional)
1462 self.assertEqual(obj.specs, obj_initial.specs)
1464 @given(bit_string_values_strategy())
1465 def test_copy(self, values):
1466 for klass in (BitString, BitStringInherited):
1467 _schema, value, impl, expl, default, optional, _decoded = values
1477 optional=optional or False,
1480 for copy_func in copy_funcs:
1481 obj_copied = copy_func(obj)
1482 self.assert_copied_basic_fields(obj, obj_copied)
1483 self.assertEqual(obj.specs, obj_copied.specs)
1484 self.assertEqual(obj._value, obj_copied._value)
1488 integers(min_value=1).map(tag_encode),
1490 def test_stripped(self, value, tag_impl):
1491 obj = BitString(value, impl=tag_impl)
1492 with self.assertRaises(NotEnoughData):
1493 obj.decode(obj.encode()[:-1])
1497 integers(min_value=1).map(tag_ctxc),
1499 def test_stripped_expl(self, value, tag_expl):
1500 obj = BitString(value, expl=tag_expl)
1501 with self.assertRaises(NotEnoughData):
1502 obj.decode(obj.encode()[:-1])
1505 integers(min_value=31),
1506 integers(min_value=0),
1509 def test_bad_tag(self, tag, offset, decode_path):
1510 with self.assertRaises(DecodeError) as err:
1512 tag_encode(tag)[:-1],
1514 decode_path=decode_path,
1517 self.assertEqual(err.exception.offset, offset)
1518 self.assertEqual(err.exception.decode_path, decode_path)
1521 integers(min_value=128),
1522 integers(min_value=0),
1525 def test_bad_len(self, l, offset, decode_path):
1526 with self.assertRaises(DecodeError) as err:
1528 BitString.tag_default + len_encode(l)[:-1],
1530 decode_path=decode_path,
1533 self.assertEqual(err.exception.offset, offset)
1534 self.assertEqual(err.exception.decode_path, decode_path)
1536 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1537 @given(data_strategy())
1538 def test_symmetric(self, d):
1547 ) = d.draw(bit_string_values_strategy(value_required=True))
1548 tail_junk = d.draw(binary(max_size=5))
1549 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1550 offset = d.draw(integers(min_value=0))
1551 decode_path = d.draw(decode_path_strat)
1552 for klass in (BitString, BitStringInherited):
1563 pprint(obj, big_blobs=True, with_decode_path=True)
1564 self.assertFalse(obj.expled)
1565 obj_encoded = obj.encode()
1566 self.assertEqual(encode2pass(obj), obj_encoded)
1567 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1568 obj_expled = obj(value, expl=tag_expl)
1569 self.assertTrue(obj_expled.expled)
1571 list(obj_expled.pps())
1572 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1573 obj_expled_encoded = obj_expled.encode()
1574 obj_expled_cer = encode_cer(obj_expled)
1575 self.assertNotEqual(obj_expled_cer, obj_encoded)
1576 self.assertSequenceEqual(
1577 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1580 ctx_copied = deepcopy(ctx_dummy)
1581 obj_decoded, tail = obj_expled.decode(
1582 obj_expled_encoded + tail_junk,
1586 self.assertDictEqual(ctx_copied, ctx_dummy)
1588 list(obj_decoded.pps())
1589 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1590 self.assertEqual(tail, tail_junk)
1591 self.assertEqual(obj_decoded, obj_expled)
1592 self.assertNotEqual(obj_decoded, obj)
1593 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1594 self.assertEqual(bytes(obj_decoded), bytes(obj))
1595 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1596 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1597 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1599 obj_decoded.expl_llen,
1600 len(len_encode(len(obj_encoded))),
1602 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1603 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1606 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1608 self.assertEqual(obj_decoded.expl_offset, offset)
1609 if isinstance(value, tuple):
1610 self.assertSetEqual(set(value), set(obj_decoded.named))
1613 assert_exceeding_data(
1615 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1619 evgens = list(obj_expled.decode_evgen(
1620 obj_expled_encoded + tail_junk,
1622 decode_path=decode_path,
1625 self.assertEqual(len(evgens), 1)
1626 _decode_path, obj, tail = evgens[0]
1627 self.assertSequenceEqual(tail, tail_junk)
1628 self.assertEqual(_decode_path, decode_path)
1629 self.assertEqual(obj.expl_offset, offset)
1633 @given(integers(min_value=1, max_value=255))
1634 def test_bad_zero_value(self, pad_size):
1635 with self.assertRaises(DecodeError):
1636 BitString().decode(b"".join((
1637 BitString.tag_default,
1642 def test_go_vectors_invalid(self):
1648 with self.assertRaises(DecodeError):
1649 BitString().decode(b"".join((
1650 BitString.tag_default,
1655 def test_go_vectors_valid(self):
1656 obj, _ = BitString().decode(b"".join((
1657 BitString.tag_default,
1661 self.assertEqual(bytes(obj), b"")
1662 self.assertEqual(obj.bit_len, 0)
1664 obj, _ = BitString().decode(b"".join((
1665 BitString.tag_default,
1669 self.assertEqual(bytes(obj), b"\x00")
1670 self.assertEqual(obj.bit_len, 1)
1672 obj = BitString((16, b"\x82\x40"))
1673 self.assertTrue(obj[0])
1674 self.assertFalse(obj[1])
1675 self.assertTrue(obj[6])
1676 self.assertTrue(obj[9])
1677 self.assertFalse(obj[17])
1679 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1681 integers(min_value=1, max_value=30),
1684 binary(min_size=1, max_size=5),
1686 binary(min_size=1, max_size=5),
1694 lists(booleans(), min_size=1),
1698 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk, decode_path):
1699 def chunk_constructed(contents):
1701 tag_encode(form=TagFormConstructed, num=3) +
1703 b"".join(BitString(content).encode() for content in contents) +
1707 chunks_len_expected = []
1708 payload_expected = b""
1709 bit_len_expected = 0
1710 for chunk_input in chunk_inputs:
1711 if isinstance(chunk_input, bytes):
1712 chunks.append(BitString(chunk_input).encode())
1713 payload_expected += chunk_input
1714 bit_len_expected += len(chunk_input) * 8
1715 chunks_len_expected.append(len(chunk_input) + 1)
1717 chunks.append(chunk_constructed(chunk_input))
1718 payload = b"".join(chunk_input)
1719 payload_expected += payload
1720 bit_len_expected += len(payload) * 8
1721 for c in chunk_input:
1722 chunks_len_expected.append(len(c) + 1)
1723 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
1724 chunk_last = BitString("'%s'B" % "".join(
1725 "1" if bit else "0" for bit in chunk_last_bits
1727 chunks_len_expected.append(BitString().decod(chunk_last.encode()).vlen)
1728 payload_expected += bytes(chunk_last)
1729 bit_len_expected += chunk_last.bit_len
1730 encoded_indefinite = (
1731 tag_encode(form=TagFormConstructed, num=impl) +
1734 chunk_last.encode() +
1737 encoded_definite = (
1738 tag_encode(form=TagFormConstructed, num=impl) +
1739 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1743 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
1744 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1745 for lenindef_expected, encoded in (
1746 (True, encoded_indefinite),
1747 (False, encoded_definite),
1749 obj, tail = BitString(impl=tag_encode(impl)).decode(
1751 ctx={"bered": True},
1753 self.assertSequenceEqual(tail, junk)
1754 self.assertEqual(obj.bit_len, bit_len_expected)
1755 self.assertSequenceEqual(bytes(obj), payload_expected)
1756 self.assertTrue(obj.ber_encoded)
1757 self.assertEqual(obj.lenindef, lenindef_expected)
1758 self.assertTrue(obj.bered)
1760 self.assertTrue(obj.ber_encoded)
1761 self.assertEqual(obj.lenindef, lenindef_expected)
1762 self.assertTrue(obj.bered)
1763 self.assertEqual(len(encoded), obj.tlvlen)
1766 pprint(obj, big_blobs=True, with_decode_path=True)
1768 evgens = list(BitString(impl=tag_encode(impl)).decode_evgen(
1770 decode_path=decode_path,
1771 ctx={"bered": True},
1773 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
1774 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
1775 self.assertGreater(len(dp), len(decode_path))
1776 self.assertEqual(obj.vlen, chunk_len_expected)
1779 integers(min_value=0),
1782 def test_ber_definite_too_short(self, offset, decode_path):
1783 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
1785 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1787 decode_path=decode_path,
1788 ctx={"bered": True},
1790 self.assertEqual(err.exception.decode_path, decode_path)
1791 self.assertEqual(err.exception.offset, offset)
1794 integers(min_value=0),
1797 def test_ber_definite_no_data(self, offset, decode_path):
1798 with self.assertRaisesRegex(DecodeError, "zero length") as err:
1800 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1802 decode_path=decode_path,
1803 ctx={"bered": True},
1805 self.assertEqual(err.exception.decode_path, decode_path)
1806 self.assertEqual(err.exception.offset, offset)
1809 integers(min_value=0),
1811 integers(min_value=1, max_value=3),
1813 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1814 bs = BitString(b"data").encode()
1815 with self.assertRaises(NotEnoughData) as err:
1817 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1819 decode_path=decode_path,
1820 ctx={"bered": True},
1822 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1823 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1826 integers(min_value=0),
1828 integers(min_value=1, max_value=3),
1830 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1831 bs = BitString(b"data").encode()
1832 bs_longer = BitString(b"data-longer").encode()
1833 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
1836 tag_encode(3, form=TagFormConstructed) +
1837 len_encode((chunks + 1) * len(bs)) +
1842 decode_path=decode_path,
1843 ctx={"bered": True},
1845 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1846 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1849 integers(min_value=0),
1852 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1853 with self.assertRaisesRegex(DecodeError, "no chunks") as err:
1855 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1857 decode_path=decode_path,
1858 ctx={"bered": True},
1860 self.assertEqual(err.exception.decode_path, decode_path)
1861 self.assertEqual(err.exception.offset, offset)
1863 @given(data_strategy())
1864 def test_ber_indefinite_not_multiple(self, d):
1865 bs_short = BitString("'A'H").encode()
1866 bs_full = BitString("'AA'H").encode()
1867 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1868 chunks.append(bs_short)
1869 d.draw(permutations(chunks))
1870 chunks.append(bs_short)
1871 offset = d.draw(integers(min_value=0))
1872 decode_path = d.draw(decode_path_strat)
1873 with self.assertRaisesRegex(DecodeError, "multiple of 8 bits") as err:
1876 tag_encode(3, form=TagFormConstructed) +
1882 decode_path=decode_path,
1883 ctx={"bered": True},
1886 err.exception.decode_path,
1887 decode_path + (str(chunks.index(bs_short)),),
1890 err.exception.offset,
1891 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1894 def test_x690_vector(self):
1895 vector = BitString("'0A3B5F291CD'H")
1896 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1897 self.assertSequenceEqual(tail, b"")
1898 self.assertEqual(obj, vector)
1899 obj, tail = BitString().decode(
1900 hexdec("23800303000A3B0305045F291CD00000"),
1901 ctx={"bered": True},
1903 self.assertSequenceEqual(tail, b"")
1904 self.assertEqual(obj, vector)
1905 self.assertTrue(obj.ber_encoded)
1906 self.assertTrue(obj.lenindef)
1907 self.assertTrue(obj.bered)
1909 self.assertTrue(obj.ber_encoded)
1910 self.assertTrue(obj.lenindef)
1911 self.assertTrue(obj.bered)
1913 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1914 @given(integers(min_value=1000, max_value=3000))
1915 def test_cer(self, data_len):
1916 data = urandom(data_len)
1917 encoded = encode_cer(BitString(data))
1918 ctx = {"bered": True}
1919 self.assertSequenceEqual(bytes(BitString().decod(encoded, ctx=ctx)), data)
1920 evgens = list(BitString().decode_evgen(encoded, ctx=ctx))
1921 evgens_expected = data_len // 999
1922 if evgens_expected * 999 != data_len:
1923 evgens_expected += 1
1924 evgens_expected += 1
1925 self.assertEqual(len(evgens), evgens_expected)
1926 for (_, obj, _) in evgens[:-2]:
1927 self.assertEqual(obj.vlen, 1000)
1928 _, obj, _ = evgens[-2]
1929 self.assertEqual(obj.vlen, 1 + data_len - len(evgens[:-2]) * 999)
1933 def octet_string_values_strategy(draw, do_expl=False):
1934 bound_min, bound_max = sorted(draw(sets(
1935 integers(min_value=0, max_value=1 << 7),
1939 value = draw(one_of(
1941 binary(min_size=bound_min, max_size=bound_max),
1943 default = draw(one_of(
1945 binary(min_size=bound_min, max_size=bound_max),
1948 if draw(booleans()):
1949 bounds = (bound_min, bound_max)
1953 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1955 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1956 optional = draw(one_of(none(), booleans()))
1958 draw(integers(min_value=0)),
1959 draw(integers(min_value=0)),
1960 draw(integers(min_value=0)),
1962 return (value, bounds, impl, expl, default, optional, _decoded)
1965 class OctetStringInherited(OctetString):
1969 class TestOctetString(CommonMixin, TestCase):
1970 base_klass = OctetString
1972 def test_invalid_value_type(self):
1973 with self.assertRaises(InvalidValueType) as err:
1974 OctetString(str(123))
1978 def test_optional(self, optional):
1979 obj = OctetString(default=OctetString(b""), optional=optional)
1980 self.assertTrue(obj.optional)
1983 def test_ready(self, value):
1985 self.assertFalse(obj.ready)
1988 pprint(obj, big_blobs=True, with_decode_path=True)
1989 with self.assertRaises(ObjNotReady) as err:
1992 with self.assertRaises(ObjNotReady) as err:
1994 obj = OctetString(value)
1995 self.assertTrue(obj.ready)
1998 pprint(obj, big_blobs=True, with_decode_path=True)
2000 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
2001 def test_comparison(self, value1, value2, tag1, tag2):
2002 for klass in (OctetString, OctetStringInherited):
2003 obj1 = klass(value1)
2004 obj2 = klass(value2)
2005 self.assertEqual(obj1 == obj2, value1 == value2)
2006 self.assertEqual(obj1 != obj2, value1 != value2)
2007 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2008 obj1 = klass(value1, impl=tag1)
2009 obj2 = klass(value1, impl=tag2)
2010 self.assertEqual(obj1 == obj2, tag1 == tag2)
2011 self.assertEqual(obj1 != obj2, tag1 != tag2)
2013 @given(lists(binary()))
2014 def test_sorted_works(self, values):
2015 self.assertSequenceEqual(
2016 [bytes(v) for v in sorted(OctetString(v) for v in values)],
2020 @given(data_strategy())
2021 def test_bounds_satisfied(self, d):
2022 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2023 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2024 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
2025 OctetString(value=value, bounds=(bound_min, bound_max))
2027 @given(data_strategy())
2028 def test_bounds_unsatisfied(self, d):
2029 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2030 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2031 value = d.draw(binary(max_size=bound_min - 1))
2032 with self.assertRaises(BoundsError) as err:
2033 OctetString(value=value, bounds=(bound_min, bound_max))
2035 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2036 OctetString(bounds=(bound_min, bound_max)).decode(
2037 OctetString(value).encode()
2040 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2041 OctetString(bounds=(bound_min, bound_max)).decode(
2042 encode2pass(OctetString(value))
2044 value = d.draw(binary(min_size=bound_max + 1))
2045 with self.assertRaises(BoundsError) as err:
2046 OctetString(value=value, bounds=(bound_min, bound_max))
2048 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2049 OctetString(bounds=(bound_min, bound_max)).decode(
2050 OctetString(value).encode()
2053 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2054 OctetString(bounds=(bound_min, bound_max)).decode(
2055 encode2pass(OctetString(value))
2058 @given(data_strategy())
2059 def test_call(self, d):
2060 for klass in (OctetString, OctetStringInherited):
2069 ) = d.draw(octet_string_values_strategy())
2070 obj_initial = klass(
2076 optional_initial or False,
2087 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
2088 if (default is None) and (obj_initial.default is not None):
2091 (bounds is None) and
2092 (value is not None) and
2093 (bounds_initial is not None) and
2094 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2098 (bounds is None) and
2099 (default is not None) and
2100 (bounds_initial is not None) and
2101 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2104 obj = obj_initial(value, bounds, impl, expl, default, optional)
2106 value_expected = default if value is None else value
2108 default_initial if value_expected is None
2111 self.assertEqual(obj, value_expected)
2112 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2113 self.assertEqual(obj.expl_tag, expl or expl_initial)
2116 default_initial if default is None else default,
2118 if obj.default is None:
2119 optional = optional_initial if optional is None else optional
2120 optional = False if optional is None else optional
2123 self.assertEqual(obj.optional, optional)
2125 (obj._bound_min, obj._bound_max),
2126 bounds or bounds_initial or (0, float("+inf")),
2129 @given(octet_string_values_strategy())
2130 def test_copy(self, values):
2131 for klass in (OctetString, OctetStringInherited):
2132 obj = klass(*values)
2133 for copy_func in copy_funcs:
2134 obj_copied = copy_func(obj)
2135 self.assert_copied_basic_fields(obj, obj_copied)
2136 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2137 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2138 self.assertEqual(obj._value, obj_copied._value)
2142 integers(min_value=1).map(tag_encode),
2144 def test_stripped(self, value, tag_impl):
2145 obj = OctetString(value, impl=tag_impl)
2146 with self.assertRaises(NotEnoughData):
2147 obj.decode(obj.encode()[:-1])
2151 integers(min_value=1).map(tag_ctxc),
2153 def test_stripped_expl(self, value, tag_expl):
2154 obj = OctetString(value, expl=tag_expl)
2155 with self.assertRaises(NotEnoughData):
2156 obj.decode(obj.encode()[:-1])
2159 integers(min_value=31),
2160 integers(min_value=0),
2163 def test_bad_tag(self, tag, offset, decode_path):
2164 with self.assertRaises(DecodeError) as err:
2165 OctetString().decode(
2166 tag_encode(tag)[:-1],
2168 decode_path=decode_path,
2171 self.assertEqual(err.exception.offset, offset)
2172 self.assertEqual(err.exception.decode_path, decode_path)
2175 integers(min_value=128),
2176 integers(min_value=0),
2179 def test_bad_len(self, l, offset, decode_path):
2180 with self.assertRaises(DecodeError) as err:
2181 OctetString().decode(
2182 OctetString.tag_default + len_encode(l)[:-1],
2184 decode_path=decode_path,
2187 self.assertEqual(err.exception.offset, offset)
2188 self.assertEqual(err.exception.decode_path, decode_path)
2191 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2192 integers(min_value=0),
2195 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2196 value, bound_min = list(sorted(ints))
2198 class String(OctetString):
2199 bounds = (bound_min, bound_min)
2200 with self.assertRaises(DecodeError) as err:
2202 OctetString(b"\x00" * value).encode(),
2204 decode_path=decode_path,
2207 self.assertEqual(err.exception.offset, offset)
2208 self.assertEqual(err.exception.decode_path, decode_path)
2210 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2212 octet_string_values_strategy(),
2214 integers(min_value=1).map(tag_ctxc),
2215 integers(min_value=0),
2219 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2220 for klass in (OctetString, OctetStringInherited):
2221 _, _, _, _, default, optional, _decoded = values
2230 pprint(obj, big_blobs=True, with_decode_path=True)
2231 self.assertFalse(obj.expled)
2232 obj_encoded = obj.encode()
2233 self.assertEqual(encode2pass(obj), obj_encoded)
2234 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2235 obj_expled = obj(value, expl=tag_expl)
2236 self.assertTrue(obj_expled.expled)
2238 list(obj_expled.pps())
2239 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2240 obj_expled_encoded = obj_expled.encode()
2241 obj_expled_cer = encode_cer(obj_expled)
2242 self.assertNotEqual(obj_expled_cer, obj_encoded)
2243 self.assertSequenceEqual(
2244 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2247 ctx_copied = deepcopy(ctx_dummy)
2248 obj_decoded, tail = obj_expled.decode(
2249 obj_expled_encoded + tail_junk,
2253 self.assertDictEqual(ctx_copied, ctx_dummy)
2255 list(obj_decoded.pps())
2256 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2257 self.assertEqual(tail, tail_junk)
2258 self.assertEqual(obj_decoded, obj_expled)
2259 self.assertNotEqual(obj_decoded, obj)
2260 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2261 self.assertEqual(bytes(obj_decoded), bytes(obj))
2262 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2263 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2264 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2266 obj_decoded.expl_llen,
2267 len(len_encode(len(obj_encoded))),
2269 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2270 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2273 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2275 self.assertEqual(obj_decoded.expl_offset, offset)
2276 assert_exceeding_data(
2278 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2282 evgens = list(obj_expled.decode_evgen(
2283 obj_expled_encoded + tail_junk,
2285 decode_path=decode_path,
2288 self.assertEqual(len(evgens), 1)
2289 _decode_path, obj, tail = evgens[0]
2290 self.assertSequenceEqual(tail, tail_junk)
2291 self.assertEqual(_decode_path, decode_path)
2292 self.assertEqual(obj.expl_offset, offset)
2296 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2298 integers(min_value=1, max_value=30),
2301 binary(min_size=1, max_size=5),
2303 binary(min_size=1, max_size=5),
2314 def test_constructed(self, impl, chunk_inputs, junk, decode_path):
2315 def chunk_constructed(contents):
2317 tag_encode(form=TagFormConstructed, num=4) +
2319 b"".join(OctetString(content).encode() for content in contents) +
2323 chunks_len_expected = []
2324 payload_expected = b""
2325 for chunk_input in chunk_inputs:
2326 if isinstance(chunk_input, bytes):
2327 chunks.append(OctetString(chunk_input).encode())
2328 payload_expected += chunk_input
2329 chunks_len_expected.append(len(chunk_input))
2331 chunks.append(chunk_constructed(chunk_input))
2332 payload = b"".join(chunk_input)
2333 payload_expected += payload
2334 for c in chunk_input:
2335 chunks_len_expected.append(len(c))
2336 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
2337 encoded_indefinite = (
2338 tag_encode(form=TagFormConstructed, num=impl) +
2343 encoded_definite = (
2344 tag_encode(form=TagFormConstructed, num=impl) +
2345 len_encode(len(b"".join(chunks))) +
2348 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
2349 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2350 for lenindef_expected, encoded in (
2351 (True, encoded_indefinite),
2352 (False, encoded_definite),
2354 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2356 ctx={"bered": True},
2358 self.assertSequenceEqual(tail, junk)
2359 self.assertSequenceEqual(bytes(obj), payload_expected)
2360 self.assertTrue(obj.ber_encoded)
2361 self.assertEqual(obj.lenindef, lenindef_expected)
2362 self.assertTrue(obj.bered)
2364 self.assertTrue(obj.ber_encoded)
2365 self.assertEqual(obj.lenindef, lenindef_expected)
2366 self.assertTrue(obj.bered)
2367 self.assertEqual(len(encoded), obj.tlvlen)
2370 pprint(obj, big_blobs=True, with_decode_path=True)
2372 evgens = list(OctetString(impl=tag_encode(impl)).decode_evgen(
2374 decode_path=decode_path,
2375 ctx={"bered": True},
2377 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
2378 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
2379 self.assertGreater(len(dp), len(decode_path))
2380 self.assertEqual(obj.vlen, chunk_len_expected)
2383 integers(min_value=0),
2386 def test_ber_definite_too_short(self, offset, decode_path):
2387 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
2388 OctetString().decode(
2389 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2391 decode_path=decode_path,
2392 ctx={"bered": True},
2394 self.assertEqual(err.exception.decode_path, decode_path)
2395 self.assertEqual(err.exception.offset, offset)
2398 integers(min_value=0),
2400 integers(min_value=1, max_value=3),
2402 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2403 bs = OctetString(b"data").encode()
2404 with self.assertRaises(NotEnoughData) as err:
2405 OctetString().decode(
2406 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2408 decode_path=decode_path,
2409 ctx={"bered": True},
2411 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2412 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2415 integers(min_value=0),
2417 integers(min_value=1, max_value=3),
2419 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2420 bs = OctetString(b"data").encode()
2421 bs_longer = OctetString(b"data-longer").encode()
2422 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
2423 OctetString().decode(
2425 tag_encode(4, form=TagFormConstructed) +
2426 len_encode((chunks + 1) * len(bs)) +
2431 decode_path=decode_path,
2432 ctx={"bered": True},
2434 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2435 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2437 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2438 @given(integers(min_value=1001, max_value=3000))
2439 def test_cer(self, data_len):
2440 data = urandom(data_len)
2441 encoded = encode_cer(OctetString(data))
2442 ctx = {"bered": True}
2443 self.assertSequenceEqual(bytes(OctetString().decod(encoded, ctx=ctx)), data)
2444 evgens = list(OctetString().decode_evgen(encoded, ctx=ctx))
2445 evgens_expected = data_len // 1000
2446 if evgens_expected * 1000 != data_len:
2447 evgens_expected += 1
2448 evgens_expected += 1
2449 self.assertEqual(len(evgens), evgens_expected)
2450 for (_, obj, _) in evgens[:-2]:
2451 self.assertEqual(obj.vlen, 1000)
2452 _, obj, _ = evgens[-2]
2453 self.assertEqual(obj.vlen, data_len - len(evgens[:-2]) * 1000)
2457 def null_values_strategy(draw, do_expl=False):
2461 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2463 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2464 optional = draw(one_of(none(), booleans()))
2466 draw(integers(min_value=0)),
2467 draw(integers(min_value=0)),
2468 draw(integers(min_value=0)),
2470 return (impl, expl, optional, _decoded)
2473 class NullInherited(Null):
2477 class TestNull(CommonMixin, TestCase):
2480 def test_ready(self):
2482 self.assertTrue(obj.ready)
2485 pprint(obj, big_blobs=True, with_decode_path=True)
2487 @given(binary(min_size=1), binary(min_size=1))
2488 def test_comparison(self, tag1, tag2):
2489 for klass in (Null, NullInherited):
2490 obj1 = klass(impl=tag1)
2491 obj2 = klass(impl=tag2)
2492 self.assertEqual(obj1 == obj2, tag1 == tag2)
2493 self.assertEqual(obj1 != obj2, tag1 != tag2)
2494 self.assertNotEqual(obj1, tag2)
2496 @given(data_strategy())
2497 def test_call(self, d):
2498 for klass in (Null, NullInherited):
2504 ) = d.draw(null_values_strategy())
2505 obj_initial = klass(
2508 optional=optional_initial or False,
2509 _decoded=_decoded_initial,
2516 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2517 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2518 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2519 self.assertEqual(obj.expl_tag, expl or expl_initial)
2520 optional = optional_initial if optional is None else optional
2521 optional = False if optional is None else optional
2522 self.assertEqual(obj.optional, optional)
2524 @given(null_values_strategy())
2525 def test_copy(self, values):
2526 for klass in (Null, NullInherited):
2527 impl, expl, optional, _decoded = values
2531 optional=optional or False,
2534 for copy_func in copy_funcs:
2535 obj_copied = copy_func(obj)
2536 self.assert_copied_basic_fields(obj, obj_copied)
2538 @given(integers(min_value=1).map(tag_encode))
2539 def test_stripped(self, tag_impl):
2540 obj = Null(impl=tag_impl)
2541 with self.assertRaises(NotEnoughData):
2542 obj.decode(obj.encode()[:-1])
2544 @given(integers(min_value=1).map(tag_ctxc))
2545 def test_stripped_expl(self, tag_expl):
2546 obj = Null(expl=tag_expl)
2547 with self.assertRaises(NotEnoughData):
2548 obj.decode(obj.encode()[:-1])
2551 integers(min_value=31),
2552 integers(min_value=0),
2555 def test_bad_tag(self, tag, offset, decode_path):
2556 with self.assertRaises(DecodeError) as err:
2558 tag_encode(tag)[:-1],
2560 decode_path=decode_path,
2563 self.assertEqual(err.exception.offset, offset)
2564 self.assertEqual(err.exception.decode_path, decode_path)
2567 integers(min_value=128),
2568 integers(min_value=0),
2571 def test_bad_len(self, l, offset, decode_path):
2572 with self.assertRaises(DecodeError) as err:
2574 Null.tag_default + len_encode(l)[:-1],
2576 decode_path=decode_path,
2579 self.assertEqual(err.exception.offset, offset)
2580 self.assertEqual(err.exception.decode_path, decode_path)
2582 @given(binary(min_size=1))
2583 def test_tag_mismatch(self, impl):
2584 assume(impl != Null.tag_default)
2585 with self.assertRaises(TagMismatch):
2586 Null(impl=impl).decode(Null().encode())
2589 null_values_strategy(),
2590 integers(min_value=1).map(tag_ctxc),
2591 integers(min_value=0),
2595 def test_symmetric(self, values, tag_expl, offset, tail_junk, decode_path):
2596 for klass in (Null, NullInherited):
2597 _, _, optional, _decoded = values
2598 obj = klass(optional=optional, _decoded=_decoded)
2601 pprint(obj, big_blobs=True, with_decode_path=True)
2602 self.assertFalse(obj.expled)
2603 obj_encoded = obj.encode()
2604 self.assertEqual(encode2pass(obj), obj_encoded)
2605 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2606 obj_expled = obj(expl=tag_expl)
2607 self.assertTrue(obj_expled.expled)
2609 list(obj_expled.pps())
2610 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2611 obj_expled_encoded = obj_expled.encode()
2612 obj_expled_cer = encode_cer(obj_expled)
2613 self.assertNotEqual(obj_expled_cer, obj_encoded)
2614 self.assertSequenceEqual(
2615 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2618 ctx_copied = deepcopy(ctx_dummy)
2619 obj_decoded, tail = obj_expled.decode(
2620 obj_expled_encoded + tail_junk,
2624 self.assertDictEqual(ctx_copied, ctx_dummy)
2626 list(obj_decoded.pps())
2627 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2628 self.assertEqual(tail, tail_junk)
2629 self.assertEqual(obj_decoded, obj_expled)
2630 self.assertNotEqual(obj_decoded, obj)
2631 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2632 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2633 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2635 obj_decoded.expl_llen,
2636 len(len_encode(len(obj_encoded))),
2638 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2639 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2642 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2644 self.assertEqual(obj_decoded.expl_offset, offset)
2645 assert_exceeding_data(
2647 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2651 evgens = list(obj_expled.decode_evgen(
2652 obj_expled_encoded + tail_junk,
2654 decode_path=decode_path,
2657 self.assertEqual(len(evgens), 1)
2658 _decode_path, obj, tail = evgens[0]
2659 self.assertSequenceEqual(tail, tail_junk)
2660 self.assertEqual(_decode_path, decode_path)
2661 self.assertEqual(obj, obj_decoded)
2662 self.assertEqual(obj.expl_offset, offset)
2666 @given(integers(min_value=1))
2667 def test_invalid_len(self, l):
2668 with self.assertRaises(InvalidLength):
2669 Null().decode(b"".join((
2676 def oid_strategy(draw):
2677 first_arc = draw(integers(min_value=0, max_value=2))
2679 if first_arc in (0, 1):
2680 second_arc = draw(integers(min_value=0, max_value=39))
2682 second_arc = draw(integers(min_value=0))
2683 other_arcs = draw(lists(integers(min_value=0)))
2684 return tuple([first_arc, second_arc] + other_arcs)
2688 def oid_values_strategy(draw, do_expl=False):
2689 value = draw(one_of(none(), oid_strategy()))
2693 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2695 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2696 default = draw(one_of(none(), oid_strategy()))
2697 optional = draw(one_of(none(), booleans()))
2699 draw(integers(min_value=0)),
2700 draw(integers(min_value=0)),
2701 draw(integers(min_value=0)),
2703 return (value, impl, expl, default, optional, _decoded)
2706 class ObjectIdentifierInherited(ObjectIdentifier):
2710 class TestObjectIdentifier(CommonMixin, TestCase):
2711 base_klass = ObjectIdentifier
2713 def test_invalid_value_type(self):
2714 with self.assertRaises(InvalidValueType) as err:
2715 ObjectIdentifier(123)
2719 def test_optional(self, optional):
2720 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2721 self.assertTrue(obj.optional)
2723 @given(oid_strategy())
2724 def test_ready(self, value):
2725 obj = ObjectIdentifier()
2726 self.assertFalse(obj.ready)
2729 pprint(obj, big_blobs=True, with_decode_path=True)
2730 with self.assertRaises(ObjNotReady) as err:
2733 with self.assertRaises(ObjNotReady) as err:
2735 obj = ObjectIdentifier(value)
2736 self.assertTrue(obj.ready)
2737 self.assertFalse(obj.ber_encoded)
2740 pprint(obj, big_blobs=True, with_decode_path=True)
2743 @given(oid_strategy(), oid_strategy(), binary(min_size=1), binary(min_size=1))
2744 def test_comparison(self, value1, value2, tag1, tag2):
2745 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2746 obj1 = klass(value1)
2747 obj2 = klass(value2)
2748 self.assertEqual(obj1 == obj2, value1 == value2)
2749 self.assertEqual(obj1 != obj2, value1 != value2)
2750 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2751 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2752 obj1 = klass(value1, impl=tag1)
2753 obj2 = klass(value1, impl=tag2)
2754 self.assertEqual(obj1 == obj2, tag1 == tag2)
2755 self.assertEqual(obj1 != obj2, tag1 != tag2)
2757 @given(lists(oid_strategy()))
2758 def test_sorted_works(self, values):
2759 self.assertSequenceEqual(
2760 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2764 @given(data_strategy())
2765 def test_call(self, d):
2766 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2774 ) = d.draw(oid_values_strategy())
2775 obj_initial = klass(
2776 value=value_initial,
2779 default=default_initial,
2780 optional=optional_initial or False,
2781 _decoded=_decoded_initial,
2790 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2799 value_expected = default if value is None else value
2801 default_initial if value_expected is None
2804 self.assertEqual(obj, value_expected)
2805 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2806 self.assertEqual(obj.expl_tag, expl or expl_initial)
2809 default_initial if default is None else default,
2811 if obj.default is None:
2812 optional = optional_initial if optional is None else optional
2813 optional = False if optional is None else optional
2816 self.assertEqual(obj.optional, optional)
2818 @given(oid_values_strategy())
2819 def test_copy(self, values):
2820 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2837 for copy_func in copy_funcs:
2838 obj_copied = copy_func(obj)
2839 self.assert_copied_basic_fields(obj, obj_copied)
2840 self.assertEqual(obj._value, obj_copied._value)
2842 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2845 integers(min_value=1).map(tag_encode),
2847 def test_stripped(self, value, tag_impl):
2848 obj = ObjectIdentifier(value, impl=tag_impl)
2849 with self.assertRaises(NotEnoughData):
2850 obj.decode(obj.encode()[:-1])
2854 integers(min_value=1).map(tag_ctxc),
2856 def test_stripped_expl(self, value, tag_expl):
2857 obj = ObjectIdentifier(value, expl=tag_expl)
2858 with self.assertRaises(NotEnoughData):
2859 obj.decode(obj.encode()[:-1])
2862 integers(min_value=31),
2863 integers(min_value=0),
2866 def test_bad_tag(self, tag, offset, decode_path):
2867 with self.assertRaises(DecodeError) as err:
2868 ObjectIdentifier().decode(
2869 tag_encode(tag)[:-1],
2871 decode_path=decode_path,
2874 self.assertEqual(err.exception.offset, offset)
2875 self.assertEqual(err.exception.decode_path, decode_path)
2878 integers(min_value=128),
2879 integers(min_value=0),
2882 def test_bad_len(self, l, offset, decode_path):
2883 with self.assertRaises(DecodeError) as err:
2884 ObjectIdentifier().decode(
2885 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2887 decode_path=decode_path,
2890 self.assertEqual(err.exception.offset, offset)
2891 self.assertEqual(err.exception.decode_path, decode_path)
2893 def test_zero_oid(self):
2894 with self.assertRaises(NotEnoughData):
2895 ObjectIdentifier().decode(
2896 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2899 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2900 @given(oid_strategy())
2901 def test_unfinished_oid(self, value):
2902 assume(list(value)[-1] > 255)
2903 obj_encoded = ObjectIdentifier(value).encode()
2904 obj, _ = ObjectIdentifier().decode(obj_encoded)
2905 data = obj_encoded[obj.tlen + obj.llen:-1]
2907 ObjectIdentifier.tag_default,
2908 len_encode(len(data)),
2911 with self.assertRaisesRegex(DecodeError, "unfinished OID"):
2914 @given(integers(min_value=0))
2915 def test_invalid_short(self, value):
2916 with self.assertRaises(InvalidOID):
2917 ObjectIdentifier((value,))
2918 with self.assertRaises(InvalidOID):
2919 ObjectIdentifier("%d" % value)
2921 @given(integers(min_value=3), integers(min_value=0))
2922 def test_invalid_first_arc(self, first_arc, second_arc):
2923 with self.assertRaises(InvalidOID):
2924 ObjectIdentifier((first_arc, second_arc))
2925 with self.assertRaises(InvalidOID):
2926 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2928 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2929 def test_invalid_second_arc(self, first_arc, second_arc):
2930 with self.assertRaises(InvalidOID):
2931 ObjectIdentifier((first_arc, second_arc))
2932 with self.assertRaises(InvalidOID):
2933 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2935 @given(text(alphabet=ascii_letters + ".", min_size=1))
2936 def test_junk(self, oid):
2937 with self.assertRaises(InvalidOID):
2938 ObjectIdentifier(oid)
2940 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2941 @given(oid_strategy())
2942 def test_validness(self, oid):
2943 obj = ObjectIdentifier(oid)
2944 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2947 pprint(obj, big_blobs=True, with_decode_path=True)
2949 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2951 oid_values_strategy(),
2953 integers(min_value=1).map(tag_ctxc),
2954 integers(min_value=0),
2958 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2959 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2960 _, _, _, default, optional, _decoded = values
2969 pprint(obj, big_blobs=True, with_decode_path=True)
2970 self.assertFalse(obj.expled)
2971 obj_encoded = obj.encode()
2972 self.assertEqual(encode2pass(obj), obj_encoded)
2973 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2974 obj_expled = obj(value, expl=tag_expl)
2975 self.assertTrue(obj_expled.expled)
2977 list(obj_expled.pps())
2978 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2979 obj_expled_encoded = obj_expled.encode()
2980 obj_expled_cer = encode_cer(obj_expled)
2981 self.assertNotEqual(obj_expled_cer, obj_encoded)
2982 self.assertSequenceEqual(
2983 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2986 ctx_copied = deepcopy(ctx_dummy)
2987 obj_decoded, tail = obj_expled.decode(
2988 obj_expled_encoded + tail_junk,
2992 self.assertDictEqual(ctx_copied, ctx_dummy)
2994 list(obj_decoded.pps())
2995 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2996 self.assertEqual(tail, tail_junk)
2997 self.assertEqual(obj_decoded, obj_expled)
2998 self.assertNotEqual(obj_decoded, obj)
2999 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
3000 self.assertEqual(tuple(obj_decoded), tuple(obj))
3001 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3002 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3003 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3005 obj_decoded.expl_llen,
3006 len(len_encode(len(obj_encoded))),
3008 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3009 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3012 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3014 self.assertEqual(obj_decoded.expl_offset, offset)
3015 assert_exceeding_data(
3017 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3021 evgens = list(obj_expled.decode_evgen(
3022 obj_expled_encoded + tail_junk,
3024 decode_path=decode_path,
3027 self.assertEqual(len(evgens), 1)
3028 _decode_path, obj, tail = evgens[0]
3029 self.assertSequenceEqual(tail, tail_junk)
3030 self.assertEqual(_decode_path, decode_path)
3031 self.assertEqual(obj, obj_decoded)
3032 self.assertEqual(obj.expl_offset, offset)
3037 oid_strategy().map(ObjectIdentifier),
3038 oid_strategy().map(ObjectIdentifier),
3040 def test_add(self, oid1, oid2):
3041 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
3042 for oid_to_add in (oid2, tuple(oid2)):
3043 self.assertEqual(oid1 + oid_to_add, oid_expect)
3044 with self.assertRaises(InvalidValueType):
3047 def test_go_vectors_valid(self):
3048 for data, expect in (
3050 (b"\x55\x02", (2, 5, 2)),
3051 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
3052 (b"\x81\x34\x03", (2, 100, 3)),
3055 ObjectIdentifier().decode(b"".join((
3056 ObjectIdentifier.tag_default,
3057 len_encode(len(data)),
3063 def test_go_vectors_invalid(self):
3064 data = b"\x55\x02\xc0\x80\x80\x80\x80"
3065 with self.assertRaises(DecodeError):
3066 ObjectIdentifier().decode(b"".join((
3067 Integer.tag_default,
3068 len_encode(len(data)),
3072 def test_go_non_minimal_encoding(self):
3073 with self.assertRaises(DecodeError):
3074 ObjectIdentifier().decode(hexdec("060a2a80864886f70d01010b"))
3076 def test_x690_vector(self):
3078 ObjectIdentifier().decode(hexdec("0603883703"))[0],
3079 ObjectIdentifier((2, 999, 3)),
3082 def test_nonnormalized_first_arc(self):
3084 ObjectIdentifier.tag_default +
3087 ObjectIdentifier((1, 0)).encode()[-1:]
3089 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3090 self.assertTrue(obj.ber_encoded)
3091 self.assertTrue(obj.bered)
3093 self.assertTrue(obj.ber_encoded)
3094 self.assertTrue(obj.bered)
3095 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3096 ObjectIdentifier().decode(tampered)
3098 @given(data_strategy())
3099 def test_negative_arcs(self, d):
3100 oid = list(d.draw(oid_strategy()))
3103 idx = d.draw(integers(min_value=3, max_value=len(oid)))
3105 if oid[idx - 1] == 0:
3107 with self.assertRaises(InvalidOID):
3108 ObjectIdentifier(tuple(oid))
3109 with self.assertRaises(InvalidOID):
3110 ObjectIdentifier(".".join(str(i) for i in oid))
3112 @given(data_strategy())
3113 def test_plused_arcs(self, d):
3114 oid = [str(arc) for arc in d.draw(oid_strategy())]
3115 idx = d.draw(integers(min_value=0, max_value=len(oid)))
3116 oid[idx - 1] = "+" + oid[idx - 1]
3117 with self.assertRaises(InvalidOID):
3118 ObjectIdentifier(".".join(str(i) for i in oid))
3120 @given(data_strategy())
3121 def test_nonnormalized_arcs(self, d):
3122 arcs = d.draw(lists(
3123 integers(min_value=0, max_value=100),
3127 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
3128 _, _, lv = tag_strip(dered)
3129 _, _, v = len_decode(lv)
3130 v_no_first_arc = v[1:]
3131 idx_for_tamper = d.draw(integers(
3133 max_value=len(v_no_first_arc) - 1,
3135 tampered = list(bytearray(v_no_first_arc))
3136 for _ in range(d.draw(integers(min_value=1, max_value=3))):
3137 tampered.insert(idx_for_tamper, 0x80)
3138 tampered = bytes(bytearray(tampered))
3140 ObjectIdentifier.tag_default +
3141 len_encode(len(tampered)) +
3144 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3145 self.assertTrue(obj.ber_encoded)
3146 self.assertTrue(obj.bered)
3148 self.assertTrue(obj.ber_encoded)
3149 self.assertTrue(obj.bered)
3150 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3151 ObjectIdentifier().decode(tampered)
3155 def enumerated_values_strategy(draw, schema=None, do_expl=False):
3157 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
3158 values = list(draw(sets(
3160 min_size=len(schema),
3161 max_size=len(schema),
3163 schema = list(zip(schema, values))
3164 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
3168 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3170 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3171 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
3172 optional = draw(one_of(none(), booleans()))
3174 draw(integers(min_value=0)),
3175 draw(integers(min_value=0)),
3176 draw(integers(min_value=0)),
3178 return (schema, value, impl, expl, default, optional, _decoded)
3181 class TestEnumerated(CommonMixin, TestCase):
3182 class EWhatever(Enumerated):
3183 schema = (("whatever", 0),)
3185 base_klass = EWhatever
3187 def test_schema_required(self):
3188 with self.assertRaisesRegex(ValueError, "schema must be specified"):
3191 def test_invalid_value_type(self):
3192 with self.assertRaises(InvalidValueType) as err:
3193 self.base_klass((1, 2))
3196 @given(sets(text_letters(), min_size=2))
3197 def test_unknown_name(self, schema_input):
3198 missing = schema_input.pop()
3200 class E(Enumerated):
3201 schema = [(n, 123) for n in schema_input]
3202 with self.assertRaises(ObjUnknown) as err:
3207 sets(text_letters(), min_size=2),
3208 sets(integers(), min_size=2),
3210 def test_unknown_value(self, schema_input, values_input):
3212 missing_value = values_input.pop()
3213 _input = list(zip(schema_input, values_input))
3215 class E(Enumerated):
3217 with self.assertRaises(DecodeError) as err:
3222 def test_optional(self, optional):
3223 obj = self.base_klass(default="whatever", optional=optional)
3224 self.assertTrue(obj.optional)
3226 def test_ready(self):
3227 obj = self.base_klass()
3228 self.assertFalse(obj.ready)
3231 pprint(obj, big_blobs=True, with_decode_path=True)
3232 with self.assertRaises(ObjNotReady) as err:
3235 obj = self.base_klass("whatever")
3236 self.assertTrue(obj.ready)
3239 pprint(obj, big_blobs=True, with_decode_path=True)
3241 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
3242 def test_comparison(self, value1, value2, tag1, tag2):
3243 class E(Enumerated):
3245 ("whatever0", value1),
3246 ("whatever1", value2),
3249 class EInherited(E):
3251 for klass in (E, EInherited):
3252 obj1 = klass(value1)
3253 obj2 = klass(value2)
3254 self.assertEqual(obj1 == obj2, value1 == value2)
3255 self.assertEqual(obj1 != obj2, value1 != value2)
3256 self.assertEqual(obj1 == int(obj2), value1 == value2)
3257 obj1 = klass(value1, impl=tag1)
3258 obj2 = klass(value1, impl=tag2)
3259 self.assertEqual(obj1 == obj2, tag1 == tag2)
3260 self.assertEqual(obj1 != obj2, tag1 != tag2)
3262 @given(data_strategy())
3263 def test_call(self, d):
3272 ) = d.draw(enumerated_values_strategy())
3274 class E(Enumerated):
3275 schema = schema_initial
3277 value=value_initial,
3280 default=default_initial,
3281 optional=optional_initial or False,
3282 _decoded=_decoded_initial,
3292 ) = d.draw(enumerated_values_strategy(
3293 schema=schema_initial,
3294 do_expl=impl_initial is None,
3304 value_expected = default if value is None else value
3306 default_initial if value_expected is None
3311 dict(schema_initial).get(value_expected, value_expected),
3313 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3314 self.assertEqual(obj.expl_tag, expl or expl_initial)
3317 default_initial if default is None else default,
3319 if obj.default is None:
3320 optional = optional_initial if optional is None else optional
3321 optional = False if optional is None else optional
3324 self.assertEqual(obj.optional, optional)
3325 self.assertEqual(obj.specs, dict(schema_initial))
3327 @given(enumerated_values_strategy())
3328 def test_copy(self, values):
3329 schema_input, value, impl, expl, default, optional, _decoded = values
3331 class E(Enumerated):
3332 schema = schema_input
3342 for copy_func in copy_funcs:
3343 obj_copied = copy_func(obj)
3344 self.assert_copied_basic_fields(obj, obj_copied)
3345 self.assertEqual(obj.specs, obj_copied.specs)
3347 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3348 @given(data_strategy())
3349 def test_symmetric(self, d):
3350 schema_input, _, _, _, default, optional, _decoded = d.draw(
3351 enumerated_values_strategy(),
3353 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3354 offset = d.draw(integers(min_value=0))
3355 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3356 tail_junk = d.draw(binary(max_size=5))
3357 decode_path = d.draw(decode_path_strat)
3359 class E(Enumerated):
3360 schema = schema_input
3369 pprint(obj, big_blobs=True, with_decode_path=True)
3370 self.assertFalse(obj.expled)
3371 obj_encoded = obj.encode()
3372 self.assertEqual(encode2pass(obj), obj_encoded)
3373 obj_expled = obj(value, expl=tag_expl)
3374 self.assertTrue(obj_expled.expled)
3376 list(obj_expled.pps())
3377 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3378 obj_expled_encoded = obj_expled.encode()
3379 ctx_copied = deepcopy(ctx_dummy)
3380 obj_decoded, tail = obj_expled.decode(
3381 obj_expled_encoded + tail_junk,
3385 self.assertDictEqual(ctx_copied, ctx_dummy)
3387 list(obj_decoded.pps())
3388 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3389 self.assertEqual(tail, tail_junk)
3390 self.assertEqual(obj_decoded, obj_expled)
3391 self.assertNotEqual(obj_decoded, obj)
3392 self.assertEqual(int(obj_decoded), int(obj_expled))
3393 self.assertEqual(int(obj_decoded), int(obj))
3394 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3395 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3396 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3398 obj_decoded.expl_llen,
3399 len(len_encode(len(obj_encoded))),
3401 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3402 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3405 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3407 self.assertEqual(obj_decoded.expl_offset, offset)
3408 assert_exceeding_data(
3410 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3414 evgens = list(obj_expled.decode_evgen(
3415 obj_expled_encoded + tail_junk,
3417 decode_path=decode_path,
3420 self.assertEqual(len(evgens), 1)
3421 _decode_path, obj, tail = evgens[0]
3422 self.assertSequenceEqual(tail, tail_junk)
3423 self.assertEqual(_decode_path, decode_path)
3424 self.assertEqual(obj, obj_decoded)
3425 self.assertEqual(obj.expl_offset, offset)
3431 def string_values_strategy(draw, alphabet, do_expl=False):
3432 bound_min, bound_max = sorted(draw(sets(
3433 integers(min_value=0, max_value=1 << 7),
3437 value = draw(one_of(
3439 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3441 default = draw(one_of(
3443 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3446 if draw(booleans()):
3447 bounds = (bound_min, bound_max)
3451 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3453 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3454 optional = draw(one_of(none(), booleans()))
3456 draw(integers(min_value=0)),
3457 draw(integers(min_value=0)),
3458 draw(integers(min_value=0)),
3460 return (value, bounds, impl, expl, default, optional, _decoded)
3463 class StringMixin(object):
3464 def test_invalid_value_type(self):
3465 with self.assertRaises(InvalidValueType) as err:
3466 self.base_klass((1, 2))
3469 def text_alphabet(self):
3470 return "".join(chr(c) for c in range(256))
3473 def test_optional(self, optional):
3474 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3475 self.assertTrue(obj.optional)
3477 @given(data_strategy())
3478 def test_ready(self, d):
3479 obj = self.base_klass()
3480 self.assertFalse(obj.ready)
3483 pprint(obj, big_blobs=True, with_decode_path=True)
3485 with self.assertRaises(ObjNotReady) as err:
3488 with self.assertRaises(ObjNotReady) as err:
3490 value = d.draw(text(alphabet=self.text_alphabet()))
3491 obj = self.base_klass(value)
3492 self.assertTrue(obj.ready)
3495 pprint(obj, big_blobs=True, with_decode_path=True)
3498 @given(data_strategy())
3499 def test_comparison(self, d):
3500 value1 = d.draw(text(alphabet=self.text_alphabet()))
3501 value2 = d.draw(text(alphabet=self.text_alphabet()))
3502 tag1 = d.draw(binary(min_size=1))
3503 tag2 = d.draw(binary(min_size=1))
3504 obj1 = self.base_klass(value1)
3505 obj2 = self.base_klass(value2)
3506 self.assertEqual(obj1 == obj2, value1 == value2)
3507 self.assertEqual(obj1 != obj2, value1 != value2)
3508 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3509 self.assertEqual(obj1 == str(obj2), value1 == value2)
3510 obj1 = self.base_klass(value1, impl=tag1)
3511 obj2 = self.base_klass(value1, impl=tag2)
3512 self.assertEqual(obj1 == obj2, tag1 == tag2)
3513 self.assertEqual(obj1 != obj2, tag1 != tag2)
3515 @given(data_strategy())
3516 def test_bounds_satisfied(self, d):
3517 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3518 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3519 value = d.draw(text(
3520 alphabet=self.text_alphabet(),
3524 self.base_klass(value=value, bounds=(bound_min, bound_max))
3526 @given(data_strategy())
3527 def test_bounds_unsatisfied(self, d):
3528 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3529 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3530 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3531 with self.assertRaises(BoundsError) as err:
3532 self.base_klass(value=value, bounds=(bound_min, bound_max))
3534 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3535 self.base_klass(bounds=(bound_min, bound_max)).decode(
3536 self.base_klass(value).encode()
3539 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3540 self.base_klass(bounds=(bound_min, bound_max)).decode(
3541 encode2pass(self.base_klass(value))
3543 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3544 with self.assertRaises(BoundsError) as err:
3545 self.base_klass(value=value, bounds=(bound_min, bound_max))
3547 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3548 self.base_klass(bounds=(bound_min, bound_max)).decode(
3549 self.base_klass(value).encode()
3552 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3553 self.base_klass(bounds=(bound_min, bound_max)).decode(
3554 encode2pass(self.base_klass(value))
3557 @given(data_strategy())
3558 def test_call(self, d):
3567 ) = d.draw(string_values_strategy(self.text_alphabet()))
3568 obj_initial = self.base_klass(
3574 optional_initial or False,
3585 ) = d.draw(string_values_strategy(
3586 self.text_alphabet(),
3587 do_expl=impl_initial is None,
3589 if (default is None) and (obj_initial.default is not None):
3592 (bounds is None) and
3593 (value is not None) and
3594 (bounds_initial is not None) and
3595 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3599 (bounds is None) and
3600 (default is not None) and
3601 (bounds_initial is not None) and
3602 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3605 obj = obj_initial(value, bounds, impl, expl, default, optional)
3607 value_expected = default if value is None else value
3609 default_initial if value_expected is None
3612 self.assertEqual(obj, value_expected)
3613 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3614 self.assertEqual(obj.expl_tag, expl or expl_initial)
3617 default_initial if default is None else default,
3619 if obj.default is None:
3620 optional = optional_initial if optional is None else optional
3621 optional = False if optional is None else optional
3624 self.assertEqual(obj.optional, optional)
3626 (obj._bound_min, obj._bound_max),
3627 bounds or bounds_initial or (0, float("+inf")),
3630 @given(data_strategy())
3631 def test_copy(self, d):
3632 values = d.draw(string_values_strategy(self.text_alphabet()))
3633 obj = self.base_klass(*values)
3634 for copy_func in copy_funcs:
3635 obj_copied = copy_func(obj)
3636 self.assert_copied_basic_fields(obj, obj_copied)
3637 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3638 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3639 self.assertEqual(obj._value, obj_copied._value)
3641 @given(data_strategy())
3642 def test_stripped(self, d):
3643 value = d.draw(text(alphabet=self.text_alphabet()))
3644 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3645 obj = self.base_klass(value, impl=tag_impl)
3646 with self.assertRaises(NotEnoughData):
3647 obj.decode(obj.encode()[:-1])
3649 @given(data_strategy())
3650 def test_stripped_expl(self, d):
3651 value = d.draw(text(alphabet=self.text_alphabet()))
3652 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3653 obj = self.base_klass(value, expl=tag_expl)
3654 with self.assertRaises(NotEnoughData):
3655 obj.decode(obj.encode()[:-1])
3658 integers(min_value=31),
3659 integers(min_value=0),
3662 def test_bad_tag(self, tag, offset, decode_path):
3663 with self.assertRaises(DecodeError) as err:
3664 self.base_klass().decode(
3665 tag_encode(tag)[:-1],
3667 decode_path=decode_path,
3670 self.assertEqual(err.exception.offset, offset)
3671 self.assertEqual(err.exception.decode_path, decode_path)
3674 integers(min_value=128),
3675 integers(min_value=0),
3678 def test_bad_len(self, l, offset, decode_path):
3679 with self.assertRaises(DecodeError) as err:
3680 self.base_klass().decode(
3681 self.base_klass.tag_default + len_encode(l)[:-1],
3683 decode_path=decode_path,
3686 self.assertEqual(err.exception.offset, offset)
3687 self.assertEqual(err.exception.decode_path, decode_path)
3690 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3691 integers(min_value=0),
3694 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3695 value, bound_min = list(sorted(ints))
3697 class String(self.base_klass):
3698 # Multiply this value by four, to satisfy UTF-32 bounds
3699 # (4 bytes per character) validation
3700 bounds = (bound_min * 4, bound_min * 4)
3701 with self.assertRaises(DecodeError) as err:
3703 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3705 decode_path=decode_path,
3708 self.assertEqual(err.exception.offset, offset)
3709 self.assertEqual(err.exception.decode_path, decode_path)
3711 @given(data_strategy())
3712 def test_symmetric(self, d):
3713 values = d.draw(string_values_strategy(self.text_alphabet()))
3714 value = d.draw(text(alphabet=self.text_alphabet()))
3715 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3716 offset = d.draw(integers(min_value=0))
3717 tail_junk = d.draw(binary(max_size=5))
3718 decode_path = d.draw(decode_path_strat)
3719 _, _, _, _, default, optional, _decoded = values
3720 obj = self.base_klass(
3728 pprint(obj, big_blobs=True, with_decode_path=True)
3729 self.assertFalse(obj.expled)
3730 obj_encoded = obj.encode()
3731 self.assertEqual(encode2pass(obj), obj_encoded)
3732 obj_expled = obj(value, expl=tag_expl)
3733 self.assertTrue(obj_expled.expled)
3735 list(obj_expled.pps())
3736 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3737 obj_expled_encoded = obj_expled.encode()
3738 ctx_copied = deepcopy(ctx_dummy)
3739 obj_decoded, tail = obj_expled.decode(
3740 obj_expled_encoded + tail_junk,
3744 self.assertDictEqual(ctx_copied, ctx_dummy)
3746 list(obj_decoded.pps())
3747 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3748 self.assertEqual(tail, tail_junk)
3749 self.assertEqual(obj_decoded, obj_expled)
3750 self.assertNotEqual(obj_decoded, obj)
3751 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3752 self.assertEqual(bytes(obj_decoded), bytes(obj))
3753 self.assertEqual(str(obj_decoded), str(obj_expled))
3754 self.assertEqual(str(obj_decoded), str(obj))
3755 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3756 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3757 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3759 obj_decoded.expl_llen,
3760 len(len_encode(len(obj_encoded))),
3762 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3763 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3766 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3768 self.assertEqual(obj_decoded.expl_offset, offset)
3769 assert_exceeding_data(
3771 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3775 evgens = list(obj_expled.decode_evgen(
3776 obj_expled_encoded + tail_junk,
3778 decode_path=decode_path,
3781 self.assertEqual(len(evgens), 1)
3782 _decode_path, obj, tail = evgens[0]
3783 self.assertSequenceEqual(tail, tail_junk)
3784 self.assertEqual(_decode_path, decode_path)
3785 if not getattr(self, "evgen_mode_skip_value", True):
3786 self.assertEqual(obj, obj_decoded)
3787 self.assertEqual(obj.expl_offset, offset)
3792 cyrillic_letters = text(
3793 alphabet="".join(chr(i) for i in list(range(0x0410, 0x044f + 1))),
3799 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3800 base_klass = UTF8String
3802 @given(cyrillic_letters)
3803 def test_byte_per_primitive(self, chars):
3805 char_raw = char.encode("utf-8")
3806 encoded = b"".join((
3807 self.base_klass().tag_constructed,
3809 OctetString(char_raw[:1]).encode(),
3810 OctetString(char_raw[1:2]).encode(),
3814 self.base_klass().decod(encoded, ctx={"bered": True}),
3819 class UnicodeDecodeErrorMixin(object):
3820 @given(cyrillic_letters)
3821 def test_unicode_decode_error(self, cyrillic_text):
3822 with self.assertRaises(DecodeError):
3823 self.base_klass(cyrillic_text)
3826 class TestNumericString(StringMixin, CommonMixin, TestCase):
3827 base_klass = NumericString
3829 def text_alphabet(self):
3832 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3833 def test_non_numeric(self, non_numeric_text):
3834 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3835 self.base_klass(non_numeric_text)
3838 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3839 integers(min_value=0),
3842 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3843 value, bound_min = list(sorted(ints))
3845 class String(self.base_klass):
3846 bounds = (bound_min, bound_min)
3847 with self.assertRaises(DecodeError) as err:
3849 self.base_klass(b"1" * value).encode(),
3851 decode_path=decode_path,
3854 self.assertEqual(err.exception.offset, offset)
3855 self.assertEqual(err.exception.decode_path, decode_path)
3857 def test_byte_per_primitive(self):
3858 encoded = b"".join((
3859 self.base_klass().tag_constructed,
3861 OctetString(b"1").encode(),
3862 OctetString(b"2").encode(),
3866 self.base_klass().decod(encoded, ctx={"bered": True}),
3871 class TestPrintableString(
3872 UnicodeDecodeErrorMixin,
3877 base_klass = PrintableString
3879 def text_alphabet(self):
3880 return ascii_letters + digits + " '()+,-./:=?"
3882 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3883 def test_non_printable(self, non_printable_text):
3884 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3885 self.base_klass(non_printable_text)
3888 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3889 integers(min_value=0),
3892 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3893 value, bound_min = list(sorted(ints))
3895 class String(self.base_klass):
3896 bounds = (bound_min, bound_min)
3897 with self.assertRaises(DecodeError) as err:
3899 self.base_klass(b"1" * value).encode(),
3901 decode_path=decode_path,
3904 self.assertEqual(err.exception.offset, offset)
3905 self.assertEqual(err.exception.decode_path, decode_path)
3907 def test_allowable_invalid_chars(self):
3909 ("*", {"allow_asterisk": True}),
3910 ("&", {"allow_ampersand": True}),
3911 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3914 obj = self.base_klass(s)
3915 for prop in kwargs.keys():
3916 self.assertFalse(getattr(obj, prop))
3918 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3920 self.base_klass(s, **kwargs)
3921 klass = self.base_klass(**kwargs)
3923 for prop in kwargs.keys():
3924 self.assertTrue(getattr(obj, prop))
3927 for prop in kwargs.keys():
3928 self.assertTrue(getattr(obj, prop))
3931 class TestTeletexString(
3932 UnicodeDecodeErrorMixin,
3937 base_klass = TeletexString
3940 class TestVideotexString(
3941 UnicodeDecodeErrorMixin,
3946 base_klass = VideotexString
3949 class TestIA5String(
3950 UnicodeDecodeErrorMixin,
3955 base_klass = IA5String
3957 def text_alphabet(self):
3958 return "".join(chr(c) for c in range(128))
3960 @given(integers(min_value=128, max_value=255))
3961 def test_alphabet_bad(self, code):
3962 with self.assertRaises(DecodeError):
3963 self.base_klass().decod(
3964 self.base_klass.tag_default +
3966 bytes(bytearray([code])),
3970 class TestGraphicString(
3971 UnicodeDecodeErrorMixin,
3976 base_klass = GraphicString
3979 class TestVisibleString(
3980 UnicodeDecodeErrorMixin,
3985 base_klass = VisibleString
3987 def text_alphabet(self):
3988 return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
3990 def test_x690_vector(self):
3991 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3992 self.assertSequenceEqual(tail, b"")
3993 self.assertEqual(str(obj), "Jones")
3994 self.assertFalse(obj.ber_encoded)
3995 self.assertFalse(obj.lenindef)
3996 self.assertFalse(obj.bered)
3998 obj, tail = VisibleString().decode(
3999 hexdec("3A0904034A6F6E04026573"),
4000 ctx={"bered": True},
4002 self.assertSequenceEqual(tail, b"")
4003 self.assertEqual(str(obj), "Jones")
4004 self.assertTrue(obj.ber_encoded)
4005 self.assertFalse(obj.lenindef)
4006 self.assertTrue(obj.bered)
4008 self.assertTrue(obj.ber_encoded)
4009 self.assertFalse(obj.lenindef)
4010 self.assertTrue(obj.bered)
4012 obj, tail = VisibleString().decode(
4013 hexdec("3A8004034A6F6E040265730000"),
4014 ctx={"bered": True},
4016 self.assertSequenceEqual(tail, b"")
4017 self.assertEqual(str(obj), "Jones")
4018 self.assertTrue(obj.ber_encoded)
4019 self.assertTrue(obj.lenindef)
4020 self.assertTrue(obj.bered)
4022 self.assertTrue(obj.ber_encoded)
4023 self.assertTrue(obj.lenindef)
4024 self.assertTrue(obj.bered)
4027 integers(min_value=0, max_value=ord(" ") - 1),
4028 integers(min_value=ord("~") + 1, max_value=255),
4030 def test_alphabet_bad(self, code):
4031 with self.assertRaises(DecodeError):
4032 self.base_klass().decod(
4033 self.base_klass.tag_default +
4035 bytes(bytearray([code])),
4039 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
4040 integers(min_value=0),
4043 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
4044 value, bound_min = list(sorted(ints))
4046 class String(self.base_klass):
4047 bounds = (bound_min, bound_min)
4048 with self.assertRaises(DecodeError) as err:
4050 self.base_klass(b"1" * value).encode(),
4052 decode_path=decode_path,
4055 self.assertEqual(err.exception.offset, offset)
4056 self.assertEqual(err.exception.decode_path, decode_path)
4059 class TestGeneralString(
4060 UnicodeDecodeErrorMixin,
4065 base_klass = GeneralString
4068 class TestUniversalString(StringMixin, CommonMixin, TestCase):
4069 base_klass = UniversalString
4072 class TestBMPString(StringMixin, CommonMixin, TestCase):
4073 base_klass = BMPString
4077 def generalized_time_values_strategy(
4085 if draw(booleans()):
4086 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4088 value = value.replace(microsecond=0)
4090 if draw(booleans()):
4091 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4093 default = default.replace(microsecond=0)
4097 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4099 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4100 optional = draw(one_of(none(), booleans()))
4102 draw(integers(min_value=0)),
4103 draw(integers(min_value=0)),
4104 draw(integers(min_value=0)),
4106 return (value, impl, expl, default, optional, _decoded)
4109 class TimeMixin(object):
4110 def test_invalid_value_type(self):
4111 with self.assertRaises(InvalidValueType) as err:
4112 self.base_klass(datetime.now().timetuple())
4115 @given(data_strategy())
4116 def test_optional(self, d):
4117 default = d.draw(datetimes(
4118 min_value=self.min_datetime,
4119 max_value=self.max_datetime,
4121 optional = d.draw(booleans())
4122 obj = self.base_klass(default=default, optional=optional)
4123 self.assertTrue(obj.optional)
4125 @given(data_strategy())
4126 def test_ready(self, d):
4127 obj = self.base_klass()
4128 self.assertFalse(obj.ready)
4131 pprint(obj, big_blobs=True, with_decode_path=True)
4132 with self.assertRaises(ObjNotReady) as err:
4135 with self.assertRaises(ObjNotReady) as err:
4137 value = d.draw(datetimes(
4138 min_value=self.min_datetime,
4139 max_value=self.max_datetime,
4141 obj = self.base_klass(value)
4142 self.assertTrue(obj.ready)
4145 pprint(obj, big_blobs=True, with_decode_path=True)
4147 @given(data_strategy())
4148 def test_comparison(self, d):
4149 value1 = d.draw(datetimes(
4150 min_value=self.min_datetime,
4151 max_value=self.max_datetime,
4153 value2 = d.draw(datetimes(
4154 min_value=self.min_datetime,
4155 max_value=self.max_datetime,
4157 tag1 = d.draw(binary(min_size=1))
4158 tag2 = d.draw(binary(min_size=1))
4160 value1 = value1.replace(microsecond=0)
4161 value2 = value2.replace(microsecond=0)
4162 obj1 = self.base_klass(value1)
4163 obj2 = self.base_klass(value2)
4164 self.assertEqual(obj1 == obj2, value1 == value2)
4165 self.assertEqual(obj1 != obj2, value1 != value2)
4166 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
4167 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4168 obj1 = self.base_klass(value1, impl=tag1)
4169 obj2 = self.base_klass(value1, impl=tag2)
4170 self.assertEqual(obj1 == obj2, tag1 == tag2)
4171 self.assertEqual(obj1 != obj2, tag1 != tag2)
4173 @given(data_strategy())
4174 def test_call(self, d):
4182 ) = d.draw(generalized_time_values_strategy(
4183 min_datetime=self.min_datetime,
4184 max_datetime=self.max_datetime,
4185 omit_ms=self.omit_ms,
4187 obj_initial = self.base_klass(
4188 value=value_initial,
4191 default=default_initial,
4192 optional=optional_initial or False,
4193 _decoded=_decoded_initial,
4202 ) = d.draw(generalized_time_values_strategy(
4203 min_datetime=self.min_datetime,
4204 max_datetime=self.max_datetime,
4205 omit_ms=self.omit_ms,
4206 do_expl=impl_initial is None,
4216 value_expected = default if value is None else value
4218 default_initial if value_expected is None
4221 self.assertEqual(obj, value_expected)
4222 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4223 self.assertEqual(obj.expl_tag, expl or expl_initial)
4226 default_initial if default is None else default,
4228 if obj.default is None:
4229 optional = optional_initial if optional is None else optional
4230 optional = False if optional is None else optional
4233 self.assertEqual(obj.optional, optional)
4235 @given(data_strategy())
4236 def test_copy(self, d):
4237 values = d.draw(generalized_time_values_strategy(
4238 min_datetime=self.min_datetime,
4239 max_datetime=self.max_datetime,
4241 obj = self.base_klass(*values)
4242 for copy_func in copy_funcs:
4243 obj_copied = copy_func(obj)
4244 self.assert_copied_basic_fields(obj, obj_copied)
4245 self.assertEqual(obj._value, obj_copied._value)
4247 @given(data_strategy())
4248 def test_stripped(self, d):
4249 value = d.draw(datetimes(
4250 min_value=self.min_datetime,
4251 max_value=self.max_datetime,
4253 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4254 obj = self.base_klass(value, impl=tag_impl)
4255 with self.assertRaises(NotEnoughData):
4256 obj.decode(obj.encode()[:-1])
4258 @given(data_strategy())
4259 def test_stripped_expl(self, d):
4260 value = d.draw(datetimes(
4261 min_value=self.min_datetime,
4262 max_value=self.max_datetime,
4264 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4265 obj = self.base_klass(value, expl=tag_expl)
4266 with self.assertRaises(NotEnoughData):
4267 obj.decode(obj.encode()[:-1])
4269 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4270 @given(data_strategy())
4271 def test_symmetric(self, d):
4272 values = d.draw(generalized_time_values_strategy(
4273 min_datetime=self.min_datetime,
4274 max_datetime=self.max_datetime,
4276 value = d.draw(datetimes(
4277 min_value=self.min_datetime,
4278 max_value=self.max_datetime,
4280 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4281 offset = d.draw(integers(min_value=0))
4282 tail_junk = d.draw(binary(max_size=5))
4283 _, _, _, default, optional, _decoded = values
4284 obj = self.base_klass(
4292 pprint(obj, big_blobs=True, with_decode_path=True)
4293 self.assertFalse(obj.expled)
4294 obj_encoded = obj.encode()
4295 self.assertEqual(encode2pass(obj), obj_encoded)
4296 self.additional_symmetric_check(value, obj_encoded)
4297 obj_expled = obj(value, expl=tag_expl)
4298 self.assertTrue(obj_expled.expled)
4300 list(obj_expled.pps())
4301 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4302 obj_expled_encoded = obj_expled.encode()
4303 ctx_copied = deepcopy(ctx_dummy)
4304 obj_decoded, tail = obj_expled.decode(
4305 obj_expled_encoded + tail_junk,
4309 self.assertDictEqual(ctx_copied, ctx_dummy)
4311 list(obj_decoded.pps())
4312 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4313 self.assertEqual(tail, tail_junk)
4314 self.assertEqual(obj_decoded, obj_expled)
4315 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
4316 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
4317 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4318 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4319 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4321 obj_decoded.expl_llen,
4322 len(len_encode(len(obj_encoded))),
4324 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4325 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4328 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4330 self.assertEqual(obj_decoded.expl_offset, offset)
4331 assert_exceeding_data(
4333 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4338 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
4339 base_klass = GeneralizedTime
4341 min_datetime = datetime(1900, 1, 1)
4342 max_datetime = datetime(9999, 12, 31)
4343 evgen_mode_skip_value = False
4345 def additional_symmetric_check(self, value, obj_encoded):
4346 if value.microsecond > 0:
4347 self.assertFalse(obj_encoded.endswith(b"0Z"))
4349 def test_repr_not_ready(self):
4350 str(GeneralizedTime())
4351 repr(GeneralizedTime())
4353 def test_x690_vector_valid(self):
4357 b"19920722132100.3Z",
4359 GeneralizedTime(data)
4361 def test_x690_vector_invalid(self):
4364 b"19920622123421.0Z",
4365 b"19920722132100.30Z",
4367 with self.assertRaises(DecodeError) as err:
4368 GeneralizedTime(data)
4371 def test_go_vectors_invalid(self):
4383 b"-20100102030410Z",
4384 b"2010-0102030410Z",
4385 b"2010-0002030410Z",
4386 b"201001-02030410Z",
4387 b"20100102-030410Z",
4388 b"2010010203-0410Z",
4389 b"201001020304-10Z",
4390 # These ones are INVALID in *DER*, but accepted
4391 # by Go's encoding/asn1
4392 b"20100102030405+0607",
4393 b"20100102030405-0607",
4395 with self.assertRaises(DecodeError) as err:
4396 GeneralizedTime(data)
4399 def test_go_vectors_valid(self):
4401 GeneralizedTime(b"20100102030405Z").todatetime(),
4402 datetime(2010, 1, 2, 3, 4, 5, 0),
4405 def test_go_vectors_valid_ber(self):
4407 b"20100102030405+0607",
4408 b"20100102030405-0607",
4410 GeneralizedTime(data, ctx={"bered": True})
4412 def test_utc_offsets(self):
4413 """Some know equal UTC offsets
4416 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4420 "200101011130-0700",
4421 "200101011500-03:30",
4424 self.assertEqual(dts[0], dts[1])
4425 self.assertEqual(dts[0], dts[2])
4426 self.assertEqual(dts[0], dts[3])
4428 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4429 @given(data_strategy())
4430 def test_valid_ber(self, d):
4431 year = d.draw(integers(min_value=2, max_value=9999))
4432 month = d.draw(integers(min_value=1, max_value=12))
4433 day = d.draw(integers(min_value=1, max_value=28))
4434 hours = d.draw(integers(min_value=0, max_value=23))
4435 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4436 dt = datetime(year, month, day, hours)
4437 fractions_sign = d.draw(sampled_from(" ,."))
4439 if fractions_sign != " ":
4440 fractions = random()
4441 if d.draw(booleans()):
4442 minutes = d.draw(integers(min_value=0, max_value=59))
4443 data += "%02d" % minutes
4444 dt += timedelta(seconds=60 * minutes)
4445 if d.draw(booleans()):
4446 seconds = d.draw(integers(min_value=0, max_value=59))
4447 data += "%02d" % seconds
4448 dt += timedelta(seconds=seconds)
4449 if fractions is not None:
4450 dt += timedelta(microseconds=10**6 * fractions)
4451 elif fractions is not None:
4452 dt += timedelta(seconds=60 * fractions)
4453 elif fractions is not None:
4454 dt += timedelta(seconds=3600 * fractions)
4455 if fractions is not None:
4456 data += fractions_sign + str(fractions)[2:]
4457 if d.draw(booleans()):
4459 elif d.draw(booleans()):
4460 offset_hour = d.draw(integers(min_value=0, max_value=13))
4462 if d.draw(booleans()):
4467 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4468 data += "%02d" % offset_hour
4469 minutes_separator = d.draw(sampled_from((None, "", ":")))
4470 if minutes_separator is not None:
4471 offset_minute = d.draw(integers(min_value=0, max_value=59))
4472 dt -= timedelta(seconds=sign * 60 * offset_minute)
4473 data += "%s%02d" % (minutes_separator, offset_minute)
4474 data = data.encode("ascii")
4475 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4477 GeneralizedTime().decod(data_der)
4482 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4485 mktime(obj.todatetime().timetuple()),
4486 mktime(dt.timetuple()),
4490 obj.todatetime().timestamp()
4494 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4495 self.assertEqual(obj.ber_encoded, not dered)
4496 self.assertEqual(obj.bered, not dered)
4497 self.assertEqual(obj.ber_raw, None if dered else data)
4498 self.assertEqual(obj.encode() == data_der, dered)
4503 def test_invalid_ber(self):
4505 # "00010203040506.07",
4506 "-0010203040506.07",
4507 "0001-203040506.07",
4508 "000102-3040506.07",
4509 "00010203-40506.07",
4510 "0001020304-506.07",
4511 "000102030405-6.07",
4512 "00010203040506.-7",
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 "001 0203040506.07",
4528 "00012 03040506.07",
4529 "0001023 040506.07",
4530 "000102034 0506.07",
4531 "00010203045 06.07",
4532 "0001020304056 .07",
4533 "00010203040506.7 ",
4613 "00010203040506.07+15",
4614 "00010203040506.07-15",
4615 "00010203040506.07+14:60",
4616 "00010203040506.07+1460",
4617 "00010203040506.07-1460",
4618 "00010203040506.07+00:60",
4619 "00010203040506.07-00:60",
4621 "00010203040506+15",
4622 "00010203040506-15",
4623 "00010203040506+14:60",
4624 "00010203040506+1460",
4625 "00010203040506-1460",
4626 "00010203040506+00:60",
4627 "00010203040506-00:60",
4636 with self.assertRaises(DecodeError):
4637 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4638 data = data.replace(".", ",")
4639 with self.assertRaises(DecodeError):
4640 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4644 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4645 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4647 binary(min_size=1, max_size=1),
4649 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4650 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4653 def test_junk(self, part0, part1, part2):
4654 junk = part0 + part1 + part2
4655 assume(not (set(junk) <= set(digits.encode("ascii"))))
4656 with self.assertRaises(DecodeError):
4657 GeneralizedTime().decode(
4658 GeneralizedTime.tag_default +
4659 len_encode(len(junk)) +
4665 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4666 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4668 binary(min_size=1, max_size=1),
4670 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4671 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4674 def test_junk_dm(self, part0, part1, part2):
4675 junk = part0 + part1 + part2
4676 assume(not (set(junk) <= set(digits.encode("ascii"))))
4677 with self.assertRaises(DecodeError):
4678 GeneralizedTime().decode(
4679 GeneralizedTime.tag_default +
4680 len_encode(len(junk)) +
4684 def test_ns_fractions(self):
4685 GeneralizedTime(b"20010101000000.000001Z")
4686 with self.assertRaisesRegex(DecodeError, "only microsecond fractions"):
4687 GeneralizedTime(b"20010101000000.0000001Z")
4689 def test_non_pure_integers(self):
4691 # b"20000102030405Z,
4698 b"20000102030405.+6Z",
4699 b"20000102030405.-6Z",
4706 b"20000102030405._6Z",
4707 b"20000102030405.6_Z",
4714 b"20000102030405. 6Z",
4721 b"20000102030405.6 Z",
4723 with self.assertRaises(DecodeError):
4724 GeneralizedTime(data)
4726 def test_aware(self):
4727 with self.assertRaisesRegex(ValueError, "only naive"):
4728 GeneralizedTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
4731 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4732 base_klass = UTCTime
4734 min_datetime = datetime(2000, 1, 1)
4735 max_datetime = datetime(2049, 12, 31)
4736 evgen_mode_skip_value = False
4738 def additional_symmetric_check(self, value, obj_encoded):
4741 def test_repr_not_ready(self):
4742 str(GeneralizedTime())
4745 def test_x690_vector_valid(self):
4753 def test_x690_vector_invalid(self):
4758 with self.assertRaises(DecodeError) as err:
4762 def test_go_vectors_invalid(self):
4788 # These ones are INVALID in *DER*, but accepted
4789 # by Go's encoding/asn1
4790 b"910506164540-0700",
4791 b"910506164540+0730",
4795 with self.assertRaises(DecodeError) as err:
4799 def test_go_vectors_valid(self):
4801 UTCTime(b"910506234540Z").todatetime(),
4802 datetime(1991, 5, 6, 23, 45, 40, 0),
4805 def test_non_pure_integers(self):
4834 with self.assertRaises(DecodeError):
4837 def test_x680_vector_valid_ber(self):
4839 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4840 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4841 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4842 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4844 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4845 obj = UTCTime().decod(data_der, ctx={"bered": True})
4846 self.assertEqual(obj, dt)
4847 self.assertEqual(obj.todatetime(), dt)
4848 self.assertTrue(obj.ber_encoded)
4849 self.assertTrue(obj.bered)
4850 self.assertEqual(obj.ber_raw, data)
4851 self.assertNotEqual(obj.encode(), data_der)
4854 def test_go_vectors_valid_ber(self):
4856 b"910506164540-0700",
4857 b"910506164540+0730",
4861 data = UTCTime.tag_default + len_encode(len(data)) + data
4862 obj = UTCTime().decod(data, ctx={"bered": True})
4863 self.assertTrue(obj.ber_encoded)
4864 self.assertTrue(obj.bered)
4865 self.assertNotEqual(obj.encode(), data)
4868 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4869 @given(data_strategy())
4870 def test_valid_ber(self, d):
4871 year = d.draw(integers(min_value=0, max_value=99))
4872 month = d.draw(integers(min_value=1, max_value=12))
4873 day = d.draw(integers(min_value=1, max_value=28))
4874 hours = d.draw(integers(min_value=0, max_value=23))
4875 minute = d.draw(integers(min_value=0, max_value=59))
4876 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4878 year + (2000 if year < 50 else 1900),
4885 if d.draw(booleans()):
4887 seconds = d.draw(integers(min_value=0, max_value=59))
4888 data += "%02d" % seconds
4889 dt += timedelta(seconds=seconds)
4890 if d.draw(booleans()):
4894 offset_hour = d.draw(integers(min_value=0, max_value=13))
4895 offset_minute = d.draw(integers(min_value=0, max_value=59))
4896 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4897 if d.draw(booleans()):
4903 data += "%02d%02d" % (offset_hour, offset_minute)
4904 data = data.encode("ascii")
4905 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4906 obj = UTCTime().decod(data_der, ctx={"bered": True})
4907 self.assertEqual(obj, dt)
4908 self.assertEqual(obj.todatetime(), dt)
4909 self.assertEqual(obj.ber_encoded, not dered)
4910 self.assertEqual(obj.bered, not dered)
4911 self.assertEqual(obj.ber_raw, None if dered else data)
4912 self.assertEqual(obj.encode() == data_der, dered)
4917 def test_invalid_ber(self):
4958 b"0001020304+0000Z",
4967 with self.assertRaises(DecodeError):
4968 UTCTime(data, ctx={"bered": True})
4969 data = data[:8] + data[8+2:]
4970 with self.assertRaises(DecodeError):
4971 UTCTime(data, ctx={"bered": True})
5016 b"000102030405+000",
5017 b"000102030405+000Z",
5018 b"000102030405+0000Z",
5019 b"000102030405+-101",
5020 b"000102030405+01-1",
5021 b"000102030405+0060",
5022 b"000102030405+1401",
5023 b"500101000002+0003",
5025 with self.assertRaises(DecodeError):
5026 UTCTime(data, ctx={"bered": True})
5028 @given(integers(min_value=0, max_value=49))
5029 def test_pre50(self, year):
5031 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5035 @given(integers(min_value=50, max_value=99))
5036 def test_post50(self, year):
5038 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5044 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5045 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5047 binary(min_size=1, max_size=1),
5049 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5050 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5053 def test_junk(self, part0, part1, part2):
5054 junk = part0 + part1 + part2
5055 assume(not (set(junk) <= set(digits.encode("ascii"))))
5056 with self.assertRaises(DecodeError):
5058 UTCTime.tag_default +
5059 len_encode(len(junk)) +
5063 def test_aware(self):
5064 with self.assertRaisesRegex(ValueError, "only naive"):
5065 UTCTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
5067 def test_raises_if_no_dateutil(self):
5068 with patch("pyderasn.tzutc", new=None):
5069 with self.assertRaisesRegex(
5070 NotImplementedError,
5071 "Package python-dateutil is required to use this feature",
5073 UTCTime(datetime.now()).totzdatetime()
5075 def test_tzinfo_gives_datetime_with_tzutc_tzinfo(self):
5076 self.assertEqual(UTCTime(datetime.now()).totzdatetime().tzinfo, tzutc())
5080 def tlv_value_strategy(draw):
5081 tag_num = draw(integers(min_value=1))
5082 data = draw(binary())
5083 return b"".join((tag_encode(tag_num), len_encode(len(data)), data))
5087 def any_values_strategy(draw, do_expl=False):
5088 value = draw(one_of(none(), tlv_value_strategy()))
5091 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5092 optional = draw(one_of(none(), booleans()))
5094 draw(integers(min_value=0)),
5095 draw(integers(min_value=0)),
5096 draw(integers(min_value=0)),
5098 return (value, expl, optional, _decoded)
5101 class AnyInherited(Any):
5105 class TestAny(CommonMixin, TestCase):
5108 def test_invalid_value_type(self):
5109 with self.assertRaises(InvalidValueType) as err:
5114 def test_optional(self, optional):
5115 obj = Any(optional=optional)
5116 self.assertEqual(obj.optional, optional)
5118 @given(tlv_value_strategy())
5119 def test_ready(self, value):
5121 self.assertFalse(obj.ready)
5124 pprint(obj, big_blobs=True, with_decode_path=True)
5125 with self.assertRaises(ObjNotReady) as err:
5128 with self.assertRaises(ObjNotReady) as err:
5131 self.assertTrue(obj.ready)
5134 pprint(obj, big_blobs=True, with_decode_path=True)
5137 def test_basic(self, value):
5138 integer_encoded = Integer(value).encode()
5140 Any(integer_encoded),
5141 Any(Integer(value)),
5142 Any(Any(Integer(value))),
5144 self.assertSequenceEqual(bytes(obj), integer_encoded)
5146 obj.decode(obj.encode())[0].vlen,
5147 len(integer_encoded),
5151 pprint(obj, big_blobs=True, with_decode_path=True)
5152 self.assertSequenceEqual(obj.encode(), integer_encoded)
5154 @given(tlv_value_strategy(), tlv_value_strategy())
5155 def test_comparison(self, value1, value2):
5156 for klass in (Any, AnyInherited):
5157 obj1 = klass(value1)
5158 obj2 = klass(value2)
5159 self.assertEqual(obj1 == obj2, value1 == value2)
5160 self.assertEqual(obj1 != obj2, value1 != value2)
5161 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
5163 @given(data_strategy())
5164 def test_call(self, d):
5165 for klass in (Any, AnyInherited):
5171 ) = d.draw(any_values_strategy())
5172 obj_initial = klass(
5175 optional_initial or False,
5183 ) = d.draw(any_values_strategy(do_expl=True))
5184 obj = obj_initial(value, expl, optional)
5186 value_expected = None if value is None else value
5187 self.assertEqual(obj, value_expected)
5188 self.assertEqual(obj.expl_tag, expl or expl_initial)
5189 if obj.default is None:
5190 optional = optional_initial if optional is None else optional
5191 optional = False if optional is None else optional
5192 self.assertEqual(obj.optional, optional)
5194 def test_simultaneous_impl_expl(self):
5195 # override it, as Any does not have implicit tag
5198 def test_decoded(self):
5199 # override it, as Any does not have implicit tag
5202 @given(any_values_strategy())
5203 def test_copy(self, values):
5204 for klass in (Any, AnyInherited):
5205 obj = klass(*values)
5206 for copy_func in copy_funcs:
5207 obj_copied = copy_func(obj)
5208 self.assert_copied_basic_fields(obj, obj_copied)
5209 self.assertEqual(obj._value, obj_copied._value)
5211 @given(binary().map(OctetString))
5212 def test_stripped(self, value):
5214 with self.assertRaises(NotEnoughData):
5215 obj.decode(obj.encode()[:-1])
5218 tlv_value_strategy(),
5219 integers(min_value=1).map(tag_ctxc),
5221 def test_stripped_expl(self, value, tag_expl):
5222 obj = Any(value, expl=tag_expl)
5223 with self.assertRaises(NotEnoughData):
5224 obj.decode(obj.encode()[:-1])
5227 integers(min_value=31),
5228 integers(min_value=0),
5231 def test_bad_tag(self, tag, offset, decode_path):
5232 with self.assertRaises(DecodeError) as err:
5234 tag_encode(tag)[:-1],
5236 decode_path=decode_path,
5239 self.assertEqual(err.exception.offset, offset)
5240 self.assertEqual(err.exception.decode_path, decode_path)
5243 integers(min_value=128),
5244 integers(min_value=0),
5247 def test_bad_len(self, l, offset, decode_path):
5248 with self.assertRaises(DecodeError) as err:
5250 Any.tag_default + len_encode(l)[:-1],
5252 decode_path=decode_path,
5255 self.assertEqual(err.exception.offset, offset)
5256 self.assertEqual(err.exception.decode_path, decode_path)
5258 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5260 any_values_strategy(),
5261 integers().map(lambda x: Integer(x).encode()),
5262 integers(min_value=1).map(tag_ctxc),
5263 integers(min_value=0),
5267 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
5268 for klass in (Any, AnyInherited):
5269 _, _, optional, _decoded = values
5270 obj = klass(value=value, optional=optional, _decoded=_decoded)
5273 pprint(obj, big_blobs=True, with_decode_path=True)
5274 self.assertFalse(obj.expled)
5275 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5276 self.assertEqual(obj.tag_order, (tag_class, tag_num))
5277 obj_encoded = obj.encode()
5278 self.assertEqual(encode2pass(obj), obj_encoded)
5279 obj_expled = obj(value, expl=tag_expl)
5280 self.assertTrue(obj_expled.expled)
5281 tag_class, _, tag_num = tag_decode(tag_expl)
5282 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5284 list(obj_expled.pps())
5285 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5286 obj_expled_encoded = obj_expled.encode()
5287 ctx_copied = deepcopy(ctx_dummy)
5288 obj_decoded, tail = obj_expled.decode(
5289 obj_expled_encoded + tail_junk,
5293 self.assertDictEqual(ctx_copied, ctx_dummy)
5295 list(obj_decoded.pps())
5296 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5297 self.assertEqual(tail, tail_junk)
5298 self.assertEqual(obj_decoded, obj_expled)
5299 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
5300 self.assertEqual(bytes(obj_decoded), bytes(obj))
5301 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5302 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5303 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5305 obj_decoded.expl_llen,
5306 len(len_encode(len(obj_encoded))),
5308 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5309 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5312 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5314 self.assertEqual(obj_decoded.expl_offset, offset)
5315 self.assertEqual(obj_decoded.tlen, 0)
5316 self.assertEqual(obj_decoded.llen, 0)
5317 self.assertEqual(obj_decoded.vlen, len(value))
5318 assert_exceeding_data(
5320 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5324 evgens = list(obj_expled.decode_evgen(
5325 obj_expled_encoded + tail_junk,
5327 decode_path=decode_path,
5330 self.assertEqual(len(evgens), 1)
5331 _decode_path, obj, tail = evgens[0]
5332 self.assertSequenceEqual(tail, tail_junk)
5333 self.assertEqual(_decode_path, decode_path)
5334 self.assertEqual(obj.expl_offset, offset)
5339 integers(min_value=1).map(tag_ctxc),
5340 integers(min_value=0, max_value=3),
5341 integers(min_value=0),
5345 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
5346 chunk = Boolean(False, expl=expl).encode()
5348 OctetString.tag_default +
5350 b"".join([chunk] * chunks) +
5353 with self.assertRaises(LenIndefForm):
5357 decode_path=decode_path,
5359 obj, tail = Any().decode(
5362 decode_path=decode_path,
5363 ctx={"bered": True},
5365 self.assertSequenceEqual(tail, junk)
5366 self.assertEqual(obj.offset, offset)
5367 self.assertEqual(obj.tlvlen, len(encoded))
5368 self.assertTrue(obj.lenindef)
5369 self.assertFalse(obj.ber_encoded)
5370 self.assertTrue(obj.bered)
5372 self.assertTrue(obj.lenindef)
5373 self.assertFalse(obj.ber_encoded)
5374 self.assertTrue(obj.bered)
5377 pprint(obj, big_blobs=True, with_decode_path=True)
5378 with self.assertRaises(NotEnoughData) as err:
5382 decode_path=decode_path,
5383 ctx={"bered": True},
5385 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
5386 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
5388 class SeqOf(SequenceOf):
5389 schema = Boolean(expl=expl)
5391 class Seq(Sequence):
5393 ("type", ObjectIdentifier(defines=((("value",), {
5394 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
5399 ("type", ObjectIdentifier("1.2.3")),
5400 ("value", Any(encoded)),
5402 seq_encoded = seq.encode()
5403 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5404 self.assertIsNotNone(seq_decoded["value"].defined)
5406 list(seq_decoded.pps())
5407 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5408 self.assertTrue(seq_decoded.bered)
5409 self.assertFalse(seq_decoded["type"].bered)
5410 self.assertTrue(seq_decoded["value"].bered)
5412 chunk = chunk[:-1] + b"\x01"
5413 chunks = b"".join([chunk] * (chunks + 1))
5414 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
5416 ("type", ObjectIdentifier("1.2.3")),
5417 ("value", Any(encoded)),
5419 seq_encoded = seq.encode()
5420 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5421 self.assertIsNotNone(seq_decoded["value"].defined)
5423 list(seq_decoded.pps())
5424 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5425 self.assertTrue(seq_decoded.bered)
5426 self.assertFalse(seq_decoded["type"].bered)
5427 self.assertTrue(seq_decoded["value"].bered)
5431 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
5433 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
5434 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
5436 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
5437 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
5439 min_size=len(names),
5440 max_size=len(names),
5443 (name, Integer(**tag_kwargs))
5444 for name, tag_kwargs in zip(names, tags)
5447 if value_required or draw(booleans()):
5448 value = draw(tuples(
5449 sampled_from([name for name, _ in schema]),
5450 integers().map(Integer),
5454 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5455 default = draw(one_of(
5457 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5459 optional = draw(one_of(none(), booleans()))
5461 draw(integers(min_value=0)),
5462 draw(integers(min_value=0)),
5463 draw(integers(min_value=0)),
5465 return (schema, value, expl, default, optional, _decoded)
5468 class ChoiceInherited(Choice):
5472 class TestChoice(CommonMixin, TestCase):
5474 schema = (("whatever", Boolean()),)
5477 def test_schema_required(self):
5478 with self.assertRaisesRegex(ValueError, "schema must be specified"):
5481 def test_impl_forbidden(self):
5482 with self.assertRaisesRegex(ValueError, "no implicit tag allowed"):
5483 Choice(impl=b"whatever")
5485 def test_invalid_value_type(self):
5486 with self.assertRaises(InvalidValueType) as err:
5487 self.base_klass(123)
5489 with self.assertRaises(ObjUnknown) as err:
5490 self.base_klass(("whenever", Boolean(False)))
5492 with self.assertRaises(InvalidValueType) as err:
5493 self.base_klass(("whatever", Integer(123)))
5497 def test_optional(self, optional):
5498 obj = self.base_klass(
5499 default=self.base_klass(("whatever", Boolean(False))),
5502 self.assertTrue(obj.optional)
5505 def test_ready(self, value):
5506 obj = self.base_klass()
5507 self.assertFalse(obj.ready)
5510 pprint(obj, big_blobs=True, with_decode_path=True)
5511 self.assertIsNone(obj["whatever"])
5512 with self.assertRaises(ObjNotReady) as err:
5515 with self.assertRaises(ObjNotReady) as err:
5517 obj["whatever"] = Boolean()
5518 self.assertFalse(obj.ready)
5521 pprint(obj, big_blobs=True, with_decode_path=True)
5522 obj["whatever"] = Boolean(value)
5523 self.assertTrue(obj.ready)
5526 pprint(obj, big_blobs=True, with_decode_path=True)
5528 @given(booleans(), booleans())
5529 def test_comparison(self, value1, value2):
5530 class WahlInherited(self.base_klass):
5532 for klass in (self.base_klass, WahlInherited):
5533 obj1 = klass(("whatever", Boolean(value1)))
5534 obj2 = klass(("whatever", Boolean(value2)))
5535 self.assertEqual(obj1 == obj2, value1 == value2)
5536 self.assertEqual(obj1 != obj2, value1 != value2)
5537 self.assertEqual(obj1 == obj2._value, value1 == value2)
5538 self.assertFalse(obj1 == obj2._value[1])
5540 @given(data_strategy())
5541 def test_call(self, d):
5542 for klass in (Choice, ChoiceInherited):
5550 ) = d.draw(choice_values_strategy())
5553 schema = schema_initial
5555 value=value_initial,
5557 default=default_initial,
5558 optional=optional_initial or False,
5559 _decoded=_decoded_initial,
5568 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5569 obj = obj_initial(value, expl, default, optional)
5571 value_expected = default if value is None else value
5573 default_initial if value_expected is None
5576 self.assertEqual(obj.choice, value_expected[0])
5577 self.assertEqual(obj.value, int(value_expected[1]))
5578 self.assertEqual(obj.expl_tag, expl or expl_initial)
5579 default_expect = default_initial if default is None else default
5580 if default_expect is not None:
5581 self.assertEqual(obj.default.choice, default_expect[0])
5582 self.assertEqual(obj.default.value, int(default_expect[1]))
5583 if obj.default is None:
5584 optional = optional_initial if optional is None else optional
5585 optional = False if optional is None else optional
5588 self.assertEqual(obj.optional, optional)
5589 self.assertEqual(obj.specs, obj_initial.specs)
5591 def test_simultaneous_impl_expl(self):
5592 # override it, as Any does not have implicit tag
5595 def test_decoded(self):
5596 # override it, as Any does not have implicit tag
5599 @given(choice_values_strategy())
5600 def test_copy(self, values):
5601 _schema, value, expl, default, optional, _decoded = values
5603 class Wahl(self.base_klass):
5605 register_class(Wahl)
5610 optional=optional or False,
5613 for copy_func in copy_funcs:
5614 obj_copied = copy_func(obj)
5615 self.assertIsNone(obj.tag)
5616 self.assertIsNone(obj_copied.tag)
5617 # hack for assert_copied_basic_fields
5618 obj.tag = "whatever"
5619 obj_copied.tag = "whatever"
5620 self.assert_copied_basic_fields(obj, obj_copied)
5622 self.assertEqual(obj._value, obj_copied._value)
5623 self.assertEqual(obj.specs, obj_copied.specs)
5626 def test_stripped(self, value):
5627 obj = self.base_klass(("whatever", Boolean(value)))
5628 with self.assertRaises(NotEnoughData):
5629 obj.decode(obj.encode()[:-1])
5633 integers(min_value=1).map(tag_ctxc),
5635 def test_stripped_expl(self, value, tag_expl):
5636 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5637 with self.assertRaises(NotEnoughData):
5638 obj.decode(obj.encode()[:-1])
5640 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5641 @given(data_strategy())
5642 def test_symmetric(self, d):
5643 _schema, value, _, default, optional, _decoded = d.draw(
5644 choice_values_strategy(value_required=True)
5646 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5647 offset = d.draw(integers(min_value=0))
5648 tail_junk = d.draw(binary(max_size=5))
5649 decode_path = d.draw(decode_path_strat)
5651 class Wahl(self.base_klass):
5661 pprint(obj, big_blobs=True, with_decode_path=True)
5662 self.assertFalse(obj.expled)
5663 self.assertEqual(obj.tag_order, obj.value.tag_order)
5664 obj_encoded = obj.encode()
5665 self.assertEqual(encode2pass(obj), obj_encoded)
5666 obj_expled = obj(value, expl=tag_expl)
5667 self.assertTrue(obj_expled.expled)
5668 tag_class, _, tag_num = tag_decode(tag_expl)
5669 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5671 list(obj_expled.pps())
5672 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5673 obj_expled_encoded = obj_expled.encode()
5674 ctx_copied = deepcopy(ctx_dummy)
5675 obj_decoded, tail = obj_expled.decode(
5676 obj_expled_encoded + tail_junk,
5680 self.assertDictEqual(ctx_copied, ctx_dummy)
5682 list(obj_decoded.pps())
5683 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5684 self.assertEqual(tail, tail_junk)
5685 self.assertEqual(obj_decoded, obj_expled)
5686 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5687 self.assertEqual(obj_decoded.value, obj_expled.value)
5688 self.assertEqual(obj_decoded.choice, obj.choice)
5689 self.assertEqual(obj_decoded.value, obj.value)
5690 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5691 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5692 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5694 obj_decoded.expl_llen,
5695 len(len_encode(len(obj_encoded))),
5697 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5698 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5701 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5703 self.assertEqual(obj_decoded.expl_offset, offset)
5704 self.assertSequenceEqual(
5706 obj_decoded.value.fulloffset - offset:
5707 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5711 assert_exceeding_data(
5713 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5717 evgens = list(obj_expled.decode_evgen(
5718 obj_expled_encoded + tail_junk,
5720 decode_path=decode_path,
5723 self.assertEqual(len(evgens), 2)
5724 _decode_path, obj, tail = evgens[0]
5725 self.assertEqual(_decode_path, decode_path + (obj_decoded.choice,))
5726 _decode_path, obj, tail = evgens[1]
5727 self.assertSequenceEqual(tail, tail_junk)
5728 self.assertEqual(_decode_path, decode_path)
5729 self.assertEqual(obj.expl_offset, offset)
5734 def test_set_get(self, value):
5737 ("erste", Boolean()),
5738 ("zweite", Integer()),
5741 with self.assertRaises(ObjUnknown) as err:
5742 obj["whatever"] = "whenever"
5743 with self.assertRaises(InvalidValueType) as err:
5744 obj["zweite"] = Boolean(False)
5745 obj["zweite"] = Integer(value)
5747 with self.assertRaises(ObjUnknown) as err:
5750 self.assertIsNone(obj["erste"])
5751 self.assertEqual(obj["zweite"], Integer(value))
5753 def test_tag_mismatch(self):
5756 ("erste", Boolean()),
5758 int_encoded = Integer(123).encode()
5759 bool_encoded = Boolean(False).encode()
5761 obj.decode(bool_encoded)
5762 with self.assertRaises(TagMismatch):
5763 obj.decode(int_encoded)
5765 def test_tag_mismatch_underlying(self):
5766 class SeqOfBoolean(SequenceOf):
5769 class SeqOfInteger(SequenceOf):
5774 ("erste", SeqOfBoolean()),
5777 int_encoded = SeqOfInteger((Integer(123),)).encode()
5778 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5780 obj.decode(bool_encoded)
5781 with self.assertRaises(TagMismatch) as err:
5782 obj.decode(int_encoded)
5783 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5787 def seq_values_strategy(draw, seq_klass, do_expl=False):
5789 if draw(booleans()):
5791 value._value = draw(dictionaries(
5794 booleans().map(Boolean),
5795 integers().map(Integer),
5799 if draw(booleans()):
5800 schema = list(draw(dictionaries(
5803 booleans().map(Boolean),
5804 integers().map(Integer),
5810 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5812 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5814 if draw(booleans()):
5815 default = seq_klass()
5816 default._value = draw(dictionaries(
5819 booleans().map(Boolean),
5820 integers().map(Integer),
5823 optional = draw(one_of(none(), booleans()))
5825 draw(integers(min_value=0)),
5826 draw(integers(min_value=0)),
5827 draw(integers(min_value=0)),
5829 return (value, schema, impl, expl, default, optional, _decoded)
5833 def sequence_strategy(draw, seq_klass):
5834 inputs = draw(lists(
5836 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5837 tuples(just(Integer), integers(), one_of(none(), integers())),
5842 integers(min_value=1),
5843 min_size=len(inputs),
5844 max_size=len(inputs),
5847 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5848 for tag, expled in zip(tags, draw(lists(
5850 min_size=len(inputs),
5851 max_size=len(inputs),
5855 for i, optional in enumerate(draw(lists(
5856 sampled_from(("required", "optional", "empty")),
5857 min_size=len(inputs),
5858 max_size=len(inputs),
5860 if optional in ("optional", "empty"):
5861 inits[i]["optional"] = True
5862 if optional == "empty":
5864 empties = set(empties)
5865 names = list(draw(sets(
5867 min_size=len(inputs),
5868 max_size=len(inputs),
5871 for i, (klass, value, default) in enumerate(inputs):
5872 schema.append((names[i], klass(default=default, **inits[i])))
5873 seq_name = draw(text_letters())
5874 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5877 for i, (klass, value, default) in enumerate(inputs):
5884 "default_value": None if spec.default is None else default,
5888 expect["optional"] = True
5890 expect["presented"] = True
5891 expect["value"] = value
5893 expect["optional"] = True
5894 if default is not None and default == value:
5895 expect["presented"] = False
5896 seq[name] = klass(value)
5897 expects.append(expect)
5902 def sequences_strategy(draw, seq_klass):
5903 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5905 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5906 for tag, expled in zip(tags, draw(lists(
5913 i for i, is_default in enumerate(draw(lists(
5919 names = list(draw(sets(
5924 seq_expectses = draw(lists(
5925 sequence_strategy(seq_klass=seq_klass),
5929 seqs = [seq for seq, _ in seq_expectses]
5931 for i, (name, seq) in enumerate(zip(names, seqs)):
5934 seq(default=(seq if i in defaulted else None), **inits[i]),
5936 seq_name = draw(text_letters())
5937 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5940 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5943 "expects": expects_inner,
5946 seq_outer[name] = seq_inner
5947 if seq_outer.specs[name].default is None:
5948 expect["presented"] = True
5949 expect_outers.append(expect)
5950 return seq_outer, expect_outers
5953 class SeqMixin(object):
5954 def test_invalid_value_type(self):
5955 with self.assertRaises(InvalidValueType) as err:
5956 self.base_klass(123)
5959 def test_invalid_value_type_set(self):
5960 class Seq(self.base_klass):
5961 schema = (("whatever", Boolean()),)
5963 with self.assertRaises(InvalidValueType) as err:
5964 seq["whatever"] = Integer(123)
5968 def test_optional(self, optional):
5969 obj = self.base_klass(default=self.base_klass(), optional=optional)
5970 self.assertTrue(obj.optional)
5972 @given(data_strategy())
5973 def test_ready(self, d):
5975 str(i): v for i, v in enumerate(d.draw(lists(
5982 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5989 for name in d.draw(permutations(
5990 list(ready.keys()) + list(non_ready.keys()),
5992 schema_input.append((name, Boolean()))
5994 class Seq(self.base_klass):
5995 schema = tuple(schema_input)
5997 for name in ready.keys():
5999 seq[name] = Boolean()
6000 self.assertFalse(seq.ready)
6003 pprint(seq, big_blobs=True, with_decode_path=True)
6004 for name, value in ready.items():
6005 seq[name] = Boolean(value)
6006 self.assertFalse(seq.ready)
6009 pprint(seq, big_blobs=True, with_decode_path=True)
6010 with self.assertRaises(ObjNotReady) as err:
6013 with self.assertRaises(ObjNotReady) as err:
6015 for name, value in non_ready.items():
6016 seq[name] = Boolean(value)
6017 self.assertTrue(seq.ready)
6020 pprint(seq, big_blobs=True, with_decode_path=True)
6022 @given(data_strategy())
6023 def test_call(self, d):
6024 class SeqInherited(self.base_klass):
6026 for klass in (self.base_klass, SeqInherited):
6035 ) = d.draw(seq_values_strategy(seq_klass=klass))
6036 obj_initial = klass(
6042 optional_initial or False,
6053 ) = d.draw(seq_values_strategy(
6055 do_expl=impl_initial is None,
6057 obj = obj_initial(value, impl, expl, default, optional)
6058 value_expected = default if value is None else value
6060 default_initial if value_expected is None
6063 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
6064 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6065 self.assertEqual(obj.expl_tag, expl or expl_initial)
6067 {} if obj.default is None else obj.default._value,
6068 getattr(default_initial if default is None else default, "_value", {}),
6070 if obj.default is None:
6071 optional = optional_initial if optional is None else optional
6072 optional = False if optional is None else optional
6075 self.assertEqual(list(obj.specs.items()), schema_initial or [])
6076 self.assertEqual(obj.optional, optional)
6078 @given(data_strategy())
6079 def test_copy(self, d):
6080 class SeqInherited(self.base_klass):
6082 register_class(SeqInherited)
6083 for klass in (self.base_klass, SeqInherited):
6084 values = d.draw(seq_values_strategy(seq_klass=klass))
6085 obj = klass(*values)
6086 for copy_func in copy_funcs:
6087 obj_copied = copy_func(obj)
6088 self.assert_copied_basic_fields(obj, obj_copied)
6089 self.assertEqual(obj.specs, obj_copied.specs)
6090 self.assertEqual(obj._value, obj_copied._value)
6092 @given(data_strategy())
6093 def test_stripped(self, d):
6094 value = d.draw(integers())
6095 tag_impl = tag_encode(d.draw(integers(min_value=1)))
6097 class Seq(self.base_klass):
6099 schema = (("whatever", Integer()),)
6101 seq["whatever"] = Integer(value)
6102 with self.assertRaises(NotEnoughData):
6103 seq.decode(seq.encode()[:-1])
6105 @given(data_strategy())
6106 def test_stripped_expl(self, d):
6107 value = d.draw(integers())
6108 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
6110 class Seq(self.base_klass):
6112 schema = (("whatever", Integer()),)
6114 seq["whatever"] = Integer(value)
6115 with self.assertRaises(NotEnoughData):
6116 seq.decode(seq.encode()[:-1])
6118 @given(integers(min_value=3), binary(min_size=2))
6119 def test_non_tag_mismatch_raised(self, junk_tag_num, junk):
6120 junk = tag_encode(junk_tag_num) + junk
6122 _, _, len_encoded = tag_strip(memoryview(junk))
6123 len_decode(len_encoded)
6129 class Seq(self.base_klass):
6131 ("whatever", Integer()),
6133 ("whenever", Integer()),
6136 seq["whatever"] = Integer(123)
6137 seq["junk"] = Any(junk)
6138 seq["whenever"] = Integer(123)
6139 with self.assertRaises(DecodeError):
6140 seq.decode(seq.encode())
6143 integers(min_value=31),
6144 integers(min_value=0),
6147 def test_bad_tag(self, tag, offset, decode_path):
6148 with self.assertRaises(DecodeError) as err:
6149 self.base_klass().decode(
6150 tag_encode(tag)[:-1],
6152 decode_path=decode_path,
6155 self.assertEqual(err.exception.offset, offset)
6156 self.assertEqual(err.exception.decode_path, decode_path)
6159 integers(min_value=128),
6160 integers(min_value=0),
6163 def test_bad_len(self, l, offset, decode_path):
6164 with self.assertRaises(DecodeError) as err:
6165 self.base_klass().decode(
6166 self.base_klass.tag_default + len_encode(l)[:-1],
6168 decode_path=decode_path,
6171 self.assertEqual(err.exception.offset, offset)
6172 self.assertEqual(err.exception.decode_path, decode_path)
6174 def _assert_expects(self, seq, expects):
6175 for expect in expects:
6177 seq.specs[expect["name"]].optional,
6180 if expect["default_value"] is not None:
6182 seq.specs[expect["name"]].default,
6183 expect["default_value"],
6185 if expect["presented"]:
6186 self.assertIn(expect["name"], seq)
6187 self.assertEqual(seq[expect["name"]], expect["value"])
6189 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6190 @given(data_strategy())
6191 def test_symmetric(self, d):
6192 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
6193 tail_junk = d.draw(binary(max_size=5))
6194 decode_path = d.draw(decode_path_strat)
6195 self.assertTrue(seq.ready)
6196 self.assertFalse(seq.decoded)
6197 self._assert_expects(seq, expects)
6200 pprint(seq, big_blobs=True, with_decode_path=True)
6201 self.assertTrue(seq.ready)
6202 seq_encoded = seq.encode()
6203 self.assertEqual(encode2pass(seq), seq_encoded)
6204 seq_encoded_cer = encode_cer(seq)
6205 self.assertNotEqual(seq_encoded_cer, seq_encoded)
6206 self.assertSequenceEqual(
6207 seq.decod(seq_encoded_cer, ctx={"bered": True}).encode(),
6210 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
6211 self.assertFalse(seq_decoded.lenindef)
6212 self.assertFalse(seq_decoded.ber_encoded)
6213 self.assertFalse(seq_decoded.bered)
6215 t, _, lv = tag_strip(seq_encoded)
6216 _, _, v = len_decode(lv)
6217 seq_encoded_lenindef = t + LENINDEF + v + EOC
6218 with self.assertRaises(DecodeError):
6219 seq.decode(seq_encoded_lenindef)
6220 ctx_copied = deepcopy(ctx_dummy)
6221 ctx_copied["bered"] = True
6222 seq_decoded_lenindef, tail_lenindef = seq.decode(
6223 seq_encoded_lenindef + tail_junk,
6226 del ctx_copied["bered"]
6227 self.assertDictEqual(ctx_copied, ctx_dummy)
6228 self.assertTrue(seq_decoded_lenindef.lenindef)
6229 self.assertTrue(seq_decoded_lenindef.bered)
6230 seq_decoded_lenindef = copy(seq_decoded_lenindef)
6231 self.assertTrue(seq_decoded_lenindef.lenindef)
6232 self.assertTrue(seq_decoded_lenindef.bered)
6233 with self.assertRaises(DecodeError):
6234 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
6235 with self.assertRaises(DecodeError):
6236 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
6237 repr(seq_decoded_lenindef)
6238 list(seq_decoded_lenindef.pps())
6239 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
6240 self.assertTrue(seq_decoded_lenindef.ready)
6242 for decoded, decoded_tail, encoded in (
6243 (seq_decoded, tail, seq_encoded),
6244 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
6246 self.assertEqual(decoded_tail, tail_junk)
6247 self._assert_expects(decoded, expects)
6248 self.assertEqual(seq, decoded)
6249 self.assertEqual(decoded.encode(), seq_encoded)
6250 self.assertEqual(decoded.tlvlen, len(encoded))
6251 for expect in expects:
6252 if not expect["presented"]:
6253 self.assertNotIn(expect["name"], decoded)
6255 self.assertIn(expect["name"], decoded)
6256 obj = decoded[expect["name"]]
6257 self.assertTrue(obj.decoded)
6258 offset = obj.expl_offset if obj.expled else obj.offset
6259 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6260 self.assertSequenceEqual(
6261 seq_encoded[offset:offset + tlvlen],
6265 evgens = list(seq.decode_evgen(
6266 encoded + decoded_tail,
6267 decode_path=decode_path,
6268 ctx={"bered": True},
6270 self.assertEqual(len(evgens), len(list(decoded._values_for_encoding())) + 1)
6271 for _decode_path, obj, _ in evgens[:-1]:
6272 self.assertEqual(_decode_path[:-1], decode_path)
6275 _decode_path, obj, tail = evgens[-1]
6276 self.assertEqual(_decode_path, decode_path)
6280 assert_exceeding_data(
6282 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
6286 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6287 @given(data_strategy())
6288 def test_symmetric_with_seq(self, d):
6289 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
6290 self.assertTrue(seq.ready)
6291 seq_encoded = seq.encode()
6292 self.assertEqual(encode2pass(seq), seq_encoded)
6293 seq_decoded, tail = seq.decode(seq_encoded)
6294 self.assertEqual(tail, b"")
6295 self.assertTrue(seq.ready)
6296 self.assertEqual(seq, seq_decoded)
6297 self.assertEqual(seq_decoded.encode(), seq_encoded)
6298 for expect_outer in expect_outers:
6299 if not expect_outer["presented"]:
6300 self.assertNotIn(expect_outer["name"], seq_decoded)
6302 self.assertIn(expect_outer["name"], seq_decoded)
6303 obj = seq_decoded[expect_outer["name"]]
6304 self.assertTrue(obj.decoded)
6305 offset = obj.expl_offset if obj.expled else obj.offset
6306 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6307 self.assertSequenceEqual(
6308 seq_encoded[offset:offset + tlvlen],
6311 self._assert_expects(obj, expect_outer["expects"])
6313 @given(data_strategy())
6314 def test_default_disappears(self, d):
6315 _schema = list(d.draw(dictionaries(
6317 sets(integers(), min_size=2, max_size=2),
6321 class Seq(self.base_klass):
6323 (n, Integer(default=d))
6324 for n, (_, d) in _schema
6327 for name, (value, _) in _schema:
6328 seq[name] = Integer(value)
6329 self.assertEqual(len(seq._value), len(_schema))
6330 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
6331 self.assertGreater(len(seq.encode()), len(empty_seq))
6332 for name, (_, default) in _schema:
6333 seq[name] = Integer(default)
6334 self.assertEqual(len(seq._value), 0)
6335 self.assertSequenceEqual(seq.encode(), empty_seq)
6337 @given(data_strategy())
6338 def test_encoded_default_not_accepted(self, d):
6339 _schema = list(d.draw(dictionaries(
6344 tags = [tag_encode(tag) for tag in d.draw(sets(
6345 integers(min_value=1),
6346 min_size=len(_schema),
6347 max_size=len(_schema),
6351 schema = (("int", Integer()),)
6353 class SeqWithoutDefault(self.base_klass):
6356 for (n, _), t in zip(_schema, tags)
6358 seq_without_default = SeqWithoutDefault()
6359 for name, value in _schema:
6360 seq_without_default[name] = Wahl(("int", Integer(value)))
6361 seq_encoded = seq_without_default.encode()
6362 seq_without_default.decode(seq_encoded)
6364 len(list(seq_without_default.decode_evgen(seq_encoded))),
6365 len(_schema) * 2 + 1,
6368 class SeqWithDefault(self.base_klass):
6370 (n, Wahl(default=Wahl(("int", Integer(v))), expl=t))
6371 for (n, v), t in zip(_schema, tags)
6373 seq_with_default = SeqWithDefault()
6374 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6375 seq_with_default.decode(seq_encoded)
6376 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6377 list(seq_with_default.decode_evgen(seq_encoded))
6378 for ctx in ({"bered": True}, {"allow_default_values": True}):
6379 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
6380 self.assertTrue(seq_decoded.ber_encoded)
6381 self.assertTrue(seq_decoded.bered)
6382 seq_decoded = copy(seq_decoded)
6383 self.assertTrue(seq_decoded.ber_encoded)
6384 self.assertTrue(seq_decoded.bered)
6385 for name, value in _schema:
6386 self.assertEqual(seq_decoded[name], seq_with_default[name])
6387 self.assertEqual(seq_decoded[name].value, value)
6389 len(list(seq_with_default.decode_evgen(seq_encoded, ctx=ctx))),
6393 seq_without_default = SeqWithoutDefault()
6394 for name, value in _schema:
6395 seq_without_default[name] = Wahl(("int", Integer(value + 1)))
6396 seq_encoded = seq_without_default.encode()
6397 seq_with_default.decode(seq_encoded)
6399 len(list(seq_with_default.decode_evgen(seq_encoded))),
6403 @given(data_strategy())
6404 def test_missing_from_spec(self, d):
6405 names = list(d.draw(sets(text_letters(), min_size=2)))
6406 tags = [tag_encode(tag) for tag in d.draw(sets(
6407 integers(min_value=1),
6408 min_size=len(names),
6409 max_size=len(names),
6411 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
6413 class SeqFull(self.base_klass):
6414 schema = [(n, Integer(impl=t)) for n, t in names_tags]
6415 seq_full = SeqFull()
6416 for i, name in enumerate(names):
6417 seq_full[name] = Integer(i)
6418 seq_encoded = seq_full.encode()
6419 altered = names_tags[:-2] + names_tags[-1:]
6421 class SeqMissing(self.base_klass):
6422 schema = [(n, Integer(impl=t)) for n, t in altered]
6423 seq_missing = SeqMissing()
6424 with self.assertRaises(TagMismatch):
6425 seq_missing.decode(seq_encoded)
6426 with self.assertRaises(TagMismatch):
6427 list(seq_missing.decode_evgen(seq_encoded))
6429 def test_bered(self):
6430 class Seq(self.base_klass):
6431 schema = (("underlying", Boolean()),)
6432 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
6433 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6434 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6435 self.assertFalse(decoded.ber_encoded)
6436 self.assertFalse(decoded.lenindef)
6437 self.assertTrue(decoded.bered)
6438 decoded = copy(decoded)
6439 self.assertFalse(decoded.ber_encoded)
6440 self.assertFalse(decoded.lenindef)
6441 self.assertTrue(decoded.bered)
6443 class Seq(self.base_klass):
6444 schema = (("underlying", OctetString()),)
6446 tag_encode(form=TagFormConstructed, num=4) +
6448 OctetString(b"whatever").encode() +
6451 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6452 with self.assertRaises(DecodeError):
6453 Seq().decode(encoded)
6454 with self.assertRaises(DecodeError):
6455 list(Seq().decode_evgen(encoded))
6456 list(Seq().decode_evgen(encoded, ctx={"bered": True}))
6457 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6458 self.assertFalse(decoded.ber_encoded)
6459 self.assertFalse(decoded.lenindef)
6460 self.assertTrue(decoded.bered)
6461 decoded = copy(decoded)
6462 self.assertFalse(decoded.ber_encoded)
6463 self.assertFalse(decoded.lenindef)
6464 self.assertTrue(decoded.bered)
6467 class TestSequence(SeqMixin, CommonMixin, TestCase):
6468 base_klass = Sequence
6474 def test_remaining(self, value, junk):
6475 class Seq(Sequence):
6477 ("whatever", Integer()),
6479 int_encoded = Integer(value).encode()
6481 Sequence.tag_default,
6482 len_encode(len(int_encoded + junk)),
6485 with self.assertRaisesRegex(DecodeError, "remaining"):
6486 Seq().decode(junked)
6488 @given(sets(text_letters(), min_size=2))
6489 def test_obj_unknown(self, names):
6490 missing = names.pop()
6492 class Seq(Sequence):
6493 schema = [(n, Boolean()) for n in names]
6495 with self.assertRaises(ObjUnknown) as err:
6498 with self.assertRaises(ObjUnknown) as err:
6499 seq[missing] = Boolean()
6502 def test_x690_vector(self):
6503 class Seq(Sequence):
6505 ("name", IA5String()),
6508 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
6509 self.assertEqual(seq["name"], "Smith")
6510 self.assertEqual(seq["ok"], True)
6513 class TestSet(SeqMixin, CommonMixin, TestCase):
6516 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6517 @given(data_strategy())
6518 def test_sorted(self, d):
6519 class DummySeq(Sequence):
6520 schema = (("null", Null()),)
6522 tag_nums = d.draw(sets(integers(min_value=1), min_size=1, max_size=50))
6523 _, _, dummy_seq_tag_num = tag_decode(DummySeq.tag_default)
6524 assume(any(i > dummy_seq_tag_num for i in tag_nums))
6525 tag_nums -= set([dummy_seq_tag_num])
6526 _schema = [(str(i), OctetString(impl=tag_encode(i))) for i in tag_nums]
6527 _schema.append(("seq", DummySeq()))
6530 schema = d.draw(permutations(_schema))
6532 for name, _ in _schema:
6534 seq[name] = OctetString(name.encode("ascii"))
6535 seq["seq"] = DummySeq((("null", Null()),))
6537 seq_encoded = seq.encode()
6538 seq_decoded, _ = seq.decode(seq_encoded)
6539 seq_encoded_expected = []
6540 for tag_num in sorted(tag_nums | set([dummy_seq_tag_num])):
6541 if tag_num == dummy_seq_tag_num:
6542 seq_encoded_expected.append(seq["seq"].encode())
6544 seq_encoded_expected.append(seq[str(tag_num)].encode())
6545 self.assertSequenceEqual(
6546 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6547 b"".join(seq_encoded_expected),
6550 encoded = b"".join(seq[str(i)].encode() for i in tag_nums)
6551 encoded += seq["seq"].encode()
6552 seq_encoded = b"".join((
6554 len_encode(len(encoded)),
6557 with self.assertRaisesRegex(DecodeError, "unordered SET"):
6558 seq.decode(seq_encoded)
6559 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6560 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6561 self.assertTrue(seq_decoded.ber_encoded)
6562 self.assertTrue(seq_decoded.bered)
6563 seq_decoded = copy(seq_decoded)
6564 self.assertTrue(seq_decoded.ber_encoded)
6565 self.assertTrue(seq_decoded.bered)
6567 def test_same_value_twice(self):
6570 ("bool", Boolean()),
6574 encoded = b"".join((
6575 Integer(123).encode(),
6576 Integer(234).encode(),
6577 Boolean(True).encode(),
6579 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6580 with self.assertRaises(TagMismatch):
6581 Seq().decod(encoded, ctx={"allow_unordered_set": True})
6585 def seqof_values_strategy(draw, schema=None, do_expl=False):
6587 schema = draw(sampled_from((Boolean(), Integer())))
6588 bound_min, bound_max = sorted(draw(sets(
6589 integers(min_value=0, max_value=10),
6593 if isinstance(schema, Boolean):
6594 values_generator = booleans().map(Boolean)
6595 elif isinstance(schema, Integer):
6596 values_generator = integers().map(Integer)
6597 values_generator = lists(
6602 values = draw(one_of(none(), values_generator))
6606 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6608 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6609 default = draw(one_of(none(), values_generator))
6610 optional = draw(one_of(none(), booleans()))
6612 draw(integers(min_value=0)),
6613 draw(integers(min_value=0)),
6614 draw(integers(min_value=0)),
6619 (bound_min, bound_max),
6628 class SeqOfMixin(object):
6629 def test_invalid_value_type(self):
6630 with self.assertRaises(InvalidValueType) as err:
6631 self.base_klass(123)
6634 def test_invalid_values_type(self):
6635 class SeqOf(self.base_klass):
6637 with self.assertRaises(InvalidValueType) as err:
6638 SeqOf([Integer(123), Boolean(False), Integer(234)])
6641 def test_schema_required(self):
6642 with self.assertRaisesRegex(ValueError, "schema must be specified"):
6643 self.base_klass.__mro__[1]()
6645 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6646 def test_comparison(self, value1, value2, tag1, tag2):
6647 class SeqOf(self.base_klass):
6649 obj1 = SeqOf([Boolean(value1)])
6650 obj2 = SeqOf([Boolean(value2)])
6651 self.assertEqual(obj1 == obj2, value1 == value2)
6652 self.assertEqual(obj1 != obj2, value1 != value2)
6653 self.assertEqual(obj1 == list(obj2), value1 == value2)
6654 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6655 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6656 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6657 self.assertEqual(obj1 == obj2, tag1 == tag2)
6658 self.assertEqual(obj1 != obj2, tag1 != tag2)
6660 @given(lists(booleans()))
6661 def test_iter(self, values):
6662 class SeqOf(self.base_klass):
6664 obj = SeqOf([Boolean(value) for value in values])
6665 self.assertEqual(len(obj), len(values))
6666 for i, value in enumerate(obj):
6667 self.assertEqual(value, values[i])
6669 @given(data_strategy())
6670 def test_ready(self, d):
6671 ready = [Integer(v) for v in d.draw(lists(
6678 range(d.draw(integers(min_value=1, max_value=5)))
6681 class SeqOf(self.base_klass):
6683 values = d.draw(permutations(ready + non_ready))
6685 for value in values:
6687 self.assertFalse(seqof.ready)
6690 pprint(seqof, big_blobs=True, with_decode_path=True)
6691 with self.assertRaises(ObjNotReady) as err:
6694 with self.assertRaises(ObjNotReady) as err:
6696 for i, value in enumerate(values):
6697 self.assertEqual(seqof[i], value)
6698 if not seqof[i].ready:
6699 seqof[i] = Integer(i)
6700 self.assertTrue(seqof.ready)
6703 pprint(seqof, big_blobs=True, with_decode_path=True)
6705 def test_spec_mismatch(self):
6706 class SeqOf(self.base_klass):
6709 seqof.append(Integer(123))
6710 with self.assertRaises(ValueError):
6711 seqof.append(Boolean(False))
6712 with self.assertRaises(ValueError):
6713 seqof[0] = Boolean(False)
6715 @given(data_strategy())
6716 def test_bounds_satisfied(self, d):
6717 class SeqOf(self.base_klass):
6719 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6720 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6721 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6722 SeqOf(value=value, bounds=(bound_min, bound_max))
6724 @given(data_strategy())
6725 def test_bounds_unsatisfied(self, d):
6726 class SeqOf(self.base_klass):
6728 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6729 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6730 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
6731 with self.assertRaises(BoundsError) as err:
6732 SeqOf(value=value, bounds=(bound_min, bound_max))
6734 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6735 SeqOf(bounds=(bound_min, bound_max)).decode(
6736 SeqOf(value).encode()
6739 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6740 SeqOf(bounds=(bound_min, bound_max)).decode(
6741 encode2pass(SeqOf(value))
6743 value = [Boolean(True)] * d.draw(integers(
6744 min_value=bound_max + 1,
6745 max_value=bound_max + 10,
6747 with self.assertRaises(BoundsError) as err:
6748 SeqOf(value=value, bounds=(bound_min, bound_max))
6750 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6751 SeqOf(bounds=(bound_min, bound_max)).decode(
6752 SeqOf(value).encode()
6755 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6756 SeqOf(bounds=(bound_min, bound_max)).decode(
6757 encode2pass(SeqOf(value))
6760 @given(integers(min_value=1, max_value=10))
6761 def test_out_of_bounds(self, bound_max):
6762 class SeqOf(self.base_klass):
6764 bounds = (0, bound_max)
6766 for _ in range(bound_max):
6767 seqof.append(Integer(123))
6768 with self.assertRaises(BoundsError):
6769 seqof.append(Integer(123))
6771 @given(data_strategy())
6772 def test_call(self, d):
6782 ) = d.draw(seqof_values_strategy())
6784 class SeqOf(self.base_klass):
6785 schema = schema_initial
6786 obj_initial = SeqOf(
6787 value=value_initial,
6788 bounds=bounds_initial,
6791 default=default_initial,
6792 optional=optional_initial or False,
6793 _decoded=_decoded_initial,
6804 ) = d.draw(seqof_values_strategy(
6805 schema=schema_initial,
6806 do_expl=impl_initial is None,
6808 if (default is None) and (obj_initial.default is not None):
6811 (bounds is None) and
6812 (value is not None) and
6813 (bounds_initial is not None) and
6814 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6818 (bounds is None) and
6819 (default is not None) and
6820 (bounds_initial is not None) and
6821 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6833 value_expected = default if value is None else value
6835 default_initial if value_expected is None
6838 value_expected = () if value_expected is None else value_expected
6839 self.assertEqual(obj, value_expected)
6840 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6841 self.assertEqual(obj.expl_tag, expl or expl_initial)
6844 default_initial if default is None else default,
6846 if obj.default is None:
6847 optional = optional_initial if optional is None else optional
6848 optional = False if optional is None else optional
6851 self.assertEqual(obj.optional, optional)
6853 (obj._bound_min, obj._bound_max),
6854 bounds or bounds_initial or (0, float("+inf")),
6857 @given(seqof_values_strategy())
6858 def test_copy(self, values):
6859 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6861 class SeqOf(self.base_klass):
6863 register_class(SeqOf)
6870 optional=optional or False,
6873 for copy_func in copy_funcs:
6874 obj_copied = copy_func(obj)
6875 self.assert_copied_basic_fields(obj, obj_copied)
6876 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6877 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6878 self.assertEqual(obj._value, obj_copied._value)
6882 integers(min_value=1).map(tag_encode),
6884 def test_stripped(self, values, tag_impl):
6885 class SeqOf(self.base_klass):
6886 schema = OctetString()
6887 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6888 with self.assertRaises(NotEnoughData):
6889 obj.decode(obj.encode()[:-1])
6893 integers(min_value=1).map(tag_ctxc),
6895 def test_stripped_expl(self, values, tag_expl):
6896 class SeqOf(self.base_klass):
6897 schema = OctetString()
6898 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6899 with self.assertRaises(NotEnoughData):
6900 obj.decode(obj.encode()[:-1])
6903 integers(min_value=31),
6904 integers(min_value=0),
6907 def test_bad_tag(self, tag, offset, decode_path):
6908 with self.assertRaises(DecodeError) as err:
6909 self.base_klass().decode(
6910 tag_encode(tag)[:-1],
6912 decode_path=decode_path,
6915 self.assertEqual(err.exception.offset, offset)
6916 self.assertEqual(err.exception.decode_path, decode_path)
6919 integers(min_value=128),
6920 integers(min_value=0),
6923 def test_bad_len(self, l, offset, decode_path):
6924 with self.assertRaises(DecodeError) as err:
6925 self.base_klass().decode(
6926 self.base_klass.tag_default + len_encode(l)[:-1],
6928 decode_path=decode_path,
6931 self.assertEqual(err.exception.offset, offset)
6932 self.assertEqual(err.exception.decode_path, decode_path)
6934 @given(binary(min_size=1))
6935 def test_tag_mismatch(self, impl):
6936 assume(impl != self.base_klass.tag_default)
6937 with self.assertRaises(TagMismatch):
6938 self.base_klass(impl=impl).decode(self.base_klass().encode())
6940 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6942 seqof_values_strategy(schema=Integer()),
6943 lists(integers().map(Integer)),
6944 integers(min_value=1).map(tag_ctxc),
6945 integers(min_value=0),
6949 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
6950 _, _, _, _, _, default, optional, _decoded = values
6952 class SeqOf(self.base_klass):
6962 pprint(obj, big_blobs=True, with_decode_path=True)
6963 self.assertFalse(obj.expled)
6964 obj_encoded = obj.encode()
6965 self.assertEqual(encode2pass(obj), obj_encoded)
6966 obj_encoded_cer = encode_cer(obj)
6967 self.assertNotEqual(obj_encoded_cer, obj_encoded)
6968 self.assertSequenceEqual(
6969 obj.decod(obj_encoded_cer, ctx={"bered": True}).encode(),
6972 obj_expled = obj(value, expl=tag_expl)
6973 self.assertTrue(obj_expled.expled)
6975 list(obj_expled.pps())
6976 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6977 obj_expled_encoded = obj_expled.encode()
6978 ctx_copied = deepcopy(ctx_dummy)
6979 obj_decoded, tail = obj_expled.decode(
6980 obj_expled_encoded + tail_junk,
6984 self.assertDictEqual(ctx_copied, ctx_dummy)
6986 list(obj_decoded.pps())
6987 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6988 self.assertEqual(tail, tail_junk)
6989 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6990 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6991 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6992 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6994 obj_decoded.expl_llen,
6995 len(len_encode(len(obj_encoded))),
6997 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
6998 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
7001 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
7003 self.assertEqual(obj_decoded.expl_offset, offset)
7004 for obj_inner in obj_decoded:
7005 self.assertIn(obj_inner, obj_decoded)
7006 self.assertSequenceEqual(
7009 obj_inner.offset - offset:
7010 obj_inner.offset + obj_inner.tlvlen - offset
7014 t, _, lv = tag_strip(obj_encoded)
7015 _, _, v = len_decode(lv)
7016 obj_encoded_lenindef = t + LENINDEF + v + EOC
7017 with self.assertRaises(DecodeError):
7018 obj.decode(obj_encoded_lenindef)
7019 obj_decoded_lenindef, tail_lenindef = obj.decode(
7020 obj_encoded_lenindef + tail_junk,
7021 ctx={"bered": True},
7023 self.assertTrue(obj_decoded_lenindef.lenindef)
7024 self.assertTrue(obj_decoded_lenindef.bered)
7025 obj_decoded_lenindef = copy(obj_decoded_lenindef)
7026 self.assertTrue(obj_decoded_lenindef.lenindef)
7027 self.assertTrue(obj_decoded_lenindef.bered)
7028 repr(obj_decoded_lenindef)
7029 list(obj_decoded_lenindef.pps())
7030 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
7031 self.assertEqual(tail_lenindef, tail_junk)
7032 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
7033 with self.assertRaises(DecodeError):
7034 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
7035 with self.assertRaises(DecodeError):
7036 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
7038 evgens = list(obj.decode_evgen(
7039 obj_encoded_lenindef + tail_junk,
7040 decode_path=decode_path,
7041 ctx={"bered": True},
7043 self.assertEqual(len(evgens), len(obj_decoded_lenindef) + 1)
7044 for i, (_decode_path, obj, _) in enumerate(evgens[:-1]):
7045 self.assertEqual(_decode_path, decode_path + (str(i),))
7048 _decode_path, obj, tail = evgens[-1]
7049 self.assertEqual(_decode_path, decode_path)
7053 assert_exceeding_data(
7055 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
7059 def test_bered(self):
7060 class SeqOf(self.base_klass):
7062 encoded = Boolean(False).encode()
7063 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
7064 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7065 with self.assertRaises(DecodeError):
7066 SeqOf().decode(encoded)
7067 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7068 self.assertFalse(decoded.ber_encoded)
7069 self.assertFalse(decoded.lenindef)
7070 self.assertTrue(decoded.bered)
7071 decoded = copy(decoded)
7072 self.assertFalse(decoded.ber_encoded)
7073 self.assertFalse(decoded.lenindef)
7074 self.assertTrue(decoded.bered)
7076 class SeqOf(self.base_klass):
7077 schema = OctetString()
7078 encoded = OctetString(b"whatever").encode()
7080 tag_encode(form=TagFormConstructed, num=4) +
7082 OctetString(b"whatever").encode() +
7085 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7086 with self.assertRaises(DecodeError):
7087 SeqOf().decode(encoded)
7088 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7089 self.assertFalse(decoded.ber_encoded)
7090 self.assertFalse(decoded.lenindef)
7091 self.assertTrue(decoded.bered)
7092 decoded = copy(decoded)
7093 self.assertFalse(decoded.ber_encoded)
7094 self.assertFalse(decoded.lenindef)
7095 self.assertTrue(decoded.bered)
7098 class TestSequenceOf(SeqOfMixin, CommonMixin, TestCase):
7099 class SeqOf(SequenceOf):
7103 def _test_symmetric_compare_objs(self, obj1, obj2):
7104 self.assertEqual(obj1, obj2)
7105 self.assertSequenceEqual(list(obj1), list(obj2))
7107 def test_iterator_pickling(self):
7108 class SeqOf(SequenceOf):
7110 register_class(SeqOf)
7113 seqof = seqof(iter(range(10)))
7114 with self.assertRaisesRegex(ValueError, "iterator"):
7117 def test_iterator_bounds(self):
7118 class SeqOf(SequenceOf):
7127 seqof = SeqOf(gen(n))
7128 self.assertTrue(seqof.ready)
7129 with self.assertRaises(BoundsError):
7131 self.assertFalse(seqof.ready)
7132 seqof = seqof(gen(n))
7133 self.assertTrue(seqof.ready)
7134 with self.assertRaises(BoundsError):
7136 self.assertFalse(seqof.ready)
7138 def test_iterator_twice(self):
7139 class SeqOf(SequenceOf):
7141 bounds = (1, float("+inf"))
7146 seqof = SeqOf(gen())
7147 self.assertTrue(seqof.ready)
7149 self.assertFalse(seqof.ready)
7150 register_class(SeqOf)
7153 def test_iterator_2pass(self):
7154 class SeqOf(SequenceOf):
7156 bounds = (1, float("+inf"))
7161 seqof = SeqOf(gen())
7162 self.assertTrue(seqof.ready)
7163 _, state = seqof.encode1st()
7164 self.assertFalse(seqof.ready)
7165 seqof = seqof(gen())
7166 self.assertTrue(seqof.ready)
7168 seqof.encode2nd(buf.write, iter(state))
7169 self.assertSequenceEqual(
7170 [int(i) for i in seqof.decod(buf.getvalue())],
7174 def test_non_ready_bound_min(self):
7175 class SeqOf(SequenceOf):
7177 bounds = (1, float("+inf"))
7179 self.assertFalse(seqof.ready)
7182 class TestSetOf(SeqOfMixin, CommonMixin, TestCase):
7187 def _test_symmetric_compare_objs(self, obj1, obj2):
7188 self.assertSetEqual(
7189 set(int(v) for v in obj1),
7190 set(int(v) for v in obj2),
7193 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7194 @given(data_strategy())
7195 def test_sorted(self, d):
7196 values = [OctetString(v) for v in d.draw(lists(binary()))]
7199 schema = OctetString()
7201 seq_encoded = seq.encode()
7202 seq_decoded, _ = seq.decode(seq_encoded)
7203 self.assertSequenceEqual(
7204 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
7205 b"".join(sorted([v.encode() for v in values])),
7208 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7209 @given(data_strategy())
7210 def test_unsorted(self, d):
7211 values = [OctetString(v).encode() for v in d.draw(sets(
7212 binary(min_size=1, max_size=5),
7216 values = d.draw(permutations(values))
7217 assume(values != sorted(values))
7218 encoded = b"".join(values)
7219 seq_encoded = b"".join((
7221 len_encode(len(encoded)),
7226 schema = OctetString()
7228 with self.assertRaisesRegex(DecodeError, "unordered SET OF"):
7229 seq.decode(seq_encoded)
7231 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
7232 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
7233 self.assertTrue(seq_decoded.ber_encoded)
7234 self.assertTrue(seq_decoded.bered)
7235 seq_decoded = copy(seq_decoded)
7236 self.assertTrue(seq_decoded.ber_encoded)
7237 self.assertTrue(seq_decoded.bered)
7238 self.assertSequenceEqual(
7239 [obj.encode() for obj in seq_decoded],
7244 class TestGoMarshalVectors(TestCase):
7246 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
7247 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
7248 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
7249 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
7250 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
7252 class Seq(Sequence):
7254 ("erste", Integer()),
7255 ("zweite", Integer(optional=True))
7258 seq["erste"] = Integer(64)
7259 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7260 seq["erste"] = Integer(0x123456)
7261 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
7262 seq["erste"] = Integer(64)
7263 seq["zweite"] = Integer(65)
7264 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
7266 class NestedSeq(Sequence):
7270 seq["erste"] = Integer(127)
7271 seq["zweite"] = None
7272 nested = NestedSeq()
7273 nested["nest"] = seq
7274 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
7276 self.assertSequenceEqual(
7277 OctetString(b"\x01\x02\x03").encode(),
7278 hexdec("0403010203"),
7281 class Seq(Sequence):
7283 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
7286 seq["erste"] = Integer(64)
7287 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
7289 class Seq(Sequence):
7291 ("erste", Integer(expl=tag_ctxc(5))),
7294 seq["erste"] = Integer(64)
7295 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
7297 class Seq(Sequence):
7300 impl=tag_encode(0, klass=TagClassContext),
7305 seq["erste"] = Null()
7306 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
7308 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7310 self.assertSequenceEqual(
7311 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
7312 hexdec("170d3730303130313030303030305a"),
7314 self.assertSequenceEqual(
7315 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
7316 hexdec("170d3039313131353232353631365a"),
7318 self.assertSequenceEqual(
7319 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
7320 hexdec("180f32313030303430353132303130315a"),
7323 class Seq(Sequence):
7325 ("erste", GeneralizedTime()),
7328 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
7329 self.assertSequenceEqual(
7331 hexdec("3011180f32303039313131353232353631365a"),
7334 self.assertSequenceEqual(
7335 BitString((1, b"\x80")).encode(),
7338 self.assertSequenceEqual(
7339 BitString((12, b"\x81\xF0")).encode(),
7340 hexdec("03030481f0"),
7343 self.assertSequenceEqual(
7344 ObjectIdentifier("1.2.3.4").encode(),
7345 hexdec("06032a0304"),
7347 self.assertSequenceEqual(
7348 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
7349 hexdec("06092a864888932d010105"),
7351 self.assertSequenceEqual(
7352 ObjectIdentifier("2.100.3").encode(),
7353 hexdec("0603813403"),
7356 self.assertSequenceEqual(
7357 PrintableString("test").encode(),
7358 hexdec("130474657374"),
7360 self.assertSequenceEqual(
7361 PrintableString("x" * 127).encode(),
7362 hexdec("137F" + "78" * 127),
7364 self.assertSequenceEqual(
7365 PrintableString("x" * 128).encode(),
7366 hexdec("138180" + "78" * 128),
7368 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
7370 class Seq(Sequence):
7372 ("erste", IA5String()),
7375 seq["erste"] = IA5String("test")
7376 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
7378 class Seq(Sequence):
7380 ("erste", PrintableString()),
7383 seq["erste"] = PrintableString("test")
7384 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
7385 # Asterisk is actually not allowable
7386 pyderasn.PRINTABLE_ALLOWABLE_CHARS |= set(b"*")
7387 seq["erste"] = PrintableString("test*")
7388 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
7389 pyderasn.PRINTABLE_ALLOWABLE_CHARS -= set(b"*")
7391 class Seq(Sequence):
7393 ("erste", Any(optional=True)),
7394 ("zweite", Integer()),
7397 seq["zweite"] = Integer(64)
7398 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7403 seq.append(Integer(10))
7404 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
7406 class _SeqOf(SequenceOf):
7407 schema = PrintableString()
7409 class SeqOf(SequenceOf):
7412 _seqof.append(PrintableString("1"))
7414 seqof.append(_seqof)
7415 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
7417 class Seq(Sequence):
7419 ("erste", Integer(default=1)),
7422 seq["erste"] = Integer(0)
7423 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
7424 seq["erste"] = Integer(1)
7425 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7426 seq["erste"] = Integer(2)
7427 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
7430 class TestPP(TestCase):
7431 @given(data_strategy())
7432 def test_oid_printing(self, d):
7434 str(ObjectIdentifier(k)): v * 2
7435 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
7437 chosen = d.draw(sampled_from(sorted(oids)))
7438 chosen_id = oids[chosen]
7439 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
7440 self.assertNotIn(chosen_id, pp_console_row(pp))
7443 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
7447 class TestAutoAddSlots(TestCase):
7449 class Inher(Integer):
7452 with self.assertRaises(AttributeError):
7454 inher.unexistent = "whatever"
7457 class TestOIDDefines(TestCase):
7458 @given(data_strategy())
7459 def runTest(self, d):
7460 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
7461 value_name_chosen = d.draw(sampled_from(value_names))
7463 ObjectIdentifier(oid)
7464 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
7466 oid_chosen = d.draw(sampled_from(oids))
7467 values = d.draw(lists(
7469 min_size=len(value_names),
7470 max_size=len(value_names),
7472 for definable_class in (Any, OctetString, BitString):
7474 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
7475 oid: Integer() for oid in oids[:-1]
7478 for i, value_name in enumerate(value_names):
7479 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
7481 class Seq(Sequence):
7484 for value_name, value in zip(value_names, values):
7485 seq[value_name] = definable_class(Integer(value).encode())
7486 seq["type"] = oid_chosen
7487 seq, _ = Seq().decode(seq.encode())
7488 for value_name in value_names:
7489 if value_name == value_name_chosen:
7491 self.assertIsNone(seq[value_name].defined)
7492 if value_name_chosen in oids[:-1]:
7493 self.assertIsNotNone(seq[value_name_chosen].defined)
7494 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
7495 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
7498 pprint(seq, big_blobs=True, with_decode_path=True)
7501 class TestDefinesByPath(TestCase):
7502 def test_generated(self):
7503 class Seq(Sequence):
7505 ("type", ObjectIdentifier()),
7506 ("value", OctetString(expl=tag_ctxc(123))),
7509 class SeqInner(Sequence):
7511 ("typeInner", ObjectIdentifier()),
7512 ("valueInner", Any()),
7515 class PairValue(SetOf):
7518 class Pair(Sequence):
7520 ("type", ObjectIdentifier()),
7521 ("value", PairValue()),
7524 class Pairs(SequenceOf):
7531 type_octet_stringed,
7533 ObjectIdentifier(oid)
7534 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
7536 seq_integered = Seq()
7537 seq_integered["type"] = type_integered
7538 seq_integered["value"] = OctetString(Integer(123).encode())
7539 seq_integered_raw = seq_integered.encode()
7543 (type_octet_stringed, OctetString(b"whatever")),
7544 (type_integered, Integer(123)),
7545 (type_octet_stringed, OctetString(b"whenever")),
7546 (type_integered, Integer(234)),
7548 for t, v in pairs_input:
7551 ("value", PairValue((Any(v),))),
7553 seq_inner = SeqInner()
7554 seq_inner["typeInner"] = type_innered
7555 seq_inner["valueInner"] = Any(pairs)
7556 seq_sequenced = Seq()
7557 seq_sequenced["type"] = type_sequenced
7558 seq_sequenced["value"] = OctetString(seq_inner.encode())
7559 seq_sequenced_raw = seq_sequenced.encode()
7561 list(seq_sequenced.pps())
7562 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7564 defines_by_path = []
7565 ctx_copied = deepcopy(ctx_dummy)
7566 seq_integered, _ = Seq().decode(
7570 self.assertDictEqual(ctx_copied, ctx_dummy)
7571 self.assertIsNone(seq_integered["value"].defined)
7572 defines_by_path.append(
7573 (("type",), ((("value",), {
7574 type_integered: Integer(),
7575 type_sequenced: SeqInner(),
7578 ctx_copied["defines_by_path"] = defines_by_path
7579 seq_integered, _ = Seq().decode(
7583 del ctx_copied["defines_by_path"]
7584 self.assertDictEqual(ctx_copied, ctx_dummy)
7585 self.assertIsNotNone(seq_integered["value"].defined)
7586 self.assertEqual(seq_integered["value"].defined[0], type_integered)
7587 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
7588 self.assertTrue(seq_integered_raw[
7589 seq_integered["value"].defined[1].offset:
7590 ].startswith(Integer(123).encode()))
7592 list(seq_integered.pps())
7593 pprint(seq_integered, big_blobs=True, with_decode_path=True)
7595 ctx_copied["defines_by_path"] = defines_by_path
7596 seq_sequenced, _ = Seq().decode(
7600 del ctx_copied["defines_by_path"]
7601 self.assertDictEqual(ctx_copied, ctx_dummy)
7602 self.assertIsNotNone(seq_sequenced["value"].defined)
7603 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7604 seq_inner = seq_sequenced["value"].defined[1]
7605 self.assertIsNone(seq_inner["valueInner"].defined)
7607 list(seq_sequenced.pps())
7608 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7610 defines_by_path.append((
7611 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
7612 ((("valueInner",), {type_innered: Pairs()}),),
7614 ctx_copied["defines_by_path"] = defines_by_path
7615 seq_sequenced, _ = Seq().decode(
7619 del ctx_copied["defines_by_path"]
7620 self.assertDictEqual(ctx_copied, ctx_dummy)
7621 self.assertIsNotNone(seq_sequenced["value"].defined)
7622 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7623 seq_inner = seq_sequenced["value"].defined[1]
7624 self.assertIsNotNone(seq_inner["valueInner"].defined)
7625 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7626 pairs = seq_inner["valueInner"].defined[1]
7628 self.assertIsNone(pair["value"][0].defined)
7630 list(seq_sequenced.pps())
7631 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7633 defines_by_path.append((
7636 DecodePathDefBy(type_sequenced),
7638 DecodePathDefBy(type_innered),
7643 type_integered: Integer(),
7644 type_octet_stringed: OctetString(),
7647 ctx_copied["defines_by_path"] = defines_by_path
7648 seq_sequenced, _ = Seq().decode(
7652 del ctx_copied["defines_by_path"]
7653 self.assertDictEqual(ctx_copied, ctx_dummy)
7654 self.assertIsNotNone(seq_sequenced["value"].defined)
7655 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7656 seq_inner = seq_sequenced["value"].defined[1]
7657 self.assertIsNotNone(seq_inner["valueInner"].defined)
7658 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7659 pairs_got = seq_inner["valueInner"].defined[1]
7660 for pair_input, pair_got in zip(pairs_input, pairs_got):
7661 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7662 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7664 list(seq_sequenced.pps())
7665 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7667 @given(oid_strategy(), integers())
7668 def test_simple(self, oid, tgt):
7669 class Inner(Sequence):
7671 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7672 ObjectIdentifier(oid): Integer(),
7676 class Outer(Sequence):
7679 ("tgt", OctetString()),
7683 inner["oid"] = ObjectIdentifier(oid)
7685 outer["inner"] = inner
7686 outer["tgt"] = OctetString(Integer(tgt).encode())
7687 decoded, _ = Outer().decode(outer.encode())
7688 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7690 def test_remaining_data(self):
7691 oid = ObjectIdentifier("1.2.3")
7693 class Seq(Sequence):
7695 ("oid", ObjectIdentifier(defines=((("tgt",), {
7698 ("tgt", OctetString()),
7703 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7705 with self.assertRaisesRegex(DecodeError, "remaining data"):
7706 Seq().decode(seq.encode())
7708 def test_remaining_data_seqof(self):
7709 oid = ObjectIdentifier("1.2.3")
7712 schema = OctetString()
7714 class Seq(Sequence):
7716 ("oid", ObjectIdentifier(defines=((("tgt",), {
7724 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7726 with self.assertRaisesRegex(DecodeError, "remaining data"):
7727 Seq().decode(seq.encode())
7730 class TestAbsDecodePath(TestCase):
7732 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7733 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7735 def test_concat(self, decode_path, rel_path):
7736 dp = abs_decode_path(decode_path, rel_path)
7737 self.assertSequenceEqual(dp, decode_path + rel_path)
7741 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7742 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7744 def test_abs(self, decode_path, rel_path):
7745 self.assertSequenceEqual(
7746 abs_decode_path(decode_path, ("/",) + rel_path),
7751 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7752 integers(min_value=1, max_value=3),
7753 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7755 def test_dots(self, decode_path, number_of_dots, rel_path):
7756 self.assertSequenceEqual(
7757 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7758 decode_path[:-number_of_dots] + rel_path,
7762 class TestStrictDefaultExistence(TestCase):
7763 @given(data_strategy())
7764 def runTest(self, d):
7765 count = d.draw(integers(min_value=1, max_value=10))
7766 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7768 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7769 for i in range(count)
7771 for klass in (Sequence, Set):
7775 for i in range(count):
7776 seq["int%d" % i] = Integer(123)
7778 chosen_choice = "int%d" % chosen
7779 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7780 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
7782 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7783 self.assertTrue(decoded.ber_encoded)
7784 self.assertTrue(decoded.bered)
7785 decoded = copy(decoded)
7786 self.assertTrue(decoded.ber_encoded)
7787 self.assertTrue(decoded.bered)
7788 decoded, _ = seq.decode(raw, ctx={"bered": True})
7789 self.assertTrue(decoded.ber_encoded)
7790 self.assertTrue(decoded.bered)
7791 decoded = copy(decoded)
7792 self.assertTrue(decoded.ber_encoded)
7793 self.assertTrue(decoded.bered)
7796 class TestX690PrefixedType(TestCase):
7798 self.assertSequenceEqual(
7799 VisibleString("Jones").encode(),
7800 hexdec("1A054A6F6E6573"),
7804 self.assertSequenceEqual(
7807 impl=tag_encode(3, klass=TagClassApplication),
7809 hexdec("43054A6F6E6573"),
7813 self.assertSequenceEqual(
7817 impl=tag_encode(3, klass=TagClassApplication),
7821 hexdec("A20743054A6F6E6573"),
7825 self.assertSequenceEqual(
7829 impl=tag_encode(3, klass=TagClassApplication),
7831 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7833 hexdec("670743054A6F6E6573"),
7837 self.assertSequenceEqual(
7838 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7839 hexdec("82054A6F6E6573"),
7843 class TestExplOOB(TestCase):
7845 expl = tag_ctxc(123)
7846 raw = Integer(123).encode() + Integer(234).encode()
7847 raw = b"".join((expl, len_encode(len(raw)), raw))
7848 with self.assertRaisesRegex(DecodeError, "explicit tag out-of-bound"):
7849 Integer(expl=expl).decode(raw)
7850 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7853 class TestPickleDifferentVersion(TestCase):
7855 pickled = pickle_dumps(Integer(123), pickle_proto)
7857 version_orig = pyderasn.__version__
7858 pyderasn.__version__ += "different"
7859 with self.assertRaisesRegex(ValueError, "different PyDERASN version"):
7860 pickle_loads(pickled)
7861 pyderasn.__version__ = version_orig
7862 pickle_loads(pickled)
7865 class TestCERSetOrdering(TestCase):
7866 def test_vectors(self):
7867 """Taken from X.690-201508
7871 ("c", Integer(impl=tag_ctxp(2))),
7872 ("d", Integer(impl=tag_ctxp(4))),
7877 ("g", Integer(impl=tag_ctxp(5))),
7878 ("h", Integer(impl=tag_ctxp(6))),
7883 ("j", Integer(impl=tag_ctxp(0))),
7894 ("a", Integer(impl=tag_ctxp(3))),
7895 ("b", B(expl=tag_ctxc(1))),
7900 ("a", Integer(123)),
7901 ("b", B(("d", Integer(234)))),
7902 ("e", E(("f", F(("g", Integer(345)))))),
7904 order = sorted(a._values_for_encoding(), key=attrgetter("tag_order_cer"))
7905 self.assertSequenceEqual(
7906 [i.__class__.__name__ for i in order],
7907 ("E", "B", "Integer"),