2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, version 3 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this program. If not, see
16 # <http://www.gnu.org/licenses/>.
19 from copy import deepcopy
20 from datetime import datetime
21 from datetime import timedelta
22 from importlib import import_module
23 from os import environ
24 from random import random
25 from string import ascii_letters
26 from string import digits
27 from string import printable
28 from string import whitespace
29 from time import mktime
31 from unittest import TestCase
33 from hypothesis import assume
34 from hypothesis import given
35 from hypothesis import settings
36 from hypothesis.strategies import binary
37 from hypothesis.strategies import booleans
38 from hypothesis.strategies import composite
39 from hypothesis.strategies import data as data_strategy
40 from hypothesis.strategies import datetimes
41 from hypothesis.strategies import dictionaries
42 from hypothesis.strategies import integers
43 from hypothesis.strategies import just
44 from hypothesis.strategies import lists
45 from hypothesis.strategies import none
46 from hypothesis.strategies import one_of
47 from hypothesis.strategies import permutations
48 from hypothesis.strategies import sampled_from
49 from hypothesis.strategies import sets
50 from hypothesis.strategies import text
51 from hypothesis.strategies import tuples
52 from six import assertRaisesRegex
53 from six import binary_type
54 from six import byte2int
55 from six import indexbytes
56 from six import int2byte
57 from six import iterbytes
59 from six import text_type
60 from six import unichr as six_unichr
61 from six.moves.cPickle import dumps as pickle_dumps
62 from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto
63 from six.moves.cPickle import loads as pickle_loads
65 from pyderasn import _pp
66 from pyderasn import abs_decode_path
67 from pyderasn import Any
68 from pyderasn import BitString
69 from pyderasn import BMPString
70 from pyderasn import Boolean
71 from pyderasn import BoundsError
72 from pyderasn import Choice
73 from pyderasn import DecodeError
74 from pyderasn import DecodePathDefBy
75 from pyderasn import Enumerated
76 from pyderasn import EOC
77 from pyderasn import EOC_LEN
78 from pyderasn import ExceedingData
79 from pyderasn import GeneralizedTime
80 from pyderasn import GeneralString
81 from pyderasn import GraphicString
82 from pyderasn import hexdec
83 from pyderasn import hexenc
84 from pyderasn import IA5String
85 from pyderasn import Integer
86 from pyderasn import InvalidLength
87 from pyderasn import InvalidOID
88 from pyderasn import InvalidValueType
89 from pyderasn import len_decode
90 from pyderasn import len_encode
91 from pyderasn import LEN_YYMMDDHHMMSSZ
92 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
93 from pyderasn import LEN_YYYYMMDDHHMMSSZ
94 from pyderasn import LENINDEF
95 from pyderasn import LenIndefForm
96 from pyderasn import NotEnoughData
97 from pyderasn import Null
98 from pyderasn import NumericString
99 from pyderasn import ObjectIdentifier
100 from pyderasn import ObjNotReady
101 from pyderasn import ObjUnknown
102 from pyderasn import OctetString
103 from pyderasn import pp_console_row
104 from pyderasn import pprint
105 from pyderasn import PrintableString
106 from pyderasn import Sequence
107 from pyderasn import SequenceOf
108 from pyderasn import Set
109 from pyderasn import SetOf
110 from pyderasn import tag_ctxc
111 from pyderasn import tag_ctxp
112 from pyderasn import tag_decode
113 from pyderasn import tag_encode
114 from pyderasn import tag_strip
115 from pyderasn import TagClassApplication
116 from pyderasn import TagClassContext
117 from pyderasn import TagClassPrivate
118 from pyderasn import TagClassUniversal
119 from pyderasn import TagFormConstructed
120 from pyderasn import TagFormPrimitive
121 from pyderasn import TagMismatch
122 from pyderasn import TeletexString
123 from pyderasn import UniversalString
124 from pyderasn import UTCTime
125 from pyderasn import UTF8String
126 from pyderasn import VideotexString
127 from pyderasn import VisibleString
130 max_examples = environ.get("MAX_EXAMPLES")
131 settings.register_profile("local", settings(
133 **({"max_examples": int(max_examples)} if max_examples else {})
135 settings.load_profile("local")
136 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
138 tag_classes = sampled_from((
144 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
145 decode_path_strat = lists(integers(), max_size=3).map(
146 lambda decode_path: tuple(str(dp) for dp in decode_path)
148 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
151 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
153 self_module = import_module(__name__)
156 def register_class(klass):
157 klassname = klass.__name__ + str(time()).replace(".", "")
158 klass.__name__ = klassname
159 klass.__qualname__ = klassname
160 setattr(self_module, klassname, klass)
163 def assert_exceeding_data(self, call, junk):
166 with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)) as err:
171 class TestHex(TestCase):
173 def test_symmetric(self, data):
174 self.assertEqual(hexdec(hexenc(data)), data)
177 class TestTagCoder(TestCase):
178 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
182 integers(min_value=0, max_value=30),
185 def test_short(self, klass, form, num, junk):
186 raw = tag_encode(klass=klass, form=form, num=num)
187 self.assertEqual(tag_decode(raw), (klass, form, num))
188 self.assertEqual(len(raw), 1)
190 byte2int(tag_encode(klass=klass, form=form, num=0)),
191 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
193 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
194 self.assertSequenceEqual(stripped.tobytes(), raw)
195 self.assertEqual(tlen, len(raw))
196 self.assertSequenceEqual(tail, junk)
198 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
202 integers(min_value=31),
205 def test_long(self, klass, form, num, junk):
206 raw = tag_encode(klass=klass, form=form, num=num)
207 self.assertEqual(tag_decode(raw), (klass, form, num))
208 self.assertGreater(len(raw), 1)
210 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
213 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
214 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
215 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
216 self.assertSequenceEqual(stripped.tobytes(), raw)
217 self.assertEqual(tlen, len(raw))
218 self.assertSequenceEqual(tail, junk)
220 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
221 @given(integers(min_value=31))
222 def test_unfinished_tag(self, num):
223 raw = bytearray(tag_encode(num=num))
224 for i in range(1, len(raw)):
226 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
227 tag_strip(bytes(raw))
229 def test_go_vectors_valid(self):
230 for data, (eklass, etag, elen, eform) in (
231 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
232 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
233 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
234 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
235 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
236 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
237 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
238 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
239 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
240 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
242 tag, _, len_encoded = tag_strip(memoryview(data))
243 klass, form, num = tag_decode(tag)
244 _len, _, tail = len_decode(len_encoded)
245 self.assertSequenceEqual(tail, b"")
246 self.assertEqual(klass, eklass)
247 self.assertEqual(num, etag)
248 self.assertEqual(_len, elen)
249 self.assertEqual(form, eform)
251 def test_go_vectors_invalid(self):
259 with self.assertRaises(DecodeError):
260 _, _, len_encoded = tag_strip(memoryview(data))
261 len_decode(len_encoded)
264 integers(min_value=0, max_value=127),
265 integers(min_value=0, max_value=2),
267 def test_long_instead_of_short(self, l, dummy_num):
268 octets = (b"\x00" * dummy_num) + int2byte(l)
269 octets = int2byte((dummy_num + 1) | 0x80) + octets
270 with self.assertRaises(DecodeError):
274 class TestLenCoder(TestCase):
275 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
277 integers(min_value=0, max_value=127),
280 def test_short(self, l, junk):
281 raw = len_encode(l) + junk
282 decoded, llen, tail = len_decode(memoryview(raw))
283 self.assertEqual(decoded, l)
284 self.assertEqual(llen, 1)
285 self.assertEqual(len(raw), 1 + len(junk))
286 self.assertEqual(tail.tobytes(), junk)
288 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
290 integers(min_value=128),
293 def test_long(self, l, junk):
294 raw = len_encode(l) + junk
295 decoded, llen, tail = len_decode(memoryview(raw))
296 self.assertEqual(decoded, l)
297 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
298 self.assertEqual(llen, len(raw) - len(junk))
299 self.assertNotEqual(indexbytes(raw, 1), 0)
300 self.assertSequenceEqual(tail.tobytes(), junk)
302 def test_empty(self):
303 with self.assertRaises(NotEnoughData):
306 @given(integers(min_value=128))
307 def test_stripped(self, _len):
308 with self.assertRaises(NotEnoughData):
309 len_decode(len_encode(_len)[:-1])
312 text_printable = text(alphabet=printable, min_size=1)
316 def text_letters(draw):
317 result = draw(text(alphabet=ascii_letters, min_size=1))
319 result = result.encode("ascii")
323 class CommonMixin(object):
324 def test_tag_default(self):
325 obj = self.base_klass()
326 self.assertEqual(obj.tag, obj.tag_default)
328 def test_simultaneous_impl_expl(self):
329 with self.assertRaises(ValueError):
330 self.base_klass(impl=b"whatever", expl=b"whenever")
332 @given(binary(min_size=1), integers(), integers(), integers())
333 def test_decoded(self, impl, offset, llen, vlen):
334 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
335 self.assertEqual(obj.offset, offset)
336 self.assertEqual(obj.llen, llen)
337 self.assertEqual(obj.vlen, vlen)
338 self.assertEqual(obj.tlen, len(impl))
339 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
341 @given(binary(min_size=1))
342 def test_impl_inherited(self, impl_tag):
343 class Inherited(self.base_klass):
346 self.assertSequenceEqual(obj.impl, impl_tag)
347 self.assertFalse(obj.expled)
349 @given(binary(min_size=1))
350 def test_expl_inherited(self, expl_tag):
351 class Inherited(self.base_klass):
354 self.assertSequenceEqual(obj.expl, expl_tag)
355 self.assertTrue(obj.expled)
357 def assert_copied_basic_fields(self, obj, obj_copied):
358 self.assertEqual(obj, obj_copied)
359 self.assertSequenceEqual(obj.tag, obj_copied.tag)
360 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
361 self.assertEqual(obj.default, obj_copied.default)
362 self.assertEqual(obj.optional, obj_copied.optional)
363 self.assertEqual(obj.offset, obj_copied.offset)
364 self.assertEqual(obj.llen, obj_copied.llen)
365 self.assertEqual(obj.vlen, obj_copied.vlen)
369 def boolean_values_strategy(draw, do_expl=False):
370 value = draw(one_of(none(), booleans()))
374 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
376 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
377 default = draw(one_of(none(), booleans()))
378 optional = draw(one_of(none(), booleans()))
380 draw(integers(min_value=0)),
381 draw(integers(min_value=0)),
382 draw(integers(min_value=0)),
384 return (value, impl, expl, default, optional, _decoded)
387 class BooleanInherited(Boolean):
391 class TestBoolean(CommonMixin, TestCase):
394 def test_invalid_value_type(self):
395 with self.assertRaises(InvalidValueType) as err:
400 def test_optional(self, optional):
401 obj = Boolean(default=Boolean(False), optional=optional)
402 self.assertTrue(obj.optional)
405 def test_ready(self, value):
407 self.assertFalse(obj.ready)
410 pprint(obj, big_blobs=True, with_decode_path=True)
411 with self.assertRaises(ObjNotReady) as err:
415 self.assertTrue(obj.ready)
418 pprint(obj, big_blobs=True, with_decode_path=True)
420 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
421 def test_comparison(self, value1, value2, tag1, tag2):
422 for klass in (Boolean, BooleanInherited):
425 self.assertEqual(obj1 == obj2, value1 == value2)
426 self.assertEqual(obj1 != obj2, value1 != value2)
427 self.assertEqual(obj1 == bool(obj2), value1 == value2)
428 obj1 = klass(value1, impl=tag1)
429 obj2 = klass(value1, impl=tag2)
430 self.assertEqual(obj1 == obj2, tag1 == tag2)
431 self.assertEqual(obj1 != obj2, tag1 != tag2)
433 @given(data_strategy())
434 def test_call(self, d):
435 for klass in (Boolean, BooleanInherited):
443 ) = d.draw(boolean_values_strategy())
449 optional_initial or False,
459 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
460 obj = obj_initial(value, impl, expl, default, optional)
462 value_expected = default if value is None else value
464 default_initial if value_expected is None
467 self.assertEqual(obj, value_expected)
468 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
469 self.assertEqual(obj.expl_tag, expl or expl_initial)
472 default_initial if default is None else default,
474 if obj.default is None:
475 optional = optional_initial if optional is None else optional
476 optional = False if optional is None else optional
479 self.assertEqual(obj.optional, optional)
481 @given(boolean_values_strategy())
482 def test_copy(self, values):
483 for klass in (Boolean, BooleanInherited):
485 for copy_func in copy_funcs:
486 obj_copied = copy_func(obj)
487 self.assert_copied_basic_fields(obj, obj_copied)
491 integers(min_value=1).map(tag_encode),
493 def test_stripped(self, value, tag_impl):
494 obj = Boolean(value, impl=tag_impl)
495 with self.assertRaises(NotEnoughData):
496 obj.decode(obj.encode()[:-1])
500 integers(min_value=1).map(tag_ctxc),
502 def test_stripped_expl(self, value, tag_expl):
503 obj = Boolean(value, expl=tag_expl)
504 with self.assertRaises(NotEnoughData):
505 obj.decode(obj.encode()[:-1])
508 integers(min_value=31),
509 integers(min_value=0),
512 def test_bad_tag(self, tag, offset, decode_path):
513 with self.assertRaises(DecodeError) as err:
515 tag_encode(tag)[:-1],
517 decode_path=decode_path,
520 self.assertEqual(err.exception.offset, offset)
521 self.assertEqual(err.exception.decode_path, decode_path)
524 integers(min_value=31),
525 integers(min_value=0),
528 def test_bad_expl_tag(self, tag, offset, decode_path):
529 with self.assertRaises(DecodeError) as err:
530 Boolean(expl=Boolean.tag_default).decode(
531 tag_encode(tag)[:-1],
533 decode_path=decode_path,
536 self.assertEqual(err.exception.offset, offset)
537 self.assertEqual(err.exception.decode_path, decode_path)
540 integers(min_value=128),
541 integers(min_value=0),
544 def test_bad_len(self, l, offset, decode_path):
545 with self.assertRaises(DecodeError) as err:
547 Boolean.tag_default + len_encode(l)[:-1],
549 decode_path=decode_path,
552 self.assertEqual(err.exception.offset, offset)
553 self.assertEqual(err.exception.decode_path, decode_path)
556 integers(min_value=128),
557 integers(min_value=0),
560 def test_bad_expl_len(self, l, offset, decode_path):
561 with self.assertRaises(DecodeError) as err:
562 Boolean(expl=Boolean.tag_default).decode(
563 Boolean.tag_default + len_encode(l)[:-1],
565 decode_path=decode_path,
568 self.assertEqual(err.exception.offset, offset)
569 self.assertEqual(err.exception.decode_path, decode_path)
571 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
573 boolean_values_strategy(),
575 integers(min_value=1).map(tag_ctxc),
576 integers(min_value=0),
579 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
580 for klass in (Boolean, BooleanInherited):
581 _, _, _, default, optional, _decoded = values
590 pprint(obj, big_blobs=True, with_decode_path=True)
591 self.assertFalse(obj.expled)
592 obj_encoded = obj.encode()
593 obj_expled = obj(value, expl=tag_expl)
594 self.assertTrue(obj_expled.expled)
596 list(obj_expled.pps())
597 pprint(obj_expled, big_blobs=True, with_decode_path=True)
598 obj_expled_hex_encoded = obj_expled.hexencode()
599 ctx_copied = deepcopy(ctx_dummy)
600 obj_decoded, tail = obj_expled.hexdecode(
601 obj_expled_hex_encoded + hexenc(tail_junk),
605 self.assertDictEqual(ctx_copied, ctx_dummy)
607 list(obj_decoded.pps())
608 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
609 self.assertEqual(tail, tail_junk)
610 self.assertEqual(obj_decoded, obj_expled)
611 self.assertNotEqual(obj_decoded, obj)
612 self.assertEqual(bool(obj_decoded), bool(obj_expled))
613 self.assertEqual(bool(obj_decoded), bool(obj))
614 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
615 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
616 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
618 obj_decoded.expl_llen,
619 len(len_encode(len(obj_encoded))),
621 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
622 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
625 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
627 self.assertEqual(obj_decoded.expl_offset, offset)
628 assert_exceeding_data(
630 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
634 @given(integers(min_value=2))
635 def test_invalid_len(self, l):
636 with self.assertRaises(InvalidLength):
637 Boolean().decode(b"".join((
643 @given(integers(min_value=0 + 1, max_value=255 - 1))
644 def test_ber_value(self, value):
645 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
646 Boolean().decode(b"".join((
651 obj, _ = Boolean().decode(
659 self.assertTrue(bool(obj))
660 self.assertTrue(obj.ber_encoded)
661 self.assertFalse(obj.lenindef)
662 self.assertTrue(obj.bered)
664 self.assertTrue(obj.ber_encoded)
665 self.assertFalse(obj.lenindef)
666 self.assertTrue(obj.bered)
669 integers(min_value=1).map(tag_ctxc),
670 binary().filter(lambda x: not x.startswith(EOC)),
672 def test_ber_expl_no_eoc(self, expl, junk):
673 encoded = expl + LENINDEF + Boolean(False).encode()
674 with self.assertRaises(LenIndefForm):
675 Boolean(expl=expl).decode(encoded + junk)
676 with assertRaisesRegex(self, DecodeError, "no EOC"):
677 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
678 obj, tail = Boolean(expl=expl).decode(
679 encoded + EOC + junk,
682 self.assertTrue(obj.expl_lenindef)
683 self.assertFalse(obj.lenindef)
684 self.assertFalse(obj.ber_encoded)
685 self.assertTrue(obj.bered)
687 self.assertTrue(obj.expl_lenindef)
688 self.assertFalse(obj.lenindef)
689 self.assertFalse(obj.ber_encoded)
690 self.assertTrue(obj.bered)
691 self.assertSequenceEqual(tail, junk)
694 pprint(obj, big_blobs=True, with_decode_path=True)
697 integers(min_value=1).map(tag_ctxc),
704 def test_ber_expl(self, expl, values):
710 Boolean(value).encode() +
713 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
715 class SeqOf(SequenceOf):
716 schema = Boolean(expl=expl)
717 with self.assertRaises(LenIndefForm):
718 SeqOf().decode(encoded)
719 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
720 self.assertSequenceEqual(tail, b"")
721 self.assertSequenceEqual([bool(v) for v in seqof], values)
737 len(expl) + 1 + 3 + EOC_LEN,
748 pprint(seqof, big_blobs=True, with_decode_path=True)
752 def integer_values_strategy(draw, do_expl=False):
753 bound_min, value, default, bound_max = sorted(draw(sets(
762 _specs = draw(sets(text_letters()))
765 min_size=len(_specs),
766 max_size=len(_specs),
768 _specs = list(zip(_specs, values))
771 bounds = (bound_min, bound_max)
775 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
777 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
780 optional = draw(one_of(none(), booleans()))
782 draw(integers(min_value=0)),
783 draw(integers(min_value=0)),
784 draw(integers(min_value=0)),
786 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
789 class IntegerInherited(Integer):
793 class TestInteger(CommonMixin, TestCase):
796 def test_invalid_value_type(self):
797 with self.assertRaises(InvalidValueType) as err:
801 @given(sets(text_letters(), min_size=2))
802 def test_unknown_name(self, names_input):
803 missing = names_input.pop()
806 schema = [(n, 123) for n in names_input]
807 with self.assertRaises(ObjUnknown) as err:
811 @given(sets(text_letters(), min_size=2))
812 def test_known_name(self, names_input):
814 schema = [(n, 123) for n in names_input]
815 Int(names_input.pop())
818 def test_optional(self, optional):
819 obj = Integer(default=Integer(0), optional=optional)
820 self.assertTrue(obj.optional)
823 def test_ready(self, value):
825 self.assertFalse(obj.ready)
828 pprint(obj, big_blobs=True, with_decode_path=True)
829 with self.assertRaises(ObjNotReady) as err:
833 self.assertTrue(obj.ready)
836 pprint(obj, big_blobs=True, with_decode_path=True)
839 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
840 def test_comparison(self, value1, value2, tag1, tag2):
841 for klass in (Integer, IntegerInherited):
844 self.assertEqual(obj1 == obj2, value1 == value2)
845 self.assertEqual(obj1 != obj2, value1 != value2)
846 self.assertEqual(obj1 == int(obj2), value1 == value2)
847 obj1 = klass(value1, impl=tag1)
848 obj2 = klass(value1, impl=tag2)
849 self.assertEqual(obj1 == obj2, tag1 == tag2)
850 self.assertEqual(obj1 != obj2, tag1 != tag2)
852 @given(lists(integers()))
853 def test_sorted_works(self, values):
854 self.assertSequenceEqual(
855 [int(v) for v in sorted(Integer(v) for v in values)],
859 @given(data_strategy())
860 def test_named(self, d):
861 names_input = list(d.draw(sets(text_letters(), min_size=1)))
862 values_input = list(d.draw(sets(
864 min_size=len(names_input),
865 max_size=len(names_input),
867 chosen_name = d.draw(sampled_from(names_input))
868 names_input = dict(zip(names_input, values_input))
872 _int = Int(chosen_name)
873 self.assertEqual(_int.named, chosen_name)
874 self.assertEqual(int(_int), names_input[chosen_name])
876 @given(integers(), integers(min_value=0), integers(min_value=0))
877 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
878 value = bound_min + value_delta
879 bound_max = value + bound_delta
880 Integer(value=value, bounds=(bound_min, bound_max))
882 @given(sets(integers(), min_size=3, max_size=3))
883 def test_bounds_unsatisfied(self, values):
884 values = sorted(values)
885 with self.assertRaises(BoundsError) as err:
886 Integer(value=values[0], bounds=(values[1], values[2]))
888 with assertRaisesRegex(self, DecodeError, "bounds") as err:
889 Integer(bounds=(values[1], values[2])).decode(
890 Integer(values[0]).encode()
893 with self.assertRaises(BoundsError) as err:
894 Integer(value=values[2], bounds=(values[0], values[1]))
896 with assertRaisesRegex(self, DecodeError, "bounds") as err:
897 Integer(bounds=(values[0], values[1])).decode(
898 Integer(values[2]).encode()
902 @given(data_strategy())
903 def test_call(self, d):
904 for klass in (Integer, IntegerInherited):
914 ) = d.draw(integer_values_strategy())
921 optional_initial or False,
934 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
935 if (default is None) and (obj_initial.default is not None):
939 (value is not None) and
940 (bounds_initial is not None) and
941 not (bounds_initial[0] <= value <= bounds_initial[1])
946 (default is not None) and
947 (bounds_initial is not None) and
948 not (bounds_initial[0] <= default <= bounds_initial[1])
951 obj = obj_initial(value, bounds, impl, expl, default, optional)
953 value_expected = default if value is None else value
955 default_initial if value_expected is None
958 self.assertEqual(obj, value_expected)
959 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
960 self.assertEqual(obj.expl_tag, expl or expl_initial)
963 default_initial if default is None else default,
965 if obj.default is None:
966 optional = optional_initial if optional is None else optional
967 optional = False if optional is None else optional
970 self.assertEqual(obj.optional, optional)
972 (obj._bound_min, obj._bound_max),
973 bounds or bounds_initial or (float("-inf"), float("+inf")),
977 {} if _specs_initial is None else dict(_specs_initial),
980 @given(integer_values_strategy())
981 def test_copy(self, values):
982 for klass in (Integer, IntegerInherited):
984 for copy_func in copy_funcs:
985 obj_copied = copy_func(obj)
986 self.assert_copied_basic_fields(obj, obj_copied)
987 self.assertEqual(obj.specs, obj_copied.specs)
988 self.assertEqual(obj._bound_min, obj_copied._bound_min)
989 self.assertEqual(obj._bound_max, obj_copied._bound_max)
990 self.assertEqual(obj._value, obj_copied._value)
994 integers(min_value=1).map(tag_encode),
996 def test_stripped(self, value, tag_impl):
997 obj = Integer(value, impl=tag_impl)
998 with self.assertRaises(NotEnoughData):
999 obj.decode(obj.encode()[:-1])
1003 integers(min_value=1).map(tag_ctxc),
1005 def test_stripped_expl(self, value, tag_expl):
1006 obj = Integer(value, expl=tag_expl)
1007 with self.assertRaises(NotEnoughData):
1008 obj.decode(obj.encode()[:-1])
1010 def test_zero_len(self):
1011 with self.assertRaises(NotEnoughData):
1012 Integer().decode(b"".join((
1013 Integer.tag_default,
1018 integers(min_value=31),
1019 integers(min_value=0),
1022 def test_bad_tag(self, tag, offset, decode_path):
1023 with self.assertRaises(DecodeError) as err:
1025 tag_encode(tag)[:-1],
1027 decode_path=decode_path,
1030 self.assertEqual(err.exception.offset, offset)
1031 self.assertEqual(err.exception.decode_path, decode_path)
1034 integers(min_value=128),
1035 integers(min_value=0),
1038 def test_bad_len(self, l, offset, decode_path):
1039 with self.assertRaises(DecodeError) as err:
1041 Integer.tag_default + len_encode(l)[:-1],
1043 decode_path=decode_path,
1046 self.assertEqual(err.exception.offset, offset)
1047 self.assertEqual(err.exception.decode_path, decode_path)
1050 sets(integers(), min_size=2, max_size=2),
1051 integers(min_value=0),
1054 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1055 value, bound_min = list(sorted(ints))
1058 bounds = (bound_min, bound_min)
1059 with self.assertRaises(DecodeError) as err:
1061 Integer(value).encode(),
1063 decode_path=decode_path,
1066 self.assertEqual(err.exception.offset, offset)
1067 self.assertEqual(err.exception.decode_path, decode_path)
1069 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1071 integer_values_strategy(),
1073 integers(min_value=1).map(tag_ctxc),
1074 integers(min_value=0),
1077 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1078 for klass in (Integer, IntegerInherited):
1079 _, _, _, _, default, optional, _, _decoded = values
1088 pprint(obj, big_blobs=True, with_decode_path=True)
1089 self.assertFalse(obj.expled)
1090 obj_encoded = obj.encode()
1091 obj_expled = obj(value, expl=tag_expl)
1092 self.assertTrue(obj_expled.expled)
1094 list(obj_expled.pps())
1095 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1096 obj_expled_encoded = obj_expled.encode()
1097 ctx_copied = deepcopy(ctx_dummy)
1098 obj_decoded, tail = obj_expled.decode(
1099 obj_expled_encoded + tail_junk,
1103 self.assertDictEqual(ctx_copied, ctx_dummy)
1105 list(obj_decoded.pps())
1106 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1107 self.assertEqual(tail, tail_junk)
1108 self.assertEqual(obj_decoded, obj_expled)
1109 self.assertNotEqual(obj_decoded, obj)
1110 self.assertEqual(int(obj_decoded), int(obj_expled))
1111 self.assertEqual(int(obj_decoded), int(obj))
1112 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1113 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1114 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1116 obj_decoded.expl_llen,
1117 len(len_encode(len(obj_encoded))),
1119 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1120 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1123 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1125 self.assertEqual(obj_decoded.expl_offset, offset)
1126 assert_exceeding_data(
1128 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1132 def test_go_vectors_valid(self):
1133 for data, expect in ((
1137 (b"\xff\x7f", -129),
1141 (b"\xff\x00", -256),
1145 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1146 (b"\x80\x00\x00\x00", -2147483648),
1149 Integer().decode(b"".join((
1150 Integer.tag_default,
1151 len_encode(len(data)),
1157 def test_go_vectors_invalid(self):
1162 with self.assertRaises(DecodeError):
1163 Integer().decode(b"".join((
1164 Integer.tag_default,
1165 len_encode(len(data)),
1171 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1174 if draw(booleans()):
1175 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1177 integers(min_value=0, max_value=255),
1178 min_size=len(schema),
1179 max_size=len(schema),
1181 schema = list(zip(schema, bits))
1183 def _value(value_required):
1184 if not value_required and draw(booleans()):
1186 generation_choice = 0
1188 generation_choice = draw(sampled_from((1, 2, 3)))
1189 if generation_choice == 1 or draw(booleans()):
1190 return "'%s'B" % "".join(draw(lists(
1191 sampled_from(("0", "1")),
1192 max_size=len(schema),
1194 if generation_choice == 2 or draw(booleans()):
1195 return draw(binary(max_size=len(schema) // 8))
1196 if generation_choice == 3 or draw(booleans()):
1197 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1199 value = _value(value_required)
1200 default = _value(value_required=False)
1204 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1206 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1207 optional = draw(one_of(none(), booleans()))
1209 draw(integers(min_value=0)),
1210 draw(integers(min_value=0)),
1211 draw(integers(min_value=0)),
1213 return (schema, value, impl, expl, default, optional, _decoded)
1216 class BitStringInherited(BitString):
1220 class TestBitString(CommonMixin, TestCase):
1221 base_klass = BitString
1223 @given(lists(booleans()))
1224 def test_b_encoding(self, bits):
1225 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1226 self.assertEqual(obj.bit_len, len(bits))
1227 self.assertSequenceEqual(list(obj), bits)
1228 for i, bit in enumerate(bits):
1229 self.assertEqual(obj[i], bit)
1231 @given(lists(booleans()))
1232 def test_out_of_bounds_bits(self, bits):
1233 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1234 for i in range(len(bits), len(bits) * 2):
1235 self.assertFalse(obj[i])
1237 def test_bad_b_encoding(self):
1238 with self.assertRaises(ValueError):
1239 BitString("'010120101'B")
1242 integers(min_value=1, max_value=255),
1243 integers(min_value=1, max_value=255),
1245 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1246 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1247 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1248 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1250 class BS(BitString):
1251 schema = (("whatever", 0),)
1252 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1253 self.assertEqual(obj.bit_len, leading_zeros + 1)
1254 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1256 def test_zero_len(self):
1257 with self.assertRaises(NotEnoughData):
1258 BitString().decode(b"".join((
1259 BitString.tag_default,
1263 def test_invalid_value_type(self):
1264 with self.assertRaises(InvalidValueType) as err:
1267 with self.assertRaises(InvalidValueType) as err:
1271 def test_obj_unknown(self):
1272 with self.assertRaises(ObjUnknown) as err:
1273 BitString(b"whatever")["whenever"]
1276 def test_get_invalid_type(self):
1277 with self.assertRaises(InvalidValueType) as err:
1278 BitString(b"whatever")[(1, 2, 3)]
1281 @given(data_strategy())
1282 def test_unknown_name(self, d):
1283 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1284 missing = _schema.pop()
1286 class BS(BitString):
1287 schema = [(n, i) for i, n in enumerate(_schema)]
1288 with self.assertRaises(ObjUnknown) as err:
1293 def test_optional(self, optional):
1294 obj = BitString(default=BitString(b""), optional=optional)
1295 self.assertTrue(obj.optional)
1298 def test_ready(self, value):
1300 self.assertFalse(obj.ready)
1303 pprint(obj, big_blobs=True, with_decode_path=True)
1304 with self.assertRaises(ObjNotReady) as err:
1307 obj = BitString(value)
1308 self.assertTrue(obj.ready)
1311 pprint(obj, big_blobs=True, with_decode_path=True)
1314 tuples(integers(min_value=0), binary()),
1315 tuples(integers(min_value=0), binary()),
1319 def test_comparison(self, value1, value2, tag1, tag2):
1320 for klass in (BitString, BitStringInherited):
1321 obj1 = klass(value1)
1322 obj2 = klass(value2)
1323 self.assertEqual(obj1 == obj2, value1 == value2)
1324 self.assertEqual(obj1 != obj2, value1 != value2)
1325 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1326 obj1 = klass(value1, impl=tag1)
1327 obj2 = klass(value1, impl=tag2)
1328 self.assertEqual(obj1 == obj2, tag1 == tag2)
1329 self.assertEqual(obj1 != obj2, tag1 != tag2)
1331 @given(data_strategy())
1332 def test_call(self, d):
1333 for klass in (BitString, BitStringInherited):
1342 ) = d.draw(bit_string_values_strategy())
1345 schema = schema_initial
1347 value=value_initial,
1350 default=default_initial,
1351 optional=optional_initial or False,
1352 _decoded=_decoded_initial,
1362 ) = d.draw(bit_string_values_strategy(
1363 schema=schema_initial,
1364 do_expl=impl_initial is None,
1373 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1374 self.assertEqual(obj.expl_tag, expl or expl_initial)
1375 if obj.default is None:
1376 optional = optional_initial if optional is None else optional
1377 optional = False if optional is None else optional
1380 self.assertEqual(obj.optional, optional)
1381 self.assertEqual(obj.specs, obj_initial.specs)
1383 @given(bit_string_values_strategy())
1384 def test_copy(self, values):
1385 for klass in (BitString, BitStringInherited):
1386 _schema, value, impl, expl, default, optional, _decoded = values
1396 optional=optional or False,
1399 for copy_func in copy_funcs:
1400 obj_copied = copy_func(obj)
1401 self.assert_copied_basic_fields(obj, obj_copied)
1402 self.assertEqual(obj.specs, obj_copied.specs)
1403 self.assertEqual(obj._value, obj_copied._value)
1407 integers(min_value=1).map(tag_encode),
1409 def test_stripped(self, value, tag_impl):
1410 obj = BitString(value, impl=tag_impl)
1411 with self.assertRaises(NotEnoughData):
1412 obj.decode(obj.encode()[:-1])
1416 integers(min_value=1).map(tag_ctxc),
1418 def test_stripped_expl(self, value, tag_expl):
1419 obj = BitString(value, expl=tag_expl)
1420 with self.assertRaises(NotEnoughData):
1421 obj.decode(obj.encode()[:-1])
1424 integers(min_value=31),
1425 integers(min_value=0),
1428 def test_bad_tag(self, tag, offset, decode_path):
1429 with self.assertRaises(DecodeError) as err:
1431 tag_encode(tag)[:-1],
1433 decode_path=decode_path,
1436 self.assertEqual(err.exception.offset, offset)
1437 self.assertEqual(err.exception.decode_path, decode_path)
1440 integers(min_value=128),
1441 integers(min_value=0),
1444 def test_bad_len(self, l, offset, decode_path):
1445 with self.assertRaises(DecodeError) as err:
1447 BitString.tag_default + len_encode(l)[:-1],
1449 decode_path=decode_path,
1452 self.assertEqual(err.exception.offset, offset)
1453 self.assertEqual(err.exception.decode_path, decode_path)
1455 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1456 @given(data_strategy())
1457 def test_symmetric(self, d):
1466 ) = d.draw(bit_string_values_strategy(value_required=True))
1467 tail_junk = d.draw(binary(max_size=5))
1468 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1469 offset = d.draw(integers(min_value=0))
1470 for klass in (BitString, BitStringInherited):
1481 pprint(obj, big_blobs=True, with_decode_path=True)
1482 self.assertFalse(obj.expled)
1483 obj_encoded = obj.encode()
1484 obj_expled = obj(value, expl=tag_expl)
1485 self.assertTrue(obj_expled.expled)
1487 list(obj_expled.pps())
1488 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1489 obj_expled_encoded = obj_expled.encode()
1490 ctx_copied = deepcopy(ctx_dummy)
1491 obj_decoded, tail = obj_expled.decode(
1492 obj_expled_encoded + tail_junk,
1496 self.assertDictEqual(ctx_copied, ctx_dummy)
1498 list(obj_decoded.pps())
1499 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1500 self.assertEqual(tail, tail_junk)
1501 self.assertEqual(obj_decoded, obj_expled)
1502 self.assertNotEqual(obj_decoded, obj)
1503 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1504 self.assertEqual(bytes(obj_decoded), bytes(obj))
1505 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1506 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1507 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1509 obj_decoded.expl_llen,
1510 len(len_encode(len(obj_encoded))),
1512 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1513 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1516 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1518 self.assertEqual(obj_decoded.expl_offset, offset)
1519 if isinstance(value, tuple):
1520 self.assertSetEqual(set(value), set(obj_decoded.named))
1523 assert_exceeding_data(
1525 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1529 @given(integers(min_value=1, max_value=255))
1530 def test_bad_zero_value(self, pad_size):
1531 with self.assertRaises(DecodeError):
1532 BitString().decode(b"".join((
1533 BitString.tag_default,
1538 def test_go_vectors_invalid(self):
1544 with self.assertRaises(DecodeError):
1545 BitString().decode(b"".join((
1546 BitString.tag_default,
1551 def test_go_vectors_valid(self):
1552 obj, _ = BitString().decode(b"".join((
1553 BitString.tag_default,
1557 self.assertEqual(bytes(obj), b"")
1558 self.assertEqual(obj.bit_len, 0)
1560 obj, _ = BitString().decode(b"".join((
1561 BitString.tag_default,
1565 self.assertEqual(bytes(obj), b"\x00")
1566 self.assertEqual(obj.bit_len, 1)
1568 obj = BitString((16, b"\x82\x40"))
1569 self.assertTrue(obj[0])
1570 self.assertFalse(obj[1])
1571 self.assertTrue(obj[6])
1572 self.assertTrue(obj[9])
1573 self.assertFalse(obj[17])
1576 integers(min_value=1, max_value=30),
1579 binary(min_size=1, max_size=5),
1581 binary(min_size=1, max_size=5),
1589 lists(booleans(), min_size=1),
1592 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1593 def chunk_constructed(contents):
1595 tag_encode(form=TagFormConstructed, num=3) +
1597 b"".join(BitString(content).encode() for content in contents) +
1601 payload_expected = b""
1602 bit_len_expected = 0
1603 for chunk_input in chunk_inputs:
1604 if isinstance(chunk_input, binary_type):
1605 chunks.append(BitString(chunk_input).encode())
1606 payload_expected += chunk_input
1607 bit_len_expected += len(chunk_input) * 8
1609 chunks.append(chunk_constructed(chunk_input))
1610 payload = b"".join(chunk_input)
1611 payload_expected += payload
1612 bit_len_expected += len(payload) * 8
1613 chunk_last = BitString("'%s'B" % "".join(
1614 "1" if bit else "0" for bit in chunk_last_bits
1616 payload_expected += bytes(chunk_last)
1617 bit_len_expected += chunk_last.bit_len
1618 encoded_indefinite = (
1619 tag_encode(form=TagFormConstructed, num=impl) +
1622 chunk_last.encode() +
1625 encoded_definite = (
1626 tag_encode(form=TagFormConstructed, num=impl) +
1627 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1631 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1632 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1633 for lenindef_expected, encoded in (
1634 (True, encoded_indefinite),
1635 (False, encoded_definite),
1637 obj, tail = BitString(impl=tag_encode(impl)).decode(
1639 ctx={"bered": True},
1641 self.assertSequenceEqual(tail, junk)
1642 self.assertEqual(obj.bit_len, bit_len_expected)
1643 self.assertSequenceEqual(bytes(obj), payload_expected)
1644 self.assertTrue(obj.ber_encoded)
1645 self.assertEqual(obj.lenindef, lenindef_expected)
1646 self.assertTrue(obj.bered)
1648 self.assertTrue(obj.ber_encoded)
1649 self.assertEqual(obj.lenindef, lenindef_expected)
1650 self.assertTrue(obj.bered)
1651 self.assertEqual(len(encoded), obj.tlvlen)
1654 pprint(obj, big_blobs=True, with_decode_path=True)
1657 integers(min_value=0),
1660 def test_ber_definite_too_short(self, offset, decode_path):
1661 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1663 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1665 decode_path=decode_path,
1666 ctx={"bered": True},
1668 self.assertEqual(err.exception.decode_path, decode_path)
1669 self.assertEqual(err.exception.offset, offset)
1672 integers(min_value=0),
1675 def test_ber_definite_no_data(self, offset, decode_path):
1676 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1678 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1680 decode_path=decode_path,
1681 ctx={"bered": True},
1683 self.assertEqual(err.exception.decode_path, decode_path)
1684 self.assertEqual(err.exception.offset, offset)
1687 integers(min_value=0),
1689 integers(min_value=1, max_value=3),
1691 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1692 bs = BitString(b"data").encode()
1693 with self.assertRaises(NotEnoughData) as err:
1695 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1697 decode_path=decode_path,
1698 ctx={"bered": True},
1700 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1701 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1704 integers(min_value=0),
1706 integers(min_value=1, max_value=3),
1708 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1709 bs = BitString(b"data").encode()
1710 bs_longer = BitString(b"data-longer").encode()
1711 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1714 tag_encode(3, form=TagFormConstructed) +
1715 len_encode((chunks + 1) * len(bs)) +
1720 decode_path=decode_path,
1721 ctx={"bered": True},
1723 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1724 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1727 integers(min_value=0),
1730 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1731 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1733 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1735 decode_path=decode_path,
1736 ctx={"bered": True},
1738 self.assertEqual(err.exception.decode_path, decode_path)
1739 self.assertEqual(err.exception.offset, offset)
1741 @given(data_strategy())
1742 def test_ber_indefinite_not_multiple(self, d):
1743 bs_short = BitString("'A'H").encode()
1744 bs_full = BitString("'AA'H").encode()
1745 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1746 chunks.append(bs_short)
1747 d.draw(permutations(chunks))
1748 chunks.append(bs_short)
1749 offset = d.draw(integers(min_value=0))
1750 decode_path = d.draw(decode_path_strat)
1751 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1754 tag_encode(3, form=TagFormConstructed) +
1760 decode_path=decode_path,
1761 ctx={"bered": True},
1764 err.exception.decode_path,
1765 decode_path + (str(chunks.index(bs_short)),),
1768 err.exception.offset,
1769 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1772 def test_x690_vector(self):
1773 vector = BitString("'0A3B5F291CD'H")
1774 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1775 self.assertSequenceEqual(tail, b"")
1776 self.assertEqual(obj, vector)
1777 obj, tail = BitString().decode(
1778 hexdec("23800303000A3B0305045F291CD00000"),
1779 ctx={"bered": True},
1781 self.assertSequenceEqual(tail, b"")
1782 self.assertEqual(obj, vector)
1783 self.assertTrue(obj.ber_encoded)
1784 self.assertTrue(obj.lenindef)
1785 self.assertTrue(obj.bered)
1787 self.assertTrue(obj.ber_encoded)
1788 self.assertTrue(obj.lenindef)
1789 self.assertTrue(obj.bered)
1793 def octet_string_values_strategy(draw, do_expl=False):
1794 bound_min, bound_max = sorted(draw(sets(
1795 integers(min_value=0, max_value=1 << 7),
1799 value = draw(one_of(
1801 binary(min_size=bound_min, max_size=bound_max),
1803 default = draw(one_of(
1805 binary(min_size=bound_min, max_size=bound_max),
1808 if draw(booleans()):
1809 bounds = (bound_min, bound_max)
1813 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1815 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1816 optional = draw(one_of(none(), booleans()))
1818 draw(integers(min_value=0)),
1819 draw(integers(min_value=0)),
1820 draw(integers(min_value=0)),
1822 return (value, bounds, impl, expl, default, optional, _decoded)
1825 class OctetStringInherited(OctetString):
1829 class TestOctetString(CommonMixin, TestCase):
1830 base_klass = OctetString
1832 def test_invalid_value_type(self):
1833 with self.assertRaises(InvalidValueType) as err:
1834 OctetString(text_type(123))
1838 def test_optional(self, optional):
1839 obj = OctetString(default=OctetString(b""), optional=optional)
1840 self.assertTrue(obj.optional)
1843 def test_ready(self, value):
1845 self.assertFalse(obj.ready)
1848 pprint(obj, big_blobs=True, with_decode_path=True)
1849 with self.assertRaises(ObjNotReady) as err:
1852 obj = OctetString(value)
1853 self.assertTrue(obj.ready)
1856 pprint(obj, big_blobs=True, with_decode_path=True)
1858 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1859 def test_comparison(self, value1, value2, tag1, tag2):
1860 for klass in (OctetString, OctetStringInherited):
1861 obj1 = klass(value1)
1862 obj2 = klass(value2)
1863 self.assertEqual(obj1 == obj2, value1 == value2)
1864 self.assertEqual(obj1 != obj2, value1 != value2)
1865 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1866 obj1 = klass(value1, impl=tag1)
1867 obj2 = klass(value1, impl=tag2)
1868 self.assertEqual(obj1 == obj2, tag1 == tag2)
1869 self.assertEqual(obj1 != obj2, tag1 != tag2)
1871 @given(lists(binary()))
1872 def test_sorted_works(self, values):
1873 self.assertSequenceEqual(
1874 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1878 @given(data_strategy())
1879 def test_bounds_satisfied(self, d):
1880 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1881 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1882 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1883 OctetString(value=value, bounds=(bound_min, bound_max))
1885 @given(data_strategy())
1886 def test_bounds_unsatisfied(self, d):
1887 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1888 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1889 value = d.draw(binary(max_size=bound_min - 1))
1890 with self.assertRaises(BoundsError) as err:
1891 OctetString(value=value, bounds=(bound_min, bound_max))
1893 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1894 OctetString(bounds=(bound_min, bound_max)).decode(
1895 OctetString(value).encode()
1898 value = d.draw(binary(min_size=bound_max + 1))
1899 with self.assertRaises(BoundsError) as err:
1900 OctetString(value=value, bounds=(bound_min, bound_max))
1902 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1903 OctetString(bounds=(bound_min, bound_max)).decode(
1904 OctetString(value).encode()
1908 @given(data_strategy())
1909 def test_call(self, d):
1910 for klass in (OctetString, OctetStringInherited):
1919 ) = d.draw(octet_string_values_strategy())
1920 obj_initial = klass(
1926 optional_initial or False,
1937 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1938 if (default is None) and (obj_initial.default is not None):
1941 (bounds is None) and
1942 (value is not None) and
1943 (bounds_initial is not None) and
1944 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1948 (bounds is None) and
1949 (default is not None) and
1950 (bounds_initial is not None) and
1951 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1954 obj = obj_initial(value, bounds, impl, expl, default, optional)
1956 value_expected = default if value is None else value
1958 default_initial if value_expected is None
1961 self.assertEqual(obj, value_expected)
1962 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1963 self.assertEqual(obj.expl_tag, expl or expl_initial)
1966 default_initial if default is None else default,
1968 if obj.default is None:
1969 optional = optional_initial if optional is None else optional
1970 optional = False if optional is None else optional
1973 self.assertEqual(obj.optional, optional)
1975 (obj._bound_min, obj._bound_max),
1976 bounds or bounds_initial or (0, float("+inf")),
1979 @given(octet_string_values_strategy())
1980 def test_copy(self, values):
1981 for klass in (OctetString, OctetStringInherited):
1982 obj = klass(*values)
1983 for copy_func in copy_funcs:
1984 obj_copied = copy_func(obj)
1985 self.assert_copied_basic_fields(obj, obj_copied)
1986 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1987 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1988 self.assertEqual(obj._value, obj_copied._value)
1992 integers(min_value=1).map(tag_encode),
1994 def test_stripped(self, value, tag_impl):
1995 obj = OctetString(value, impl=tag_impl)
1996 with self.assertRaises(NotEnoughData):
1997 obj.decode(obj.encode()[:-1])
2001 integers(min_value=1).map(tag_ctxc),
2003 def test_stripped_expl(self, value, tag_expl):
2004 obj = OctetString(value, expl=tag_expl)
2005 with self.assertRaises(NotEnoughData):
2006 obj.decode(obj.encode()[:-1])
2009 integers(min_value=31),
2010 integers(min_value=0),
2013 def test_bad_tag(self, tag, offset, decode_path):
2014 with self.assertRaises(DecodeError) as err:
2015 OctetString().decode(
2016 tag_encode(tag)[:-1],
2018 decode_path=decode_path,
2021 self.assertEqual(err.exception.offset, offset)
2022 self.assertEqual(err.exception.decode_path, decode_path)
2025 integers(min_value=128),
2026 integers(min_value=0),
2029 def test_bad_len(self, l, offset, decode_path):
2030 with self.assertRaises(DecodeError) as err:
2031 OctetString().decode(
2032 OctetString.tag_default + len_encode(l)[:-1],
2034 decode_path=decode_path,
2037 self.assertEqual(err.exception.offset, offset)
2038 self.assertEqual(err.exception.decode_path, decode_path)
2041 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2042 integers(min_value=0),
2045 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2046 value, bound_min = list(sorted(ints))
2048 class String(OctetString):
2049 bounds = (bound_min, bound_min)
2050 with self.assertRaises(DecodeError) as err:
2052 OctetString(b"\x00" * value).encode(),
2054 decode_path=decode_path,
2057 self.assertEqual(err.exception.offset, offset)
2058 self.assertEqual(err.exception.decode_path, decode_path)
2060 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2062 octet_string_values_strategy(),
2064 integers(min_value=1).map(tag_ctxc),
2065 integers(min_value=0),
2068 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2069 for klass in (OctetString, OctetStringInherited):
2070 _, _, _, _, default, optional, _decoded = values
2079 pprint(obj, big_blobs=True, with_decode_path=True)
2080 self.assertFalse(obj.expled)
2081 obj_encoded = obj.encode()
2082 obj_expled = obj(value, expl=tag_expl)
2083 self.assertTrue(obj_expled.expled)
2085 list(obj_expled.pps())
2086 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2087 obj_expled_encoded = obj_expled.encode()
2088 ctx_copied = deepcopy(ctx_dummy)
2089 obj_decoded, tail = obj_expled.decode(
2090 obj_expled_encoded + tail_junk,
2094 self.assertDictEqual(ctx_copied, ctx_dummy)
2096 list(obj_decoded.pps())
2097 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2098 self.assertEqual(tail, tail_junk)
2099 self.assertEqual(obj_decoded, obj_expled)
2100 self.assertNotEqual(obj_decoded, obj)
2101 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2102 self.assertEqual(bytes(obj_decoded), bytes(obj))
2103 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2104 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2105 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2107 obj_decoded.expl_llen,
2108 len(len_encode(len(obj_encoded))),
2110 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2111 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2114 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2116 self.assertEqual(obj_decoded.expl_offset, offset)
2117 assert_exceeding_data(
2119 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2124 integers(min_value=1, max_value=30),
2127 binary(min_size=1, max_size=5),
2129 binary(min_size=1, max_size=5),
2139 def test_constructed(self, impl, chunk_inputs, junk):
2140 def chunk_constructed(contents):
2142 tag_encode(form=TagFormConstructed, num=4) +
2144 b"".join(OctetString(content).encode() for content in contents) +
2148 payload_expected = b""
2149 for chunk_input in chunk_inputs:
2150 if isinstance(chunk_input, binary_type):
2151 chunks.append(OctetString(chunk_input).encode())
2152 payload_expected += chunk_input
2154 chunks.append(chunk_constructed(chunk_input))
2155 payload = b"".join(chunk_input)
2156 payload_expected += payload
2157 encoded_indefinite = (
2158 tag_encode(form=TagFormConstructed, num=impl) +
2163 encoded_definite = (
2164 tag_encode(form=TagFormConstructed, num=impl) +
2165 len_encode(len(b"".join(chunks))) +
2168 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2169 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2170 for lenindef_expected, encoded in (
2171 (True, encoded_indefinite),
2172 (False, encoded_definite),
2174 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2176 ctx={"bered": True},
2178 self.assertSequenceEqual(tail, junk)
2179 self.assertSequenceEqual(bytes(obj), payload_expected)
2180 self.assertTrue(obj.ber_encoded)
2181 self.assertEqual(obj.lenindef, lenindef_expected)
2182 self.assertTrue(obj.bered)
2184 self.assertTrue(obj.ber_encoded)
2185 self.assertEqual(obj.lenindef, lenindef_expected)
2186 self.assertTrue(obj.bered)
2187 self.assertEqual(len(encoded), obj.tlvlen)
2190 pprint(obj, big_blobs=True, with_decode_path=True)
2193 integers(min_value=0),
2196 def test_ber_definite_too_short(self, offset, decode_path):
2197 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2198 OctetString().decode(
2199 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2201 decode_path=decode_path,
2202 ctx={"bered": True},
2204 self.assertEqual(err.exception.decode_path, decode_path)
2205 self.assertEqual(err.exception.offset, offset)
2208 integers(min_value=0),
2210 integers(min_value=1, max_value=3),
2212 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2213 bs = OctetString(b"data").encode()
2214 with self.assertRaises(NotEnoughData) as err:
2215 OctetString().decode(
2216 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2218 decode_path=decode_path,
2219 ctx={"bered": True},
2221 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2222 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2225 integers(min_value=0),
2227 integers(min_value=1, max_value=3),
2229 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2230 bs = OctetString(b"data").encode()
2231 bs_longer = OctetString(b"data-longer").encode()
2232 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2233 OctetString().decode(
2235 tag_encode(4, form=TagFormConstructed) +
2236 len_encode((chunks + 1) * len(bs)) +
2241 decode_path=decode_path,
2242 ctx={"bered": True},
2244 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2245 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2249 def null_values_strategy(draw, do_expl=False):
2253 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2255 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2256 optional = draw(one_of(none(), booleans()))
2258 draw(integers(min_value=0)),
2259 draw(integers(min_value=0)),
2260 draw(integers(min_value=0)),
2262 return (impl, expl, optional, _decoded)
2265 class NullInherited(Null):
2269 class TestNull(CommonMixin, TestCase):
2272 def test_ready(self):
2274 self.assertTrue(obj.ready)
2277 pprint(obj, big_blobs=True, with_decode_path=True)
2279 @given(binary(min_size=1), binary(min_size=1))
2280 def test_comparison(self, tag1, tag2):
2281 for klass in (Null, NullInherited):
2282 obj1 = klass(impl=tag1)
2283 obj2 = klass(impl=tag2)
2284 self.assertEqual(obj1 == obj2, tag1 == tag2)
2285 self.assertEqual(obj1 != obj2, tag1 != tag2)
2286 self.assertNotEqual(obj1, tag2)
2288 @given(data_strategy())
2289 def test_call(self, d):
2290 for klass in (Null, NullInherited):
2296 ) = d.draw(null_values_strategy())
2297 obj_initial = klass(
2300 optional=optional_initial or False,
2301 _decoded=_decoded_initial,
2308 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2309 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2310 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2311 self.assertEqual(obj.expl_tag, expl or expl_initial)
2312 optional = optional_initial if optional is None else optional
2313 optional = False if optional is None else optional
2314 self.assertEqual(obj.optional, optional)
2316 @given(null_values_strategy())
2317 def test_copy(self, values):
2318 for klass in (Null, NullInherited):
2319 impl, expl, optional, _decoded = values
2323 optional=optional or False,
2326 for copy_func in copy_funcs:
2327 obj_copied = copy_func(obj)
2328 self.assert_copied_basic_fields(obj, obj_copied)
2330 @given(integers(min_value=1).map(tag_encode))
2331 def test_stripped(self, tag_impl):
2332 obj = Null(impl=tag_impl)
2333 with self.assertRaises(NotEnoughData):
2334 obj.decode(obj.encode()[:-1])
2336 @given(integers(min_value=1).map(tag_ctxc))
2337 def test_stripped_expl(self, tag_expl):
2338 obj = Null(expl=tag_expl)
2339 with self.assertRaises(NotEnoughData):
2340 obj.decode(obj.encode()[:-1])
2343 integers(min_value=31),
2344 integers(min_value=0),
2347 def test_bad_tag(self, tag, offset, decode_path):
2348 with self.assertRaises(DecodeError) as err:
2350 tag_encode(tag)[:-1],
2352 decode_path=decode_path,
2355 self.assertEqual(err.exception.offset, offset)
2356 self.assertEqual(err.exception.decode_path, decode_path)
2359 integers(min_value=128),
2360 integers(min_value=0),
2363 def test_bad_len(self, l, offset, decode_path):
2364 with self.assertRaises(DecodeError) as err:
2366 Null.tag_default + len_encode(l)[:-1],
2368 decode_path=decode_path,
2371 self.assertEqual(err.exception.offset, offset)
2372 self.assertEqual(err.exception.decode_path, decode_path)
2374 @given(binary(min_size=1))
2375 def test_tag_mismatch(self, impl):
2376 assume(impl != Null.tag_default)
2377 with self.assertRaises(TagMismatch):
2378 Null(impl=impl).decode(Null().encode())
2381 null_values_strategy(),
2382 integers(min_value=1).map(tag_ctxc),
2383 integers(min_value=0),
2386 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2387 for klass in (Null, NullInherited):
2388 _, _, optional, _decoded = values
2389 obj = klass(optional=optional, _decoded=_decoded)
2392 pprint(obj, big_blobs=True, with_decode_path=True)
2393 self.assertFalse(obj.expled)
2394 obj_encoded = obj.encode()
2395 obj_expled = obj(expl=tag_expl)
2396 self.assertTrue(obj_expled.expled)
2398 list(obj_expled.pps())
2399 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2400 obj_expled_encoded = obj_expled.encode()
2401 ctx_copied = deepcopy(ctx_dummy)
2402 obj_decoded, tail = obj_expled.decode(
2403 obj_expled_encoded + tail_junk,
2407 self.assertDictEqual(ctx_copied, ctx_dummy)
2409 list(obj_decoded.pps())
2410 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2411 self.assertEqual(tail, tail_junk)
2412 self.assertEqual(obj_decoded, obj_expled)
2413 self.assertNotEqual(obj_decoded, obj)
2414 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2415 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2416 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2418 obj_decoded.expl_llen,
2419 len(len_encode(len(obj_encoded))),
2421 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2422 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2425 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2427 self.assertEqual(obj_decoded.expl_offset, offset)
2428 assert_exceeding_data(
2430 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2434 @given(integers(min_value=1))
2435 def test_invalid_len(self, l):
2436 with self.assertRaises(InvalidLength):
2437 Null().decode(b"".join((
2444 def oid_strategy(draw):
2445 first_arc = draw(integers(min_value=0, max_value=2))
2447 if first_arc in (0, 1):
2448 second_arc = draw(integers(min_value=0, max_value=39))
2450 second_arc = draw(integers(min_value=0))
2451 other_arcs = draw(lists(integers(min_value=0)))
2452 return tuple([first_arc, second_arc] + other_arcs)
2456 def oid_values_strategy(draw, do_expl=False):
2457 value = draw(one_of(none(), oid_strategy()))
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 default = draw(one_of(none(), oid_strategy()))
2465 optional = draw(one_of(none(), booleans()))
2467 draw(integers(min_value=0)),
2468 draw(integers(min_value=0)),
2469 draw(integers(min_value=0)),
2471 return (value, impl, expl, default, optional, _decoded)
2474 class ObjectIdentifierInherited(ObjectIdentifier):
2478 class TestObjectIdentifier(CommonMixin, TestCase):
2479 base_klass = ObjectIdentifier
2481 def test_invalid_value_type(self):
2482 with self.assertRaises(InvalidValueType) as err:
2483 ObjectIdentifier(123)
2487 def test_optional(self, optional):
2488 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2489 self.assertTrue(obj.optional)
2491 @given(oid_strategy())
2492 def test_ready(self, value):
2493 obj = ObjectIdentifier()
2494 self.assertFalse(obj.ready)
2497 pprint(obj, big_blobs=True, with_decode_path=True)
2498 with self.assertRaises(ObjNotReady) as err:
2501 obj = ObjectIdentifier(value)
2502 self.assertTrue(obj.ready)
2503 self.assertFalse(obj.ber_encoded)
2506 pprint(obj, big_blobs=True, with_decode_path=True)
2509 @given(oid_strategy(), oid_strategy(), binary(min_size=1), binary(min_size=1))
2510 def test_comparison(self, value1, value2, tag1, tag2):
2511 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2512 obj1 = klass(value1)
2513 obj2 = klass(value2)
2514 self.assertEqual(obj1 == obj2, value1 == value2)
2515 self.assertEqual(obj1 != obj2, value1 != value2)
2516 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2517 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2518 obj1 = klass(value1, impl=tag1)
2519 obj2 = klass(value1, impl=tag2)
2520 self.assertEqual(obj1 == obj2, tag1 == tag2)
2521 self.assertEqual(obj1 != obj2, tag1 != tag2)
2523 @given(lists(oid_strategy()))
2524 def test_sorted_works(self, values):
2525 self.assertSequenceEqual(
2526 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2530 @given(data_strategy())
2531 def test_call(self, d):
2532 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2540 ) = d.draw(oid_values_strategy())
2541 obj_initial = klass(
2542 value=value_initial,
2545 default=default_initial,
2546 optional=optional_initial or False,
2547 _decoded=_decoded_initial,
2556 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2565 value_expected = default if value is None else value
2567 default_initial if value_expected is None
2570 self.assertEqual(obj, value_expected)
2571 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2572 self.assertEqual(obj.expl_tag, expl or expl_initial)
2575 default_initial if default is None else default,
2577 if obj.default is None:
2578 optional = optional_initial if optional is None else optional
2579 optional = False if optional is None else optional
2582 self.assertEqual(obj.optional, optional)
2584 @given(oid_values_strategy())
2585 def test_copy(self, values):
2586 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2603 for copy_func in copy_funcs:
2604 obj_copied = copy_func(obj)
2605 self.assert_copied_basic_fields(obj, obj_copied)
2606 self.assertEqual(obj._value, obj_copied._value)
2608 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2611 integers(min_value=1).map(tag_encode),
2613 def test_stripped(self, value, tag_impl):
2614 obj = ObjectIdentifier(value, impl=tag_impl)
2615 with self.assertRaises(NotEnoughData):
2616 obj.decode(obj.encode()[:-1])
2620 integers(min_value=1).map(tag_ctxc),
2622 def test_stripped_expl(self, value, tag_expl):
2623 obj = ObjectIdentifier(value, expl=tag_expl)
2624 with self.assertRaises(NotEnoughData):
2625 obj.decode(obj.encode()[:-1])
2628 integers(min_value=31),
2629 integers(min_value=0),
2632 def test_bad_tag(self, tag, offset, decode_path):
2633 with self.assertRaises(DecodeError) as err:
2634 ObjectIdentifier().decode(
2635 tag_encode(tag)[:-1],
2637 decode_path=decode_path,
2640 self.assertEqual(err.exception.offset, offset)
2641 self.assertEqual(err.exception.decode_path, decode_path)
2644 integers(min_value=128),
2645 integers(min_value=0),
2648 def test_bad_len(self, l, offset, decode_path):
2649 with self.assertRaises(DecodeError) as err:
2650 ObjectIdentifier().decode(
2651 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2653 decode_path=decode_path,
2656 self.assertEqual(err.exception.offset, offset)
2657 self.assertEqual(err.exception.decode_path, decode_path)
2659 def test_zero_oid(self):
2660 with self.assertRaises(NotEnoughData):
2661 ObjectIdentifier().decode(
2662 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2665 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2666 @given(oid_strategy())
2667 def test_unfinished_oid(self, value):
2668 assume(list(value)[-1] > 255)
2669 obj_encoded = ObjectIdentifier(value).encode()
2670 obj, _ = ObjectIdentifier().decode(obj_encoded)
2671 data = obj_encoded[obj.tlen + obj.llen:-1]
2673 ObjectIdentifier.tag_default,
2674 len_encode(len(data)),
2677 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2680 @given(integers(min_value=0))
2681 def test_invalid_short(self, value):
2682 with self.assertRaises(InvalidOID):
2683 ObjectIdentifier((value,))
2684 with self.assertRaises(InvalidOID):
2685 ObjectIdentifier("%d" % value)
2687 @given(integers(min_value=3), integers(min_value=0))
2688 def test_invalid_first_arc(self, first_arc, second_arc):
2689 with self.assertRaises(InvalidOID):
2690 ObjectIdentifier((first_arc, second_arc))
2691 with self.assertRaises(InvalidOID):
2692 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2694 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2695 def test_invalid_second_arc(self, first_arc, second_arc):
2696 with self.assertRaises(InvalidOID):
2697 ObjectIdentifier((first_arc, second_arc))
2698 with self.assertRaises(InvalidOID):
2699 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2701 @given(text(alphabet=ascii_letters + ".", min_size=1))
2702 def test_junk(self, oid):
2703 with self.assertRaises(InvalidOID):
2704 ObjectIdentifier(oid)
2706 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2707 @given(oid_strategy())
2708 def test_validness(self, oid):
2709 obj = ObjectIdentifier(oid)
2710 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2713 pprint(obj, big_blobs=True, with_decode_path=True)
2715 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2717 oid_values_strategy(),
2719 integers(min_value=1).map(tag_ctxc),
2720 integers(min_value=0),
2723 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2724 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2725 _, _, _, default, optional, _decoded = values
2734 pprint(obj, big_blobs=True, with_decode_path=True)
2735 self.assertFalse(obj.expled)
2736 obj_encoded = obj.encode()
2737 obj_expled = obj(value, expl=tag_expl)
2738 self.assertTrue(obj_expled.expled)
2740 list(obj_expled.pps())
2741 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2742 obj_expled_encoded = obj_expled.encode()
2743 ctx_copied = deepcopy(ctx_dummy)
2744 obj_decoded, tail = obj_expled.decode(
2745 obj_expled_encoded + tail_junk,
2749 self.assertDictEqual(ctx_copied, ctx_dummy)
2751 list(obj_decoded.pps())
2752 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2753 self.assertEqual(tail, tail_junk)
2754 self.assertEqual(obj_decoded, obj_expled)
2755 self.assertNotEqual(obj_decoded, obj)
2756 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2757 self.assertEqual(tuple(obj_decoded), tuple(obj))
2758 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2759 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2760 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2762 obj_decoded.expl_llen,
2763 len(len_encode(len(obj_encoded))),
2765 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2766 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2769 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2771 self.assertEqual(obj_decoded.expl_offset, offset)
2772 assert_exceeding_data(
2774 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2779 oid_strategy().map(ObjectIdentifier),
2780 oid_strategy().map(ObjectIdentifier),
2782 def test_add(self, oid1, oid2):
2783 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2784 for oid_to_add in (oid2, tuple(oid2)):
2785 self.assertEqual(oid1 + oid_to_add, oid_expect)
2786 with self.assertRaises(InvalidValueType):
2789 def test_go_vectors_valid(self):
2790 for data, expect in (
2792 (b"\x55\x02", (2, 5, 2)),
2793 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2794 (b"\x81\x34\x03", (2, 100, 3)),
2797 ObjectIdentifier().decode(b"".join((
2798 ObjectIdentifier.tag_default,
2799 len_encode(len(data)),
2805 def test_go_vectors_invalid(self):
2806 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2807 with self.assertRaises(DecodeError):
2808 ObjectIdentifier().decode(b"".join((
2809 Integer.tag_default,
2810 len_encode(len(data)),
2814 def test_x690_vector(self):
2816 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2817 ObjectIdentifier((2, 999, 3)),
2820 def test_nonnormalized_first_arc(self):
2822 ObjectIdentifier.tag_default +
2825 ObjectIdentifier((1, 0)).encode()[-1:]
2827 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2828 self.assertTrue(obj.ber_encoded)
2829 self.assertTrue(obj.bered)
2831 self.assertTrue(obj.ber_encoded)
2832 self.assertTrue(obj.bered)
2833 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2834 ObjectIdentifier().decode(tampered)
2836 @given(data_strategy())
2837 def test_negative_arcs(self, d):
2838 oid = list(d.draw(oid_strategy()))
2841 idx = d.draw(integers(min_value=3, max_value=len(oid)))
2843 if oid[idx - 1] == 0:
2845 with self.assertRaises(InvalidOID):
2846 ObjectIdentifier(tuple(oid))
2847 with self.assertRaises(InvalidOID):
2848 ObjectIdentifier(".".join(str(i) for i in oid))
2850 @given(data_strategy())
2851 def test_plused_arcs(self, d):
2852 oid = [str(arc) for arc in d.draw(oid_strategy())]
2853 idx = d.draw(integers(min_value=0, max_value=len(oid)))
2854 oid[idx - 1] = "+" + oid[idx - 1]
2855 with self.assertRaises(InvalidOID):
2856 ObjectIdentifier(".".join(str(i) for i in oid))
2858 @given(data_strategy())
2859 def test_nonnormalized_arcs(self, d):
2860 arcs = d.draw(lists(
2861 integers(min_value=0, max_value=100),
2865 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2866 _, _, lv = tag_strip(dered)
2867 _, _, v = len_decode(lv)
2868 v_no_first_arc = v[1:]
2869 idx_for_tamper = d.draw(integers(
2871 max_value=len(v_no_first_arc) - 1,
2873 tampered = list(bytearray(v_no_first_arc))
2874 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2875 tampered.insert(idx_for_tamper, 0x80)
2876 tampered = bytes(bytearray(tampered))
2878 ObjectIdentifier.tag_default +
2879 len_encode(len(tampered)) +
2882 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2883 self.assertTrue(obj.ber_encoded)
2884 self.assertTrue(obj.bered)
2886 self.assertTrue(obj.ber_encoded)
2887 self.assertTrue(obj.bered)
2888 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2889 ObjectIdentifier().decode(tampered)
2893 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2895 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2896 values = list(draw(sets(
2898 min_size=len(schema),
2899 max_size=len(schema),
2901 schema = list(zip(schema, values))
2902 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2906 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2908 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2909 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2910 optional = draw(one_of(none(), booleans()))
2912 draw(integers(min_value=0)),
2913 draw(integers(min_value=0)),
2914 draw(integers(min_value=0)),
2916 return (schema, value, impl, expl, default, optional, _decoded)
2919 class TestEnumerated(CommonMixin, TestCase):
2920 class EWhatever(Enumerated):
2921 schema = (("whatever", 0),)
2923 base_klass = EWhatever
2925 def test_schema_required(self):
2926 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2929 def test_invalid_value_type(self):
2930 with self.assertRaises(InvalidValueType) as err:
2931 self.base_klass((1, 2))
2934 @given(sets(text_letters(), min_size=2))
2935 def test_unknown_name(self, schema_input):
2936 missing = schema_input.pop()
2938 class E(Enumerated):
2939 schema = [(n, 123) for n in schema_input]
2940 with self.assertRaises(ObjUnknown) as err:
2945 sets(text_letters(), min_size=2),
2946 sets(integers(), min_size=2),
2948 def test_unknown_value(self, schema_input, values_input):
2950 missing_value = values_input.pop()
2951 _input = list(zip(schema_input, values_input))
2953 class E(Enumerated):
2955 with self.assertRaises(DecodeError) as err:
2960 def test_optional(self, optional):
2961 obj = self.base_klass(default="whatever", optional=optional)
2962 self.assertTrue(obj.optional)
2964 def test_ready(self):
2965 obj = self.base_klass()
2966 self.assertFalse(obj.ready)
2969 pprint(obj, big_blobs=True, with_decode_path=True)
2970 with self.assertRaises(ObjNotReady) as err:
2973 obj = self.base_klass("whatever")
2974 self.assertTrue(obj.ready)
2977 pprint(obj, big_blobs=True, with_decode_path=True)
2979 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
2980 def test_comparison(self, value1, value2, tag1, tag2):
2981 class E(Enumerated):
2983 ("whatever0", value1),
2984 ("whatever1", value2),
2987 class EInherited(E):
2989 for klass in (E, EInherited):
2990 obj1 = klass(value1)
2991 obj2 = klass(value2)
2992 self.assertEqual(obj1 == obj2, value1 == value2)
2993 self.assertEqual(obj1 != obj2, value1 != value2)
2994 self.assertEqual(obj1 == int(obj2), value1 == value2)
2995 obj1 = klass(value1, impl=tag1)
2996 obj2 = klass(value1, impl=tag2)
2997 self.assertEqual(obj1 == obj2, tag1 == tag2)
2998 self.assertEqual(obj1 != obj2, tag1 != tag2)
3000 @given(data_strategy())
3001 def test_call(self, d):
3010 ) = d.draw(enumerated_values_strategy())
3012 class E(Enumerated):
3013 schema = schema_initial
3015 value=value_initial,
3018 default=default_initial,
3019 optional=optional_initial or False,
3020 _decoded=_decoded_initial,
3030 ) = d.draw(enumerated_values_strategy(
3031 schema=schema_initial,
3032 do_expl=impl_initial is None,
3042 value_expected = default if value is None else value
3044 default_initial if value_expected is None
3049 dict(schema_initial).get(value_expected, value_expected),
3051 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3052 self.assertEqual(obj.expl_tag, expl or expl_initial)
3055 default_initial if default is None else default,
3057 if obj.default is None:
3058 optional = optional_initial if optional is None else optional
3059 optional = False if optional is None else optional
3062 self.assertEqual(obj.optional, optional)
3063 self.assertEqual(obj.specs, dict(schema_initial))
3065 @given(enumerated_values_strategy())
3066 def test_copy(self, values):
3067 schema_input, value, impl, expl, default, optional, _decoded = values
3069 class E(Enumerated):
3070 schema = schema_input
3080 for copy_func in copy_funcs:
3081 obj_copied = copy_func(obj)
3082 self.assert_copied_basic_fields(obj, obj_copied)
3083 self.assertEqual(obj.specs, obj_copied.specs)
3085 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3086 @given(data_strategy())
3087 def test_symmetric(self, d):
3088 schema_input, _, _, _, default, optional, _decoded = d.draw(
3089 enumerated_values_strategy(),
3091 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3092 offset = d.draw(integers(min_value=0))
3093 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3094 tail_junk = d.draw(binary(max_size=5))
3096 class E(Enumerated):
3097 schema = schema_input
3106 pprint(obj, big_blobs=True, with_decode_path=True)
3107 self.assertFalse(obj.expled)
3108 obj_encoded = obj.encode()
3109 obj_expled = obj(value, expl=tag_expl)
3110 self.assertTrue(obj_expled.expled)
3112 list(obj_expled.pps())
3113 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3114 obj_expled_encoded = obj_expled.encode()
3115 ctx_copied = deepcopy(ctx_dummy)
3116 obj_decoded, tail = obj_expled.decode(
3117 obj_expled_encoded + tail_junk,
3121 self.assertDictEqual(ctx_copied, ctx_dummy)
3123 list(obj_decoded.pps())
3124 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3125 self.assertEqual(tail, tail_junk)
3126 self.assertEqual(obj_decoded, obj_expled)
3127 self.assertNotEqual(obj_decoded, obj)
3128 self.assertEqual(int(obj_decoded), int(obj_expled))
3129 self.assertEqual(int(obj_decoded), int(obj))
3130 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3131 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3132 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3134 obj_decoded.expl_llen,
3135 len(len_encode(len(obj_encoded))),
3137 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3138 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3141 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3143 self.assertEqual(obj_decoded.expl_offset, offset)
3144 assert_exceeding_data(
3146 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3152 def string_values_strategy(draw, alphabet, do_expl=False):
3153 bound_min, bound_max = sorted(draw(sets(
3154 integers(min_value=0, max_value=1 << 7),
3158 value = draw(one_of(
3160 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3162 default = draw(one_of(
3164 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3167 if draw(booleans()):
3168 bounds = (bound_min, bound_max)
3172 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3174 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3175 optional = draw(one_of(none(), booleans()))
3177 draw(integers(min_value=0)),
3178 draw(integers(min_value=0)),
3179 draw(integers(min_value=0)),
3181 return (value, bounds, impl, expl, default, optional, _decoded)
3184 class StringMixin(object):
3185 def test_invalid_value_type(self):
3186 with self.assertRaises(InvalidValueType) as err:
3187 self.base_klass((1, 2))
3190 def text_alphabet(self):
3191 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3192 return printable + whitespace
3196 def test_optional(self, optional):
3197 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3198 self.assertTrue(obj.optional)
3200 @given(data_strategy())
3201 def test_ready(self, d):
3202 obj = self.base_klass()
3203 self.assertFalse(obj.ready)
3206 pprint(obj, big_blobs=True, with_decode_path=True)
3208 with self.assertRaises(ObjNotReady) as err:
3211 value = d.draw(text(alphabet=self.text_alphabet()))
3212 obj = self.base_klass(value)
3213 self.assertTrue(obj.ready)
3216 pprint(obj, big_blobs=True, with_decode_path=True)
3219 @given(data_strategy())
3220 def test_comparison(self, d):
3221 value1 = d.draw(text(alphabet=self.text_alphabet()))
3222 value2 = d.draw(text(alphabet=self.text_alphabet()))
3223 tag1 = d.draw(binary(min_size=1))
3224 tag2 = d.draw(binary(min_size=1))
3225 obj1 = self.base_klass(value1)
3226 obj2 = self.base_klass(value2)
3227 self.assertEqual(obj1 == obj2, value1 == value2)
3228 self.assertEqual(obj1 != obj2, value1 != value2)
3229 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3230 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3231 obj1 = self.base_klass(value1, impl=tag1)
3232 obj2 = self.base_klass(value1, impl=tag2)
3233 self.assertEqual(obj1 == obj2, tag1 == tag2)
3234 self.assertEqual(obj1 != obj2, tag1 != tag2)
3236 @given(data_strategy())
3237 def test_bounds_satisfied(self, d):
3238 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3239 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3240 value = d.draw(text(
3241 alphabet=self.text_alphabet(),
3245 self.base_klass(value=value, bounds=(bound_min, bound_max))
3247 @given(data_strategy())
3248 def test_bounds_unsatisfied(self, d):
3249 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3250 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3251 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3252 with self.assertRaises(BoundsError) as err:
3253 self.base_klass(value=value, bounds=(bound_min, bound_max))
3255 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3256 self.base_klass(bounds=(bound_min, bound_max)).decode(
3257 self.base_klass(value).encode()
3260 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3261 with self.assertRaises(BoundsError) as err:
3262 self.base_klass(value=value, bounds=(bound_min, bound_max))
3264 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3265 self.base_klass(bounds=(bound_min, bound_max)).decode(
3266 self.base_klass(value).encode()
3270 @given(data_strategy())
3271 def test_call(self, d):
3280 ) = d.draw(string_values_strategy(self.text_alphabet()))
3281 obj_initial = self.base_klass(
3287 optional_initial or False,
3298 ) = d.draw(string_values_strategy(
3299 self.text_alphabet(),
3300 do_expl=impl_initial is None,
3302 if (default is None) and (obj_initial.default is not None):
3305 (bounds is None) and
3306 (value is not None) and
3307 (bounds_initial is not None) and
3308 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3312 (bounds is None) and
3313 (default is not None) and
3314 (bounds_initial is not None) and
3315 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3318 obj = obj_initial(value, bounds, impl, expl, default, optional)
3320 value_expected = default if value is None else value
3322 default_initial if value_expected is None
3325 self.assertEqual(obj, value_expected)
3326 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3327 self.assertEqual(obj.expl_tag, expl or expl_initial)
3330 default_initial if default is None else default,
3332 if obj.default is None:
3333 optional = optional_initial if optional is None else optional
3334 optional = False if optional is None else optional
3337 self.assertEqual(obj.optional, optional)
3339 (obj._bound_min, obj._bound_max),
3340 bounds or bounds_initial or (0, float("+inf")),
3343 @given(data_strategy())
3344 def test_copy(self, d):
3345 values = d.draw(string_values_strategy(self.text_alphabet()))
3346 obj = self.base_klass(*values)
3347 for copy_func in copy_funcs:
3348 obj_copied = copy_func(obj)
3349 self.assert_copied_basic_fields(obj, obj_copied)
3350 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3351 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3352 self.assertEqual(obj._value, obj_copied._value)
3354 @given(data_strategy())
3355 def test_stripped(self, d):
3356 value = d.draw(text(alphabet=self.text_alphabet()))
3357 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3358 obj = self.base_klass(value, impl=tag_impl)
3359 with self.assertRaises(NotEnoughData):
3360 obj.decode(obj.encode()[:-1])
3362 @given(data_strategy())
3363 def test_stripped_expl(self, d):
3364 value = d.draw(text(alphabet=self.text_alphabet()))
3365 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3366 obj = self.base_klass(value, expl=tag_expl)
3367 with self.assertRaises(NotEnoughData):
3368 obj.decode(obj.encode()[:-1])
3371 integers(min_value=31),
3372 integers(min_value=0),
3375 def test_bad_tag(self, tag, offset, decode_path):
3376 with self.assertRaises(DecodeError) as err:
3377 self.base_klass().decode(
3378 tag_encode(tag)[:-1],
3380 decode_path=decode_path,
3383 self.assertEqual(err.exception.offset, offset)
3384 self.assertEqual(err.exception.decode_path, decode_path)
3387 integers(min_value=128),
3388 integers(min_value=0),
3391 def test_bad_len(self, l, offset, decode_path):
3392 with self.assertRaises(DecodeError) as err:
3393 self.base_klass().decode(
3394 self.base_klass.tag_default + len_encode(l)[:-1],
3396 decode_path=decode_path,
3399 self.assertEqual(err.exception.offset, offset)
3400 self.assertEqual(err.exception.decode_path, decode_path)
3403 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3404 integers(min_value=0),
3407 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3408 value, bound_min = list(sorted(ints))
3410 class String(self.base_klass):
3411 # Multiply this value by four, to satisfy UTF-32 bounds
3412 # (4 bytes per character) validation
3413 bounds = (bound_min * 4, bound_min * 4)
3414 with self.assertRaises(DecodeError) as err:
3416 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3418 decode_path=decode_path,
3421 self.assertEqual(err.exception.offset, offset)
3422 self.assertEqual(err.exception.decode_path, decode_path)
3424 @given(data_strategy())
3425 def test_symmetric(self, d):
3426 values = d.draw(string_values_strategy(self.text_alphabet()))
3427 value = d.draw(text(alphabet=self.text_alphabet()))
3428 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3429 offset = d.draw(integers(min_value=0))
3430 tail_junk = d.draw(binary(max_size=5))
3431 _, _, _, _, default, optional, _decoded = values
3432 obj = self.base_klass(
3440 pprint(obj, big_blobs=True, with_decode_path=True)
3441 self.assertFalse(obj.expled)
3442 obj_encoded = obj.encode()
3443 obj_expled = obj(value, expl=tag_expl)
3444 self.assertTrue(obj_expled.expled)
3446 list(obj_expled.pps())
3447 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3448 obj_expled_encoded = obj_expled.encode()
3449 ctx_copied = deepcopy(ctx_dummy)
3450 obj_decoded, tail = obj_expled.decode(
3451 obj_expled_encoded + tail_junk,
3455 self.assertDictEqual(ctx_copied, ctx_dummy)
3457 list(obj_decoded.pps())
3458 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3459 self.assertEqual(tail, tail_junk)
3460 self.assertEqual(obj_decoded, obj_expled)
3461 self.assertNotEqual(obj_decoded, obj)
3462 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3463 self.assertEqual(bytes(obj_decoded), bytes(obj))
3464 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3465 self.assertEqual(text_type(obj_decoded), text_type(obj))
3466 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3467 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3468 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3470 obj_decoded.expl_llen,
3471 len(len_encode(len(obj_encoded))),
3473 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3474 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3477 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3479 self.assertEqual(obj_decoded.expl_offset, offset)
3480 assert_exceeding_data(
3482 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3487 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3488 base_klass = UTF8String
3491 cyrillic_letters = text(
3492 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3498 class UnicodeDecodeErrorMixin(object):
3499 @given(cyrillic_letters)
3500 def test_unicode_decode_error(self, cyrillic_text):
3501 with self.assertRaises(DecodeError):
3502 self.base_klass(cyrillic_text)
3505 class TestNumericString(StringMixin, CommonMixin, TestCase):
3506 base_klass = NumericString
3508 def text_alphabet(self):
3511 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3512 def test_non_numeric(self, non_numeric_text):
3513 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3514 self.base_klass(non_numeric_text)
3517 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3518 integers(min_value=0),
3521 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3522 value, bound_min = list(sorted(ints))
3524 class String(self.base_klass):
3525 bounds = (bound_min, bound_min)
3526 with self.assertRaises(DecodeError) as err:
3528 self.base_klass(b"1" * value).encode(),
3530 decode_path=decode_path,
3533 self.assertEqual(err.exception.offset, offset)
3534 self.assertEqual(err.exception.decode_path, decode_path)
3537 class TestPrintableString(
3538 UnicodeDecodeErrorMixin,
3543 base_klass = PrintableString
3545 def text_alphabet(self):
3546 return ascii_letters + digits + " '()+,-./:=?"
3548 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3549 def test_non_printable(self, non_printable_text):
3550 with assertRaisesRegex(self, DecodeError, "non-printable"):
3551 self.base_klass(non_printable_text)
3554 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3555 integers(min_value=0),
3558 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3559 value, bound_min = list(sorted(ints))
3561 class String(self.base_klass):
3562 bounds = (bound_min, bound_min)
3563 with self.assertRaises(DecodeError) as err:
3565 self.base_klass(b"1" * value).encode(),
3567 decode_path=decode_path,
3570 self.assertEqual(err.exception.offset, offset)
3571 self.assertEqual(err.exception.decode_path, decode_path)
3573 def test_allowable_invalid_chars(self):
3575 ("*", {"allow_asterisk": True}),
3576 ("&", {"allow_ampersand": True}),
3577 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3580 obj = self.base_klass(s)
3581 for prop in kwargs.keys():
3582 self.assertFalse(getattr(obj, prop))
3584 with assertRaisesRegex(self, DecodeError, "non-printable"):
3586 self.base_klass(s, **kwargs)
3587 klass = self.base_klass(**kwargs)
3589 for prop in kwargs.keys():
3590 self.assertTrue(getattr(obj, prop))
3593 for prop in kwargs.keys():
3594 self.assertTrue(getattr(obj, prop))
3597 class TestTeletexString(
3598 UnicodeDecodeErrorMixin,
3603 base_klass = TeletexString
3606 class TestVideotexString(
3607 UnicodeDecodeErrorMixin,
3612 base_klass = VideotexString
3615 class TestIA5String(
3616 UnicodeDecodeErrorMixin,
3621 base_klass = IA5String
3624 class TestGraphicString(
3625 UnicodeDecodeErrorMixin,
3630 base_klass = GraphicString
3633 class TestVisibleString(
3634 UnicodeDecodeErrorMixin,
3639 base_klass = VisibleString
3641 def test_x690_vector(self):
3642 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3643 self.assertSequenceEqual(tail, b"")
3644 self.assertEqual(str(obj), "Jones")
3645 self.assertFalse(obj.ber_encoded)
3646 self.assertFalse(obj.lenindef)
3647 self.assertFalse(obj.bered)
3649 obj, tail = VisibleString().decode(
3650 hexdec("3A0904034A6F6E04026573"),
3651 ctx={"bered": True},
3653 self.assertSequenceEqual(tail, b"")
3654 self.assertEqual(str(obj), "Jones")
3655 self.assertTrue(obj.ber_encoded)
3656 self.assertFalse(obj.lenindef)
3657 self.assertTrue(obj.bered)
3659 self.assertTrue(obj.ber_encoded)
3660 self.assertFalse(obj.lenindef)
3661 self.assertTrue(obj.bered)
3663 obj, tail = VisibleString().decode(
3664 hexdec("3A8004034A6F6E040265730000"),
3665 ctx={"bered": True},
3667 self.assertSequenceEqual(tail, b"")
3668 self.assertEqual(str(obj), "Jones")
3669 self.assertTrue(obj.ber_encoded)
3670 self.assertTrue(obj.lenindef)
3671 self.assertTrue(obj.bered)
3673 self.assertTrue(obj.ber_encoded)
3674 self.assertTrue(obj.lenindef)
3675 self.assertTrue(obj.bered)
3678 class TestGeneralString(
3679 UnicodeDecodeErrorMixin,
3684 base_klass = GeneralString
3687 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3688 base_klass = UniversalString
3691 class TestBMPString(StringMixin, CommonMixin, TestCase):
3692 base_klass = BMPString
3696 def generalized_time_values_strategy(
3704 if draw(booleans()):
3705 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3707 value = value.replace(microsecond=0)
3709 if draw(booleans()):
3710 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3712 default = default.replace(microsecond=0)
3716 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3718 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3719 optional = draw(one_of(none(), booleans()))
3721 draw(integers(min_value=0)),
3722 draw(integers(min_value=0)),
3723 draw(integers(min_value=0)),
3725 return (value, impl, expl, default, optional, _decoded)
3728 class TimeMixin(object):
3729 def test_invalid_value_type(self):
3730 with self.assertRaises(InvalidValueType) as err:
3731 self.base_klass(datetime.now().timetuple())
3734 @given(data_strategy())
3735 def test_optional(self, d):
3736 default = d.draw(datetimes(
3737 min_value=self.min_datetime,
3738 max_value=self.max_datetime,
3740 optional = d.draw(booleans())
3741 obj = self.base_klass(default=default, optional=optional)
3742 self.assertTrue(obj.optional)
3744 @given(data_strategy())
3745 def test_ready(self, d):
3746 obj = self.base_klass()
3747 self.assertFalse(obj.ready)
3750 pprint(obj, big_blobs=True, with_decode_path=True)
3751 with self.assertRaises(ObjNotReady) as err:
3754 value = d.draw(datetimes(
3755 min_value=self.min_datetime,
3756 max_value=self.max_datetime,
3758 obj = self.base_klass(value)
3759 self.assertTrue(obj.ready)
3762 pprint(obj, big_blobs=True, with_decode_path=True)
3764 @given(data_strategy())
3765 def test_comparison(self, d):
3766 value1 = d.draw(datetimes(
3767 min_value=self.min_datetime,
3768 max_value=self.max_datetime,
3770 value2 = d.draw(datetimes(
3771 min_value=self.min_datetime,
3772 max_value=self.max_datetime,
3774 tag1 = d.draw(binary(min_size=1))
3775 tag2 = d.draw(binary(min_size=1))
3777 value1 = value1.replace(microsecond=0)
3778 value2 = value2.replace(microsecond=0)
3779 obj1 = self.base_klass(value1)
3780 obj2 = self.base_klass(value2)
3781 self.assertEqual(obj1 == obj2, value1 == value2)
3782 self.assertEqual(obj1 != obj2, value1 != value2)
3783 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3784 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3785 obj1 = self.base_klass(value1, impl=tag1)
3786 obj2 = self.base_klass(value1, impl=tag2)
3787 self.assertEqual(obj1 == obj2, tag1 == tag2)
3788 self.assertEqual(obj1 != obj2, tag1 != tag2)
3790 @given(data_strategy())
3791 def test_call(self, d):
3799 ) = d.draw(generalized_time_values_strategy(
3800 min_datetime=self.min_datetime,
3801 max_datetime=self.max_datetime,
3802 omit_ms=self.omit_ms,
3804 obj_initial = self.base_klass(
3805 value=value_initial,
3808 default=default_initial,
3809 optional=optional_initial or False,
3810 _decoded=_decoded_initial,
3819 ) = d.draw(generalized_time_values_strategy(
3820 min_datetime=self.min_datetime,
3821 max_datetime=self.max_datetime,
3822 omit_ms=self.omit_ms,
3823 do_expl=impl_initial is None,
3833 value_expected = default if value is None else value
3835 default_initial if value_expected is None
3838 self.assertEqual(obj, value_expected)
3839 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3840 self.assertEqual(obj.expl_tag, expl or expl_initial)
3843 default_initial if default is None else default,
3845 if obj.default is None:
3846 optional = optional_initial if optional is None else optional
3847 optional = False if optional is None else optional
3850 self.assertEqual(obj.optional, optional)
3852 @given(data_strategy())
3853 def test_copy(self, d):
3854 values = d.draw(generalized_time_values_strategy(
3855 min_datetime=self.min_datetime,
3856 max_datetime=self.max_datetime,
3858 obj = self.base_klass(*values)
3859 for copy_func in copy_funcs:
3860 obj_copied = copy_func(obj)
3861 self.assert_copied_basic_fields(obj, obj_copied)
3862 self.assertEqual(obj._value, obj_copied._value)
3864 @given(data_strategy())
3865 def test_stripped(self, d):
3866 value = d.draw(datetimes(
3867 min_value=self.min_datetime,
3868 max_value=self.max_datetime,
3870 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3871 obj = self.base_klass(value, impl=tag_impl)
3872 with self.assertRaises(NotEnoughData):
3873 obj.decode(obj.encode()[:-1])
3875 @given(data_strategy())
3876 def test_stripped_expl(self, d):
3877 value = d.draw(datetimes(
3878 min_value=self.min_datetime,
3879 max_value=self.max_datetime,
3881 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3882 obj = self.base_klass(value, expl=tag_expl)
3883 with self.assertRaises(NotEnoughData):
3884 obj.decode(obj.encode()[:-1])
3886 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3887 @given(data_strategy())
3888 def test_symmetric(self, d):
3889 values = d.draw(generalized_time_values_strategy(
3890 min_datetime=self.min_datetime,
3891 max_datetime=self.max_datetime,
3893 value = d.draw(datetimes(
3894 min_value=self.min_datetime,
3895 max_value=self.max_datetime,
3897 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3898 offset = d.draw(integers(min_value=0))
3899 tail_junk = d.draw(binary(max_size=5))
3900 _, _, _, default, optional, _decoded = values
3901 obj = self.base_klass(
3909 pprint(obj, big_blobs=True, with_decode_path=True)
3910 self.assertFalse(obj.expled)
3911 obj_encoded = obj.encode()
3912 self.additional_symmetric_check(value, obj_encoded)
3913 obj_expled = obj(value, expl=tag_expl)
3914 self.assertTrue(obj_expled.expled)
3916 list(obj_expled.pps())
3917 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3918 obj_expled_encoded = obj_expled.encode()
3919 ctx_copied = deepcopy(ctx_dummy)
3920 obj_decoded, tail = obj_expled.decode(
3921 obj_expled_encoded + tail_junk,
3925 self.assertDictEqual(ctx_copied, ctx_dummy)
3927 list(obj_decoded.pps())
3928 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3929 self.assertEqual(tail, tail_junk)
3930 self.assertEqual(obj_decoded, obj_expled)
3931 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3932 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3933 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3934 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3935 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3937 obj_decoded.expl_llen,
3938 len(len_encode(len(obj_encoded))),
3940 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3941 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3944 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3946 self.assertEqual(obj_decoded.expl_offset, offset)
3947 assert_exceeding_data(
3949 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3954 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3955 base_klass = GeneralizedTime
3957 min_datetime = datetime(1900, 1, 1)
3958 max_datetime = datetime(9999, 12, 31)
3960 def additional_symmetric_check(self, value, obj_encoded):
3961 if value.microsecond > 0:
3962 self.assertFalse(obj_encoded.endswith(b"0Z"))
3964 def test_repr_not_ready(self):
3965 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
3966 repr(GeneralizedTime())
3968 def test_x690_vector_valid(self):
3972 b"19920722132100.3Z",
3974 GeneralizedTime(data)
3976 def test_x690_vector_invalid(self):
3979 b"19920622123421.0Z",
3980 b"19920722132100.30Z",
3982 with self.assertRaises(DecodeError) as err:
3983 GeneralizedTime(data)
3986 def test_go_vectors_invalid(self):
3998 b"-20100102030410Z",
3999 b"2010-0102030410Z",
4000 b"2010-0002030410Z",
4001 b"201001-02030410Z",
4002 b"20100102-030410Z",
4003 b"2010010203-0410Z",
4004 b"201001020304-10Z",
4005 # These ones are INVALID in *DER*, but accepted
4006 # by Go's encoding/asn1
4007 b"20100102030405+0607",
4008 b"20100102030405-0607",
4010 with self.assertRaises(DecodeError) as err:
4011 GeneralizedTime(data)
4014 def test_go_vectors_valid(self):
4016 GeneralizedTime(b"20100102030405Z").todatetime(),
4017 datetime(2010, 1, 2, 3, 4, 5, 0),
4020 def test_go_vectors_valid_ber(self):
4022 b"20100102030405+0607",
4023 b"20100102030405-0607",
4025 GeneralizedTime(data, ctx={"bered": True})
4027 def test_utc_offsets(self):
4028 """Some know equal UTC offsets
4031 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4035 "200101011130-0700",
4036 "200101011500-03:30",
4039 self.assertEqual(dts[0], dts[1])
4040 self.assertEqual(dts[0], dts[2])
4041 self.assertEqual(dts[0], dts[3])
4043 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4044 @given(data_strategy())
4045 def test_valid_ber(self, d):
4046 min_year = 1901 if PY2 else 2
4047 year = d.draw(integers(min_value=min_year, max_value=9999))
4048 month = d.draw(integers(min_value=1, max_value=12))
4049 day = d.draw(integers(min_value=1, max_value=28))
4050 hours = d.draw(integers(min_value=0, max_value=23))
4051 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4052 dt = datetime(year, month, day, hours)
4053 fractions_sign = d.draw(sampled_from(" ,."))
4055 if fractions_sign != " ":
4056 fractions = random()
4057 if d.draw(booleans()):
4058 minutes = d.draw(integers(min_value=0, max_value=59))
4059 data += "%02d" % minutes
4060 dt += timedelta(seconds=60 * minutes)
4061 if d.draw(booleans()):
4062 seconds = d.draw(integers(min_value=0, max_value=59))
4063 data += "%02d" % seconds
4064 dt += timedelta(seconds=seconds)
4065 if fractions is not None:
4066 dt += timedelta(microseconds=10**6 * fractions)
4067 elif fractions is not None:
4068 dt += timedelta(seconds=60 * fractions)
4069 elif fractions is not None:
4070 dt += timedelta(seconds=3600 * fractions)
4071 if fractions is not None:
4072 data += fractions_sign + str(fractions)[2:]
4073 if d.draw(booleans()):
4075 elif d.draw(booleans()):
4076 offset_hour = d.draw(integers(min_value=0, max_value=13))
4078 if d.draw(booleans()):
4083 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4084 data += "%02d" % offset_hour
4085 minutes_separator = d.draw(sampled_from((None, "", ":")))
4086 if minutes_separator is not None:
4087 offset_minute = d.draw(integers(min_value=0, max_value=59))
4088 dt -= timedelta(seconds=sign * 60 * offset_minute)
4089 data += "%s%02d" % (minutes_separator, offset_minute)
4090 data = data.encode("ascii")
4091 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4093 GeneralizedTime().decod(data_der)
4098 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4101 mktime(obj.todatetime().timetuple()),
4102 mktime(dt.timetuple()),
4105 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4106 self.assertEqual(obj.ber_encoded, not dered)
4107 self.assertEqual(obj.bered, not dered)
4108 self.assertEqual(obj.ber_raw, None if dered else data)
4109 self.assertEqual(obj.encode() == data_der, dered)
4114 def test_invalid_ber(self):
4116 # "00010203040506.07",
4117 "-0010203040506.07",
4118 "0001-203040506.07",
4119 "000102-3040506.07",
4120 "00010203-40506.07",
4121 "0001020304-506.07",
4122 "000102030405-6.07",
4123 "00010203040506.-7",
4124 "+0010203040506.07",
4125 "0001+203040506.07",
4126 "000102+3040506.07",
4127 "00010203+40506.07",
4128 "0001020304+506.07",
4129 "000102030405+6.07",
4130 "00010203040506.+7",
4131 " 0010203040506.07",
4132 "0001 203040506.07",
4133 "000102 3040506.07",
4134 "00010203 40506.07",
4135 "0001020304 506.07",
4136 "000102030405 6.07",
4137 "00010203040506. 7",
4138 "001 0203040506.07",
4139 "00012 03040506.07",
4140 "0001023 040506.07",
4141 "000102034 0506.07",
4142 "00010203045 06.07",
4143 "0001020304056 .07",
4144 "00010203040506.7 ",
4224 "00010203040506.07+15",
4225 "00010203040506.07-15",
4226 "00010203040506.07+14:60",
4227 "00010203040506.07+1460",
4228 "00010203040506.07-1460",
4229 "00010203040506.07+00:60",
4230 "00010203040506.07-00:60",
4232 "00010203040506+15",
4233 "00010203040506-15",
4234 "00010203040506+14:60",
4235 "00010203040506+1460",
4236 "00010203040506-1460",
4237 "00010203040506+00:60",
4238 "00010203040506-00:60",
4247 with self.assertRaises(DecodeError):
4248 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4249 data = data.replace(".", ",")
4250 with self.assertRaises(DecodeError):
4251 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4255 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4256 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4258 binary(min_size=1, max_size=1),
4260 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4261 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4264 def test_junk(self, part0, part1, part2):
4265 junk = part0 + part1 + part2
4266 assume(not (set(junk) <= set(digits.encode("ascii"))))
4267 with self.assertRaises(DecodeError):
4268 GeneralizedTime().decode(
4269 GeneralizedTime.tag_default +
4270 len_encode(len(junk)) +
4276 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4277 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4279 binary(min_size=1, max_size=1),
4281 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4282 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4285 def test_junk_dm(self, part0, part1, part2):
4286 junk = part0 + part1 + part2
4287 assume(not (set(junk) <= set(digits.encode("ascii"))))
4288 with self.assertRaises(DecodeError):
4289 GeneralizedTime().decode(
4290 GeneralizedTime.tag_default +
4291 len_encode(len(junk)) +
4295 def test_ns_fractions(self):
4296 GeneralizedTime(b"20010101000000.000001Z")
4297 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
4298 GeneralizedTime(b"20010101000000.0000001Z")
4300 def test_non_pure_integers(self):
4302 # b"20000102030405Z,
4309 b"20000102030405.+6Z",
4310 b"20000102030405.-6Z",
4317 b"20000102030405._6Z",
4318 b"20000102030405.6_Z",
4325 b"20000102030405. 6Z",
4332 b"20000102030405.6 Z",
4334 with self.assertRaises(DecodeError):
4335 GeneralizedTime(data)
4338 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4339 base_klass = UTCTime
4341 min_datetime = datetime(2000, 1, 1)
4342 max_datetime = datetime(2049, 12, 31)
4344 def additional_symmetric_check(self, value, obj_encoded):
4347 def test_repr_not_ready(self):
4348 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
4351 def test_x690_vector_valid(self):
4359 def test_x690_vector_invalid(self):
4364 with self.assertRaises(DecodeError) as err:
4368 def test_go_vectors_invalid(self):
4394 # These ones are INVALID in *DER*, but accepted
4395 # by Go's encoding/asn1
4396 b"910506164540-0700",
4397 b"910506164540+0730",
4401 with self.assertRaises(DecodeError) as err:
4405 def test_go_vectors_valid(self):
4407 UTCTime(b"910506234540Z").todatetime(),
4408 datetime(1991, 5, 6, 23, 45, 40, 0),
4411 def test_non_pure_integers(self):
4440 with self.assertRaises(DecodeError):
4443 def test_x680_vector_valid_ber(self):
4445 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4446 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4447 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4448 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4450 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4451 obj = UTCTime().decod(data_der, ctx={"bered": True})
4452 self.assertEqual(obj, dt)
4453 self.assertEqual(obj.todatetime(), dt)
4454 self.assertTrue(obj.ber_encoded)
4455 self.assertTrue(obj.bered)
4456 self.assertEqual(obj.ber_raw, data)
4457 self.assertNotEqual(obj.encode(), data_der)
4460 def test_go_vectors_valid_ber(self):
4462 b"910506164540-0700",
4463 b"910506164540+0730",
4467 data = UTCTime.tag_default + len_encode(len(data)) + data
4468 obj = UTCTime().decod(data, ctx={"bered": True})
4469 self.assertTrue(obj.ber_encoded)
4470 self.assertTrue(obj.bered)
4471 self.assertNotEqual(obj.encode(), data)
4474 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4475 @given(data_strategy())
4476 def test_valid_ber(self, d):
4477 year = d.draw(integers(min_value=0, max_value=99))
4478 month = d.draw(integers(min_value=1, max_value=12))
4479 day = d.draw(integers(min_value=1, max_value=28))
4480 hours = d.draw(integers(min_value=0, max_value=23))
4481 minute = d.draw(integers(min_value=0, max_value=59))
4482 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4484 year + (2000 if year < 50 else 1900),
4491 if d.draw(booleans()):
4493 seconds = d.draw(integers(min_value=0, max_value=59))
4494 data += "%02d" % seconds
4495 dt += timedelta(seconds=seconds)
4496 if d.draw(booleans()):
4500 offset_hour = d.draw(integers(min_value=0, max_value=13))
4501 offset_minute = d.draw(integers(min_value=0, max_value=59))
4502 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4503 if d.draw(booleans()):
4509 data += "%02d%02d" % (offset_hour, offset_minute)
4510 data = data.encode("ascii")
4511 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4512 obj = UTCTime().decod(data_der, ctx={"bered": True})
4513 self.assertEqual(obj, dt)
4514 self.assertEqual(obj.todatetime(), dt)
4515 self.assertEqual(obj.ber_encoded, not dered)
4516 self.assertEqual(obj.bered, not dered)
4517 self.assertEqual(obj.ber_raw, None if dered else data)
4518 self.assertEqual(obj.encode() == data_der, dered)
4523 def test_invalid_ber(self):
4564 b"0001020304+0000Z",
4573 with self.assertRaises(DecodeError):
4574 UTCTime(data, ctx={"bered": True})
4575 data = data[:8] + data[8+2:]
4576 with self.assertRaises(DecodeError):
4577 UTCTime(data, ctx={"bered": True})
4622 b"000102030405+000",
4623 b"000102030405+000Z",
4624 b"000102030405+0000Z",
4625 b"000102030405+-101",
4626 b"000102030405+01-1",
4627 b"000102030405+0060",
4628 b"000102030405+1401",
4629 b"500101000002+0003",
4631 with self.assertRaises(DecodeError):
4632 UTCTime(data, ctx={"bered": True})
4634 @given(integers(min_value=0, max_value=49))
4635 def test_pre50(self, year):
4637 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4641 @given(integers(min_value=50, max_value=99))
4642 def test_post50(self, year):
4644 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4650 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4651 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4653 binary(min_size=1, max_size=1),
4655 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4656 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4659 def test_junk(self, part0, part1, part2):
4660 junk = part0 + part1 + part2
4661 assume(not (set(junk) <= set(digits.encode("ascii"))))
4662 with self.assertRaises(DecodeError):
4664 UTCTime.tag_default +
4665 len_encode(len(junk)) +
4671 def any_values_strategy(draw, do_expl=False):
4672 value = draw(one_of(none(), binary()))
4675 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4676 optional = draw(one_of(none(), booleans()))
4678 draw(integers(min_value=0)),
4679 draw(integers(min_value=0)),
4680 draw(integers(min_value=0)),
4682 return (value, expl, optional, _decoded)
4685 class AnyInherited(Any):
4689 class TestAny(CommonMixin, TestCase):
4692 def test_invalid_value_type(self):
4693 with self.assertRaises(InvalidValueType) as err:
4698 def test_optional(self, optional):
4699 obj = Any(optional=optional)
4700 self.assertEqual(obj.optional, optional)
4703 def test_ready(self, value):
4705 self.assertFalse(obj.ready)
4708 pprint(obj, big_blobs=True, with_decode_path=True)
4709 with self.assertRaises(ObjNotReady) as err:
4713 self.assertTrue(obj.ready)
4716 pprint(obj, big_blobs=True, with_decode_path=True)
4719 def test_basic(self, value):
4720 integer_encoded = Integer(value).encode()
4722 Any(integer_encoded),
4723 Any(Integer(value)),
4724 Any(Any(Integer(value))),
4726 self.assertSequenceEqual(bytes(obj), integer_encoded)
4728 obj.decode(obj.encode())[0].vlen,
4729 len(integer_encoded),
4733 pprint(obj, big_blobs=True, with_decode_path=True)
4734 self.assertSequenceEqual(obj.encode(), integer_encoded)
4736 @given(binary(min_size=1), binary(min_size=1))
4737 def test_comparison(self, value1, value2):
4738 for klass in (Any, AnyInherited):
4739 obj1 = klass(value1)
4740 obj2 = klass(value2)
4741 self.assertEqual(obj1 == obj2, value1 == value2)
4742 self.assertEqual(obj1 != obj2, value1 != value2)
4743 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4745 @given(data_strategy())
4746 def test_call(self, d):
4747 for klass in (Any, AnyInherited):
4753 ) = d.draw(any_values_strategy())
4754 obj_initial = klass(
4757 optional_initial or False,
4765 ) = d.draw(any_values_strategy(do_expl=True))
4766 obj = obj_initial(value, expl, optional)
4768 value_expected = None if value is None else value
4769 self.assertEqual(obj, value_expected)
4770 self.assertEqual(obj.expl_tag, expl or expl_initial)
4771 if obj.default is None:
4772 optional = optional_initial if optional is None else optional
4773 optional = False if optional is None else optional
4774 self.assertEqual(obj.optional, optional)
4776 def test_simultaneous_impl_expl(self):
4777 # override it, as Any does not have implicit tag
4780 def test_decoded(self):
4781 # override it, as Any does not have implicit tag
4784 @given(any_values_strategy())
4785 def test_copy(self, values):
4786 for klass in (Any, AnyInherited):
4787 obj = klass(*values)
4788 for copy_func in copy_funcs:
4789 obj_copied = copy_func(obj)
4790 self.assert_copied_basic_fields(obj, obj_copied)
4791 self.assertEqual(obj._value, obj_copied._value)
4793 @given(binary().map(OctetString))
4794 def test_stripped(self, value):
4796 with self.assertRaises(NotEnoughData):
4797 obj.decode(obj.encode()[:-1])
4801 integers(min_value=1).map(tag_ctxc),
4803 def test_stripped_expl(self, value, tag_expl):
4804 obj = Any(value, expl=tag_expl)
4805 with self.assertRaises(NotEnoughData):
4806 obj.decode(obj.encode()[:-1])
4809 integers(min_value=31),
4810 integers(min_value=0),
4813 def test_bad_tag(self, tag, offset, decode_path):
4814 with self.assertRaises(DecodeError) as err:
4816 tag_encode(tag)[:-1],
4818 decode_path=decode_path,
4821 self.assertEqual(err.exception.offset, offset)
4822 self.assertEqual(err.exception.decode_path, decode_path)
4825 integers(min_value=128),
4826 integers(min_value=0),
4829 def test_bad_len(self, l, offset, decode_path):
4830 with self.assertRaises(DecodeError) as err:
4832 Any.tag_default + len_encode(l)[:-1],
4834 decode_path=decode_path,
4837 self.assertEqual(err.exception.offset, offset)
4838 self.assertEqual(err.exception.decode_path, decode_path)
4840 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4842 any_values_strategy(),
4843 integers().map(lambda x: Integer(x).encode()),
4844 integers(min_value=1).map(tag_ctxc),
4845 integers(min_value=0),
4848 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4849 for klass in (Any, AnyInherited):
4850 _, _, optional, _decoded = values
4851 obj = klass(value=value, optional=optional, _decoded=_decoded)
4854 pprint(obj, big_blobs=True, with_decode_path=True)
4855 self.assertFalse(obj.expled)
4856 obj_encoded = obj.encode()
4857 obj_expled = obj(value, expl=tag_expl)
4858 self.assertTrue(obj_expled.expled)
4860 list(obj_expled.pps())
4861 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4862 obj_expled_encoded = obj_expled.encode()
4863 ctx_copied = deepcopy(ctx_dummy)
4864 obj_decoded, tail = obj_expled.decode(
4865 obj_expled_encoded + tail_junk,
4869 self.assertDictEqual(ctx_copied, ctx_dummy)
4871 list(obj_decoded.pps())
4872 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4873 self.assertEqual(tail, tail_junk)
4874 self.assertEqual(obj_decoded, obj_expled)
4875 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4876 self.assertEqual(bytes(obj_decoded), bytes(obj))
4877 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4878 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4879 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4881 obj_decoded.expl_llen,
4882 len(len_encode(len(obj_encoded))),
4884 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4885 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4888 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4890 self.assertEqual(obj_decoded.expl_offset, offset)
4891 self.assertEqual(obj_decoded.tlen, 0)
4892 self.assertEqual(obj_decoded.llen, 0)
4893 self.assertEqual(obj_decoded.vlen, len(value))
4894 assert_exceeding_data(
4896 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4901 integers(min_value=1).map(tag_ctxc),
4902 integers(min_value=0, max_value=3),
4903 integers(min_value=0),
4907 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4908 chunk = Boolean(False, expl=expl).encode()
4910 OctetString.tag_default +
4912 b"".join([chunk] * chunks) +
4915 with self.assertRaises(LenIndefForm):
4919 decode_path=decode_path,
4921 obj, tail = Any().decode(
4924 decode_path=decode_path,
4925 ctx={"bered": True},
4927 self.assertSequenceEqual(tail, junk)
4928 self.assertEqual(obj.offset, offset)
4929 self.assertEqual(obj.tlvlen, len(encoded))
4930 self.assertTrue(obj.lenindef)
4931 self.assertFalse(obj.ber_encoded)
4932 self.assertTrue(obj.bered)
4934 self.assertTrue(obj.lenindef)
4935 self.assertFalse(obj.ber_encoded)
4936 self.assertTrue(obj.bered)
4939 pprint(obj, big_blobs=True, with_decode_path=True)
4940 with self.assertRaises(NotEnoughData) as err:
4944 decode_path=decode_path,
4945 ctx={"bered": True},
4947 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4948 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4950 class SeqOf(SequenceOf):
4951 schema = Boolean(expl=expl)
4953 class Seq(Sequence):
4955 ("type", ObjectIdentifier(defines=((("value",), {
4956 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4961 ("type", ObjectIdentifier("1.2.3")),
4962 ("value", Any(encoded)),
4964 seq_encoded = seq.encode()
4965 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4966 self.assertIsNotNone(seq_decoded["value"].defined)
4968 list(seq_decoded.pps())
4969 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4970 self.assertTrue(seq_decoded.bered)
4971 self.assertFalse(seq_decoded["type"].bered)
4972 self.assertTrue(seq_decoded["value"].bered)
4974 chunk = chunk[:-1] + b"\x01"
4975 chunks = b"".join([chunk] * (chunks + 1))
4976 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4978 ("type", ObjectIdentifier("1.2.3")),
4979 ("value", Any(encoded)),
4981 seq_encoded = seq.encode()
4982 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4983 self.assertIsNotNone(seq_decoded["value"].defined)
4985 list(seq_decoded.pps())
4986 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4987 self.assertTrue(seq_decoded.bered)
4988 self.assertFalse(seq_decoded["type"].bered)
4989 self.assertTrue(seq_decoded["value"].bered)
4993 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4995 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4996 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4998 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4999 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
5001 min_size=len(names),
5002 max_size=len(names),
5005 (name, Integer(**tag_kwargs))
5006 for name, tag_kwargs in zip(names, tags)
5009 if value_required or draw(booleans()):
5010 value = draw(tuples(
5011 sampled_from([name for name, _ in schema]),
5012 integers().map(Integer),
5016 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5017 default = draw(one_of(
5019 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5021 optional = draw(one_of(none(), booleans()))
5023 draw(integers(min_value=0)),
5024 draw(integers(min_value=0)),
5025 draw(integers(min_value=0)),
5027 return (schema, value, expl, default, optional, _decoded)
5030 class ChoiceInherited(Choice):
5034 class TestChoice(CommonMixin, TestCase):
5036 schema = (("whatever", Boolean()),)
5039 def test_schema_required(self):
5040 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5043 def test_impl_forbidden(self):
5044 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
5045 Choice(impl=b"whatever")
5047 def test_invalid_value_type(self):
5048 with self.assertRaises(InvalidValueType) as err:
5049 self.base_klass(123)
5051 with self.assertRaises(ObjUnknown) as err:
5052 self.base_klass(("whenever", Boolean(False)))
5054 with self.assertRaises(InvalidValueType) as err:
5055 self.base_klass(("whatever", Integer(123)))
5059 def test_optional(self, optional):
5060 obj = self.base_klass(
5061 default=self.base_klass(("whatever", Boolean(False))),
5064 self.assertTrue(obj.optional)
5067 def test_ready(self, value):
5068 obj = self.base_klass()
5069 self.assertFalse(obj.ready)
5072 pprint(obj, big_blobs=True, with_decode_path=True)
5073 self.assertIsNone(obj["whatever"])
5074 with self.assertRaises(ObjNotReady) as err:
5077 obj["whatever"] = Boolean()
5078 self.assertFalse(obj.ready)
5081 pprint(obj, big_blobs=True, with_decode_path=True)
5082 obj["whatever"] = Boolean(value)
5083 self.assertTrue(obj.ready)
5086 pprint(obj, big_blobs=True, with_decode_path=True)
5088 @given(booleans(), booleans())
5089 def test_comparison(self, value1, value2):
5090 class WahlInherited(self.base_klass):
5092 for klass in (self.base_klass, WahlInherited):
5093 obj1 = klass(("whatever", Boolean(value1)))
5094 obj2 = klass(("whatever", Boolean(value2)))
5095 self.assertEqual(obj1 == obj2, value1 == value2)
5096 self.assertEqual(obj1 != obj2, value1 != value2)
5097 self.assertEqual(obj1 == obj2._value, value1 == value2)
5098 self.assertFalse(obj1 == obj2._value[1])
5100 @given(data_strategy())
5101 def test_call(self, d):
5102 for klass in (Choice, ChoiceInherited):
5110 ) = d.draw(choice_values_strategy())
5113 schema = schema_initial
5115 value=value_initial,
5117 default=default_initial,
5118 optional=optional_initial or False,
5119 _decoded=_decoded_initial,
5128 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5129 obj = obj_initial(value, expl, default, optional)
5131 value_expected = default if value is None else value
5133 default_initial if value_expected is None
5136 self.assertEqual(obj.choice, value_expected[0])
5137 self.assertEqual(obj.value, int(value_expected[1]))
5138 self.assertEqual(obj.expl_tag, expl or expl_initial)
5139 default_expect = default_initial if default is None else default
5140 if default_expect is not None:
5141 self.assertEqual(obj.default.choice, default_expect[0])
5142 self.assertEqual(obj.default.value, int(default_expect[1]))
5143 if obj.default is None:
5144 optional = optional_initial if optional is None else optional
5145 optional = False if optional is None else optional
5148 self.assertEqual(obj.optional, optional)
5149 self.assertEqual(obj.specs, obj_initial.specs)
5151 def test_simultaneous_impl_expl(self):
5152 # override it, as Any does not have implicit tag
5155 def test_decoded(self):
5156 # override it, as Any does not have implicit tag
5159 @given(choice_values_strategy())
5160 def test_copy(self, values):
5161 _schema, value, expl, default, optional, _decoded = values
5163 class Wahl(self.base_klass):
5165 register_class(Wahl)
5170 optional=optional or False,
5173 for copy_func in copy_funcs:
5174 obj_copied = copy_func(obj)
5175 self.assertIsNone(obj.tag)
5176 self.assertIsNone(obj_copied.tag)
5177 # hack for assert_copied_basic_fields
5178 obj.tag = "whatever"
5179 obj_copied.tag = "whatever"
5180 self.assert_copied_basic_fields(obj, obj_copied)
5182 self.assertEqual(obj._value, obj_copied._value)
5183 self.assertEqual(obj.specs, obj_copied.specs)
5186 def test_stripped(self, value):
5187 obj = self.base_klass(("whatever", Boolean(value)))
5188 with self.assertRaises(NotEnoughData):
5189 obj.decode(obj.encode()[:-1])
5193 integers(min_value=1).map(tag_ctxc),
5195 def test_stripped_expl(self, value, tag_expl):
5196 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5197 with self.assertRaises(NotEnoughData):
5198 obj.decode(obj.encode()[:-1])
5200 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5201 @given(data_strategy())
5202 def test_symmetric(self, d):
5203 _schema, value, _, default, optional, _decoded = d.draw(
5204 choice_values_strategy(value_required=True)
5206 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5207 offset = d.draw(integers(min_value=0))
5208 tail_junk = d.draw(binary(max_size=5))
5210 class Wahl(self.base_klass):
5220 pprint(obj, big_blobs=True, with_decode_path=True)
5221 self.assertFalse(obj.expled)
5222 obj_encoded = obj.encode()
5223 obj_expled = obj(value, expl=tag_expl)
5224 self.assertTrue(obj_expled.expled)
5226 list(obj_expled.pps())
5227 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5228 obj_expled_encoded = obj_expled.encode()
5229 ctx_copied = deepcopy(ctx_dummy)
5230 obj_decoded, tail = obj_expled.decode(
5231 obj_expled_encoded + tail_junk,
5235 self.assertDictEqual(ctx_copied, ctx_dummy)
5237 list(obj_decoded.pps())
5238 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5239 self.assertEqual(tail, tail_junk)
5240 self.assertEqual(obj_decoded, obj_expled)
5241 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5242 self.assertEqual(obj_decoded.value, obj_expled.value)
5243 self.assertEqual(obj_decoded.choice, obj.choice)
5244 self.assertEqual(obj_decoded.value, obj.value)
5245 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5246 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5247 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5249 obj_decoded.expl_llen,
5250 len(len_encode(len(obj_encoded))),
5252 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5253 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5256 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5258 self.assertEqual(obj_decoded.expl_offset, offset)
5259 self.assertSequenceEqual(
5261 obj_decoded.value.fulloffset - offset:
5262 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5266 assert_exceeding_data(
5268 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5273 def test_set_get(self, value):
5276 ("erste", Boolean()),
5277 ("zweite", Integer()),
5280 with self.assertRaises(ObjUnknown) as err:
5281 obj["whatever"] = "whenever"
5282 with self.assertRaises(InvalidValueType) as err:
5283 obj["zweite"] = Boolean(False)
5284 obj["zweite"] = Integer(value)
5286 with self.assertRaises(ObjUnknown) as err:
5289 self.assertIsNone(obj["erste"])
5290 self.assertEqual(obj["zweite"], Integer(value))
5292 def test_tag_mismatch(self):
5295 ("erste", Boolean()),
5297 int_encoded = Integer(123).encode()
5298 bool_encoded = Boolean(False).encode()
5300 obj.decode(bool_encoded)
5301 with self.assertRaises(TagMismatch):
5302 obj.decode(int_encoded)
5304 def test_tag_mismatch_underlying(self):
5305 class SeqOfBoolean(SequenceOf):
5308 class SeqOfInteger(SequenceOf):
5313 ("erste", SeqOfBoolean()),
5316 int_encoded = SeqOfInteger((Integer(123),)).encode()
5317 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5319 obj.decode(bool_encoded)
5320 with self.assertRaises(TagMismatch) as err:
5321 obj.decode(int_encoded)
5322 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5326 def seq_values_strategy(draw, seq_klass, do_expl=False):
5328 if draw(booleans()):
5330 value._value = draw(dictionaries(
5333 booleans().map(Boolean),
5334 integers().map(Integer),
5338 if draw(booleans()):
5339 schema = list(draw(dictionaries(
5342 booleans().map(Boolean),
5343 integers().map(Integer),
5349 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5351 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5353 if draw(booleans()):
5354 default = seq_klass()
5355 default._value = draw(dictionaries(
5358 booleans().map(Boolean),
5359 integers().map(Integer),
5362 optional = draw(one_of(none(), booleans()))
5364 draw(integers(min_value=0)),
5365 draw(integers(min_value=0)),
5366 draw(integers(min_value=0)),
5368 return (value, schema, impl, expl, default, optional, _decoded)
5372 def sequence_strategy(draw, seq_klass):
5373 inputs = draw(lists(
5375 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5376 tuples(just(Integer), integers(), one_of(none(), integers())),
5381 integers(min_value=1),
5382 min_size=len(inputs),
5383 max_size=len(inputs),
5386 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5387 for tag, expled in zip(tags, draw(lists(
5389 min_size=len(inputs),
5390 max_size=len(inputs),
5394 for i, optional in enumerate(draw(lists(
5395 sampled_from(("required", "optional", "empty")),
5396 min_size=len(inputs),
5397 max_size=len(inputs),
5399 if optional in ("optional", "empty"):
5400 inits[i]["optional"] = True
5401 if optional == "empty":
5403 empties = set(empties)
5404 names = list(draw(sets(
5406 min_size=len(inputs),
5407 max_size=len(inputs),
5410 for i, (klass, value, default) in enumerate(inputs):
5411 schema.append((names[i], klass(default=default, **inits[i])))
5412 seq_name = draw(text_letters())
5413 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5416 for i, (klass, value, default) in enumerate(inputs):
5423 "default_value": None if spec.default is None else default,
5427 expect["optional"] = True
5429 expect["presented"] = True
5430 expect["value"] = value
5432 expect["optional"] = True
5433 if default is not None and default == value:
5434 expect["presented"] = False
5435 seq[name] = klass(value)
5436 expects.append(expect)
5441 def sequences_strategy(draw, seq_klass):
5442 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5444 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5445 for tag, expled in zip(tags, draw(lists(
5452 i for i, is_default in enumerate(draw(lists(
5458 names = list(draw(sets(
5463 seq_expectses = draw(lists(
5464 sequence_strategy(seq_klass=seq_klass),
5468 seqs = [seq for seq, _ in seq_expectses]
5470 for i, (name, seq) in enumerate(zip(names, seqs)):
5473 seq(default=(seq if i in defaulted else None), **inits[i]),
5475 seq_name = draw(text_letters())
5476 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5479 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5482 "expects": expects_inner,
5485 seq_outer[name] = seq_inner
5486 if seq_outer.specs[name].default is None:
5487 expect["presented"] = True
5488 expect_outers.append(expect)
5489 return seq_outer, expect_outers
5492 class SeqMixing(object):
5493 def test_invalid_value_type(self):
5494 with self.assertRaises(InvalidValueType) as err:
5495 self.base_klass(123)
5498 def test_invalid_value_type_set(self):
5499 class Seq(self.base_klass):
5500 schema = (("whatever", Boolean()),)
5502 with self.assertRaises(InvalidValueType) as err:
5503 seq["whatever"] = Integer(123)
5507 def test_optional(self, optional):
5508 obj = self.base_klass(default=self.base_klass(), optional=optional)
5509 self.assertTrue(obj.optional)
5511 @given(data_strategy())
5512 def test_ready(self, d):
5514 str(i): v for i, v in enumerate(d.draw(lists(
5521 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5528 for name in d.draw(permutations(
5529 list(ready.keys()) + list(non_ready.keys()),
5531 schema_input.append((name, Boolean()))
5533 class Seq(self.base_klass):
5534 schema = tuple(schema_input)
5536 for name in ready.keys():
5538 seq[name] = Boolean()
5539 self.assertFalse(seq.ready)
5542 pprint(seq, big_blobs=True, with_decode_path=True)
5543 for name, value in ready.items():
5544 seq[name] = Boolean(value)
5545 self.assertFalse(seq.ready)
5548 pprint(seq, big_blobs=True, with_decode_path=True)
5549 with self.assertRaises(ObjNotReady) as err:
5552 for name, value in non_ready.items():
5553 seq[name] = Boolean(value)
5554 self.assertTrue(seq.ready)
5557 pprint(seq, big_blobs=True, with_decode_path=True)
5559 @given(data_strategy())
5560 def test_call(self, d):
5561 class SeqInherited(self.base_klass):
5563 for klass in (self.base_klass, SeqInherited):
5572 ) = d.draw(seq_values_strategy(seq_klass=klass))
5573 obj_initial = klass(
5579 optional_initial or False,
5590 ) = d.draw(seq_values_strategy(
5592 do_expl=impl_initial is None,
5594 obj = obj_initial(value, impl, expl, default, optional)
5595 value_expected = default if value is None else value
5597 default_initial if value_expected is None
5600 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5601 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5602 self.assertEqual(obj.expl_tag, expl or expl_initial)
5604 {} if obj.default is None else obj.default._value,
5605 getattr(default_initial if default is None else default, "_value", {}),
5607 if obj.default is None:
5608 optional = optional_initial if optional is None else optional
5609 optional = False if optional is None else optional
5612 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5613 self.assertEqual(obj.optional, optional)
5615 @given(data_strategy())
5616 def test_copy(self, d):
5617 class SeqInherited(self.base_klass):
5619 register_class(SeqInherited)
5620 for klass in (self.base_klass, SeqInherited):
5621 values = d.draw(seq_values_strategy(seq_klass=klass))
5622 obj = klass(*values)
5623 for copy_func in copy_funcs:
5624 obj_copied = copy_func(obj)
5625 self.assert_copied_basic_fields(obj, obj_copied)
5626 self.assertEqual(obj.specs, obj_copied.specs)
5627 self.assertEqual(obj._value, obj_copied._value)
5629 @given(data_strategy())
5630 def test_stripped(self, d):
5631 value = d.draw(integers())
5632 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5634 class Seq(self.base_klass):
5636 schema = (("whatever", Integer()),)
5638 seq["whatever"] = Integer(value)
5639 with self.assertRaises(NotEnoughData):
5640 seq.decode(seq.encode()[:-1])
5642 @given(data_strategy())
5643 def test_stripped_expl(self, d):
5644 value = d.draw(integers())
5645 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5647 class Seq(self.base_klass):
5649 schema = (("whatever", Integer()),)
5651 seq["whatever"] = Integer(value)
5652 with self.assertRaises(NotEnoughData):
5653 seq.decode(seq.encode()[:-1])
5655 @given(binary(min_size=2))
5656 def test_non_tag_mismatch_raised(self, junk):
5658 _, _, len_encoded = tag_strip(memoryview(junk))
5659 len_decode(len_encoded)
5665 class Seq(self.base_klass):
5667 ("whatever", Integer()),
5669 ("whenever", Integer()),
5672 seq["whatever"] = Integer(123)
5673 seq["junk"] = Any(junk)
5674 seq["whenever"] = Integer(123)
5675 with self.assertRaises(DecodeError):
5676 seq.decode(seq.encode())
5679 integers(min_value=31),
5680 integers(min_value=0),
5683 def test_bad_tag(self, tag, offset, decode_path):
5684 with self.assertRaises(DecodeError) as err:
5685 self.base_klass().decode(
5686 tag_encode(tag)[:-1],
5688 decode_path=decode_path,
5691 self.assertEqual(err.exception.offset, offset)
5692 self.assertEqual(err.exception.decode_path, decode_path)
5695 integers(min_value=128),
5696 integers(min_value=0),
5699 def test_bad_len(self, l, offset, decode_path):
5700 with self.assertRaises(DecodeError) as err:
5701 self.base_klass().decode(
5702 self.base_klass.tag_default + len_encode(l)[:-1],
5704 decode_path=decode_path,
5707 self.assertEqual(err.exception.offset, offset)
5708 self.assertEqual(err.exception.decode_path, decode_path)
5710 def _assert_expects(self, seq, expects):
5711 for expect in expects:
5713 seq.specs[expect["name"]].optional,
5716 if expect["default_value"] is not None:
5718 seq.specs[expect["name"]].default,
5719 expect["default_value"],
5721 if expect["presented"]:
5722 self.assertIn(expect["name"], seq)
5723 self.assertEqual(seq[expect["name"]], expect["value"])
5725 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5726 @given(data_strategy())
5727 def test_symmetric(self, d):
5728 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5729 tail_junk = d.draw(binary(max_size=5))
5730 self.assertTrue(seq.ready)
5731 self.assertFalse(seq.decoded)
5732 self._assert_expects(seq, expects)
5735 pprint(seq, big_blobs=True, with_decode_path=True)
5736 self.assertTrue(seq.ready)
5737 seq_encoded = seq.encode()
5738 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5739 self.assertFalse(seq_decoded.lenindef)
5740 self.assertFalse(seq_decoded.ber_encoded)
5741 self.assertFalse(seq_decoded.bered)
5743 t, _, lv = tag_strip(seq_encoded)
5744 _, _, v = len_decode(lv)
5745 seq_encoded_lenindef = t + LENINDEF + v + EOC
5746 with self.assertRaises(DecodeError):
5747 seq.decode(seq_encoded_lenindef)
5748 ctx_copied = deepcopy(ctx_dummy)
5749 ctx_copied["bered"] = True
5750 seq_decoded_lenindef, tail_lenindef = seq.decode(
5751 seq_encoded_lenindef + tail_junk,
5754 del ctx_copied["bered"]
5755 self.assertDictEqual(ctx_copied, ctx_dummy)
5756 self.assertTrue(seq_decoded_lenindef.lenindef)
5757 self.assertTrue(seq_decoded_lenindef.bered)
5758 seq_decoded_lenindef = copy(seq_decoded_lenindef)
5759 self.assertTrue(seq_decoded_lenindef.lenindef)
5760 self.assertTrue(seq_decoded_lenindef.bered)
5761 with self.assertRaises(DecodeError):
5762 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5763 with self.assertRaises(DecodeError):
5764 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5765 repr(seq_decoded_lenindef)
5766 list(seq_decoded_lenindef.pps())
5767 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5768 self.assertTrue(seq_decoded_lenindef.ready)
5770 for decoded, decoded_tail, encoded in (
5771 (seq_decoded, tail, seq_encoded),
5772 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5774 self.assertEqual(decoded_tail, tail_junk)
5775 self._assert_expects(decoded, expects)
5776 self.assertEqual(seq, decoded)
5777 self.assertEqual(decoded.encode(), seq_encoded)
5778 self.assertEqual(decoded.tlvlen, len(encoded))
5779 for expect in expects:
5780 if not expect["presented"]:
5781 self.assertNotIn(expect["name"], decoded)
5783 self.assertIn(expect["name"], decoded)
5784 obj = decoded[expect["name"]]
5785 self.assertTrue(obj.decoded)
5786 offset = obj.expl_offset if obj.expled else obj.offset
5787 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5788 self.assertSequenceEqual(
5789 seq_encoded[offset:offset + tlvlen],
5793 assert_exceeding_data(
5795 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
5799 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5800 @given(data_strategy())
5801 def test_symmetric_with_seq(self, d):
5802 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5803 self.assertTrue(seq.ready)
5804 seq_encoded = seq.encode()
5805 seq_decoded, tail = seq.decode(seq_encoded)
5806 self.assertEqual(tail, b"")
5807 self.assertTrue(seq.ready)
5808 self.assertEqual(seq, seq_decoded)
5809 self.assertEqual(seq_decoded.encode(), seq_encoded)
5810 for expect_outer in expect_outers:
5811 if not expect_outer["presented"]:
5812 self.assertNotIn(expect_outer["name"], seq_decoded)
5814 self.assertIn(expect_outer["name"], seq_decoded)
5815 obj = seq_decoded[expect_outer["name"]]
5816 self.assertTrue(obj.decoded)
5817 offset = obj.expl_offset if obj.expled else obj.offset
5818 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5819 self.assertSequenceEqual(
5820 seq_encoded[offset:offset + tlvlen],
5823 self._assert_expects(obj, expect_outer["expects"])
5825 @given(data_strategy())
5826 def test_default_disappears(self, d):
5827 _schema = list(d.draw(dictionaries(
5829 sets(integers(), min_size=2, max_size=2),
5833 class Seq(self.base_klass):
5835 (n, Integer(default=d))
5836 for n, (_, d) in _schema
5839 for name, (value, _) in _schema:
5840 seq[name] = Integer(value)
5841 self.assertEqual(len(seq._value), len(_schema))
5842 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5843 self.assertGreater(len(seq.encode()), len(empty_seq))
5844 for name, (_, default) in _schema:
5845 seq[name] = Integer(default)
5846 self.assertEqual(len(seq._value), 0)
5847 self.assertSequenceEqual(seq.encode(), empty_seq)
5849 @given(data_strategy())
5850 def test_encoded_default_not_accepted(self, d):
5851 _schema = list(d.draw(dictionaries(
5856 tags = [tag_encode(tag) for tag in d.draw(sets(
5857 integers(min_value=1),
5858 min_size=len(_schema),
5859 max_size=len(_schema),
5862 class SeqWithoutDefault(self.base_klass):
5864 (n, Integer(impl=t))
5865 for (n, _), t in zip(_schema, tags)
5867 seq_without_default = SeqWithoutDefault()
5868 for name, value in _schema:
5869 seq_without_default[name] = Integer(value)
5870 seq_encoded = seq_without_default.encode()
5872 class SeqWithDefault(self.base_klass):
5874 (n, Integer(default=v, impl=t))
5875 for (n, v), t in zip(_schema, tags)
5877 seq_with_default = SeqWithDefault()
5878 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5879 seq_with_default.decode(seq_encoded)
5880 for ctx in ({"bered": True}, {"allow_default_values": True}):
5881 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5882 self.assertTrue(seq_decoded.ber_encoded)
5883 self.assertTrue(seq_decoded.bered)
5884 seq_decoded = copy(seq_decoded)
5885 self.assertTrue(seq_decoded.ber_encoded)
5886 self.assertTrue(seq_decoded.bered)
5887 for name, value in _schema:
5888 self.assertEqual(seq_decoded[name], seq_with_default[name])
5889 self.assertEqual(seq_decoded[name], value)
5891 @given(data_strategy())
5892 def test_missing_from_spec(self, d):
5893 names = list(d.draw(sets(text_letters(), min_size=2)))
5894 tags = [tag_encode(tag) for tag in d.draw(sets(
5895 integers(min_value=1),
5896 min_size=len(names),
5897 max_size=len(names),
5899 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5901 class SeqFull(self.base_klass):
5902 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5903 seq_full = SeqFull()
5904 for i, name in enumerate(names):
5905 seq_full[name] = Integer(i)
5906 seq_encoded = seq_full.encode()
5907 altered = names_tags[:-2] + names_tags[-1:]
5909 class SeqMissing(self.base_klass):
5910 schema = [(n, Integer(impl=t)) for n, t in altered]
5911 seq_missing = SeqMissing()
5912 with self.assertRaises(TagMismatch):
5913 seq_missing.decode(seq_encoded)
5915 def test_bered(self):
5916 class Seq(self.base_klass):
5917 schema = (("underlying", Boolean()),)
5918 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5919 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5920 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5921 self.assertFalse(decoded.ber_encoded)
5922 self.assertFalse(decoded.lenindef)
5923 self.assertTrue(decoded.bered)
5924 decoded = copy(decoded)
5925 self.assertFalse(decoded.ber_encoded)
5926 self.assertFalse(decoded.lenindef)
5927 self.assertTrue(decoded.bered)
5929 class Seq(self.base_klass):
5930 schema = (("underlying", OctetString()),)
5932 tag_encode(form=TagFormConstructed, num=4) +
5934 OctetString(b"whatever").encode() +
5937 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5938 with self.assertRaises(DecodeError):
5939 Seq().decode(encoded)
5940 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5941 self.assertFalse(decoded.ber_encoded)
5942 self.assertFalse(decoded.lenindef)
5943 self.assertTrue(decoded.bered)
5944 decoded = copy(decoded)
5945 self.assertFalse(decoded.ber_encoded)
5946 self.assertFalse(decoded.lenindef)
5947 self.assertTrue(decoded.bered)
5950 class TestSequence(SeqMixing, CommonMixin, TestCase):
5951 base_klass = Sequence
5957 def test_remaining(self, value, junk):
5958 class Seq(Sequence):
5960 ("whatever", Integer()),
5962 int_encoded = Integer(value).encode()
5964 Sequence.tag_default,
5965 len_encode(len(int_encoded + junk)),
5968 with assertRaisesRegex(self, DecodeError, "remaining"):
5969 Seq().decode(junked)
5971 @given(sets(text_letters(), min_size=2))
5972 def test_obj_unknown(self, names):
5973 missing = names.pop()
5975 class Seq(Sequence):
5976 schema = [(n, Boolean()) for n in names]
5978 with self.assertRaises(ObjUnknown) as err:
5981 with self.assertRaises(ObjUnknown) as err:
5982 seq[missing] = Boolean()
5985 def test_x690_vector(self):
5986 class Seq(Sequence):
5988 ("name", IA5String()),
5991 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5992 self.assertEqual(seq["name"], "Smith")
5993 self.assertEqual(seq["ok"], True)
5996 class TestSet(SeqMixing, CommonMixin, TestCase):
5999 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6000 @given(data_strategy())
6001 def test_sorted(self, d):
6003 tag_encode(tag) for tag in
6004 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
6008 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
6010 for name, _ in Seq.schema:
6011 seq[name] = OctetString(b"")
6012 seq_encoded = seq.encode()
6013 seq_decoded, _ = seq.decode(seq_encoded)
6014 self.assertSequenceEqual(
6015 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6016 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
6019 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6020 @given(data_strategy())
6021 def test_unsorted(self, d):
6023 tag_encode(tag) for tag in
6024 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
6026 tags = d.draw(permutations(tags))
6027 assume(tags != sorted(tags))
6028 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
6029 seq_encoded = b"".join((
6031 len_encode(len(encoded)),
6036 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
6038 with assertRaisesRegex(self, DecodeError, "unordered SET"):
6039 seq.decode(seq_encoded)
6040 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6041 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6042 self.assertTrue(seq_decoded.ber_encoded)
6043 self.assertTrue(seq_decoded.bered)
6044 seq_decoded = copy(seq_decoded)
6045 self.assertTrue(seq_decoded.ber_encoded)
6046 self.assertTrue(seq_decoded.bered)
6047 self.assertSequenceEqual(
6048 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
6052 def test_same_value_twice(self):
6055 ("bool", Boolean()),
6059 encoded = b"".join((
6060 Integer(123).encode(),
6061 Integer(234).encode(),
6062 Boolean(True).encode(),
6064 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6065 with self.assertRaises(TagMismatch):
6066 Seq().decod(encoded, ctx={"allow_unordered_set": True})
6070 def seqof_values_strategy(draw, schema=None, do_expl=False):
6072 schema = draw(sampled_from((Boolean(), Integer())))
6073 bound_min, bound_max = sorted(draw(sets(
6074 integers(min_value=0, max_value=10),
6078 if isinstance(schema, Boolean):
6079 values_generator = booleans().map(Boolean)
6080 elif isinstance(schema, Integer):
6081 values_generator = integers().map(Integer)
6082 values_generator = lists(
6087 values = draw(one_of(none(), values_generator))
6091 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6093 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6094 default = draw(one_of(none(), values_generator))
6095 optional = draw(one_of(none(), booleans()))
6097 draw(integers(min_value=0)),
6098 draw(integers(min_value=0)),
6099 draw(integers(min_value=0)),
6104 (bound_min, bound_max),
6113 class SeqOfMixing(object):
6114 def test_invalid_value_type(self):
6115 with self.assertRaises(InvalidValueType) as err:
6116 self.base_klass(123)
6119 def test_invalid_values_type(self):
6120 class SeqOf(self.base_klass):
6122 with self.assertRaises(InvalidValueType) as err:
6123 SeqOf([Integer(123), Boolean(False), Integer(234)])
6126 def test_schema_required(self):
6127 with assertRaisesRegex(self, ValueError, "schema must be specified"):
6128 self.base_klass.__mro__[1]()
6130 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6131 def test_comparison(self, value1, value2, tag1, tag2):
6132 class SeqOf(self.base_klass):
6134 obj1 = SeqOf([Boolean(value1)])
6135 obj2 = SeqOf([Boolean(value2)])
6136 self.assertEqual(obj1 == obj2, value1 == value2)
6137 self.assertEqual(obj1 != obj2, value1 != value2)
6138 self.assertEqual(obj1 == list(obj2), value1 == value2)
6139 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6140 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6141 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6142 self.assertEqual(obj1 == obj2, tag1 == tag2)
6143 self.assertEqual(obj1 != obj2, tag1 != tag2)
6145 @given(lists(booleans()))
6146 def test_iter(self, values):
6147 class SeqOf(self.base_klass):
6149 obj = SeqOf([Boolean(value) for value in values])
6150 self.assertEqual(len(obj), len(values))
6151 for i, value in enumerate(obj):
6152 self.assertEqual(value, values[i])
6154 @given(data_strategy())
6155 def test_ready(self, d):
6156 ready = [Integer(v) for v in d.draw(lists(
6163 range(d.draw(integers(min_value=1, max_value=5)))
6166 class SeqOf(self.base_klass):
6168 values = d.draw(permutations(ready + non_ready))
6170 for value in values:
6172 self.assertFalse(seqof.ready)
6175 pprint(seqof, big_blobs=True, with_decode_path=True)
6176 with self.assertRaises(ObjNotReady) as err:
6179 for i, value in enumerate(values):
6180 self.assertEqual(seqof[i], value)
6181 if not seqof[i].ready:
6182 seqof[i] = Integer(i)
6183 self.assertTrue(seqof.ready)
6186 pprint(seqof, big_blobs=True, with_decode_path=True)
6188 def test_spec_mismatch(self):
6189 class SeqOf(self.base_klass):
6192 seqof.append(Integer(123))
6193 with self.assertRaises(ValueError):
6194 seqof.append(Boolean(False))
6195 with self.assertRaises(ValueError):
6196 seqof[0] = Boolean(False)
6198 @given(data_strategy())
6199 def test_bounds_satisfied(self, d):
6200 class SeqOf(self.base_klass):
6202 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6203 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6204 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6205 SeqOf(value=value, bounds=(bound_min, bound_max))
6207 @given(data_strategy())
6208 def test_bounds_unsatisfied(self, d):
6209 class SeqOf(self.base_klass):
6211 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6212 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6213 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
6214 with self.assertRaises(BoundsError) as err:
6215 SeqOf(value=value, bounds=(bound_min, bound_max))
6217 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6218 SeqOf(bounds=(bound_min, bound_max)).decode(
6219 SeqOf(value).encode()
6222 value = [Boolean(True)] * d.draw(integers(
6223 min_value=bound_max + 1,
6224 max_value=bound_max + 10,
6226 with self.assertRaises(BoundsError) as err:
6227 SeqOf(value=value, bounds=(bound_min, bound_max))
6229 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6230 SeqOf(bounds=(bound_min, bound_max)).decode(
6231 SeqOf(value).encode()
6235 @given(integers(min_value=1, max_value=10))
6236 def test_out_of_bounds(self, bound_max):
6237 class SeqOf(self.base_klass):
6239 bounds = (0, bound_max)
6241 for _ in range(bound_max):
6242 seqof.append(Integer(123))
6243 with self.assertRaises(BoundsError):
6244 seqof.append(Integer(123))
6246 @given(data_strategy())
6247 def test_call(self, d):
6257 ) = d.draw(seqof_values_strategy())
6259 class SeqOf(self.base_klass):
6260 schema = schema_initial
6261 obj_initial = SeqOf(
6262 value=value_initial,
6263 bounds=bounds_initial,
6266 default=default_initial,
6267 optional=optional_initial or False,
6268 _decoded=_decoded_initial,
6279 ) = d.draw(seqof_values_strategy(
6280 schema=schema_initial,
6281 do_expl=impl_initial is None,
6283 if (default is None) and (obj_initial.default is not None):
6286 (bounds is None) and
6287 (value is not None) and
6288 (bounds_initial is not None) and
6289 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6293 (bounds is None) and
6294 (default is not None) and
6295 (bounds_initial is not None) and
6296 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6308 value_expected = default if value is None else value
6310 default_initial if value_expected is None
6313 value_expected = () if value_expected is None else value_expected
6314 self.assertEqual(obj, value_expected)
6315 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6316 self.assertEqual(obj.expl_tag, expl or expl_initial)
6319 default_initial if default is None else default,
6321 if obj.default is None:
6322 optional = optional_initial if optional is None else optional
6323 optional = False if optional is None else optional
6326 self.assertEqual(obj.optional, optional)
6328 (obj._bound_min, obj._bound_max),
6329 bounds or bounds_initial or (0, float("+inf")),
6332 @given(seqof_values_strategy())
6333 def test_copy(self, values):
6334 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6336 class SeqOf(self.base_klass):
6338 register_class(SeqOf)
6345 optional=optional or False,
6348 for copy_func in copy_funcs:
6349 obj_copied = copy_func(obj)
6350 self.assert_copied_basic_fields(obj, obj_copied)
6351 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6352 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6353 self.assertEqual(obj._value, obj_copied._value)
6357 integers(min_value=1).map(tag_encode),
6359 def test_stripped(self, values, tag_impl):
6360 class SeqOf(self.base_klass):
6361 schema = OctetString()
6362 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6363 with self.assertRaises(NotEnoughData):
6364 obj.decode(obj.encode()[:-1])
6368 integers(min_value=1).map(tag_ctxc),
6370 def test_stripped_expl(self, values, tag_expl):
6371 class SeqOf(self.base_klass):
6372 schema = OctetString()
6373 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6374 with self.assertRaises(NotEnoughData):
6375 obj.decode(obj.encode()[:-1])
6378 integers(min_value=31),
6379 integers(min_value=0),
6382 def test_bad_tag(self, tag, offset, decode_path):
6383 with self.assertRaises(DecodeError) as err:
6384 self.base_klass().decode(
6385 tag_encode(tag)[:-1],
6387 decode_path=decode_path,
6390 self.assertEqual(err.exception.offset, offset)
6391 self.assertEqual(err.exception.decode_path, decode_path)
6394 integers(min_value=128),
6395 integers(min_value=0),
6398 def test_bad_len(self, l, offset, decode_path):
6399 with self.assertRaises(DecodeError) as err:
6400 self.base_klass().decode(
6401 self.base_klass.tag_default + len_encode(l)[:-1],
6403 decode_path=decode_path,
6406 self.assertEqual(err.exception.offset, offset)
6407 self.assertEqual(err.exception.decode_path, decode_path)
6409 @given(binary(min_size=1))
6410 def test_tag_mismatch(self, impl):
6411 assume(impl != self.base_klass.tag_default)
6412 with self.assertRaises(TagMismatch):
6413 self.base_klass(impl=impl).decode(self.base_klass().encode())
6415 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6417 seqof_values_strategy(schema=Integer()),
6418 lists(integers().map(Integer)),
6419 integers(min_value=1).map(tag_ctxc),
6420 integers(min_value=0),
6423 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
6424 _, _, _, _, _, default, optional, _decoded = values
6426 class SeqOf(self.base_klass):
6436 pprint(obj, big_blobs=True, with_decode_path=True)
6437 self.assertFalse(obj.expled)
6438 obj_encoded = obj.encode()
6439 obj_expled = obj(value, expl=tag_expl)
6440 self.assertTrue(obj_expled.expled)
6442 list(obj_expled.pps())
6443 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6444 obj_expled_encoded = obj_expled.encode()
6445 ctx_copied = deepcopy(ctx_dummy)
6446 obj_decoded, tail = obj_expled.decode(
6447 obj_expled_encoded + tail_junk,
6451 self.assertDictEqual(ctx_copied, ctx_dummy)
6453 list(obj_decoded.pps())
6454 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6455 self.assertEqual(tail, tail_junk)
6456 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6457 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6458 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6459 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6461 obj_decoded.expl_llen,
6462 len(len_encode(len(obj_encoded))),
6464 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
6465 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
6468 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
6470 self.assertEqual(obj_decoded.expl_offset, offset)
6471 for obj_inner in obj_decoded:
6472 self.assertIn(obj_inner, obj_decoded)
6473 self.assertSequenceEqual(
6476 obj_inner.offset - offset:
6477 obj_inner.offset + obj_inner.tlvlen - offset
6481 t, _, lv = tag_strip(obj_encoded)
6482 _, _, v = len_decode(lv)
6483 obj_encoded_lenindef = t + LENINDEF + v + EOC
6484 with self.assertRaises(DecodeError):
6485 obj.decode(obj_encoded_lenindef)
6486 obj_decoded_lenindef, tail_lenindef = obj.decode(
6487 obj_encoded_lenindef + tail_junk,
6488 ctx={"bered": True},
6490 self.assertTrue(obj_decoded_lenindef.lenindef)
6491 self.assertTrue(obj_decoded_lenindef.bered)
6492 obj_decoded_lenindef = copy(obj_decoded_lenindef)
6493 self.assertTrue(obj_decoded_lenindef.lenindef)
6494 self.assertTrue(obj_decoded_lenindef.bered)
6495 repr(obj_decoded_lenindef)
6496 list(obj_decoded_lenindef.pps())
6497 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
6498 self.assertEqual(tail_lenindef, tail_junk)
6499 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
6500 with self.assertRaises(DecodeError):
6501 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
6502 with self.assertRaises(DecodeError):
6503 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
6505 assert_exceeding_data(
6507 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
6511 def test_bered(self):
6512 class SeqOf(self.base_klass):
6514 encoded = Boolean(False).encode()
6515 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
6516 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6517 with self.assertRaises(DecodeError):
6518 SeqOf().decode(encoded)
6519 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6520 self.assertFalse(decoded.ber_encoded)
6521 self.assertFalse(decoded.lenindef)
6522 self.assertTrue(decoded.bered)
6523 decoded = copy(decoded)
6524 self.assertFalse(decoded.ber_encoded)
6525 self.assertFalse(decoded.lenindef)
6526 self.assertTrue(decoded.bered)
6528 class SeqOf(self.base_klass):
6529 schema = OctetString()
6530 encoded = OctetString(b"whatever").encode()
6532 tag_encode(form=TagFormConstructed, num=4) +
6534 OctetString(b"whatever").encode() +
6537 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6538 with self.assertRaises(DecodeError):
6539 SeqOf().decode(encoded)
6540 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6541 self.assertFalse(decoded.ber_encoded)
6542 self.assertFalse(decoded.lenindef)
6543 self.assertTrue(decoded.bered)
6544 decoded = copy(decoded)
6545 self.assertFalse(decoded.ber_encoded)
6546 self.assertFalse(decoded.lenindef)
6547 self.assertTrue(decoded.bered)
6550 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
6551 class SeqOf(SequenceOf):
6555 def _test_symmetric_compare_objs(self, obj1, obj2):
6556 self.assertEqual(obj1, obj2)
6557 self.assertSequenceEqual(list(obj1), list(obj2))
6560 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
6565 def _test_symmetric_compare_objs(self, obj1, obj2):
6566 self.assertSetEqual(
6567 set(int(v) for v in obj1),
6568 set(int(v) for v in obj2),
6571 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6572 @given(data_strategy())
6573 def test_sorted(self, d):
6574 values = [OctetString(v) for v in d.draw(lists(binary()))]
6577 schema = OctetString()
6579 seq_encoded = seq.encode()
6580 seq_decoded, _ = seq.decode(seq_encoded)
6581 self.assertSequenceEqual(
6582 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6583 b"".join(sorted([v.encode() for v in values])),
6586 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6587 @given(data_strategy())
6588 def test_unsorted(self, d):
6589 values = [OctetString(v).encode() for v in d.draw(sets(
6590 binary(min_size=1, max_size=5),
6594 values = d.draw(permutations(values))
6595 assume(values != sorted(values))
6596 encoded = b"".join(values)
6597 seq_encoded = b"".join((
6599 len_encode(len(encoded)),
6604 schema = OctetString()
6606 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6607 seq.decode(seq_encoded)
6609 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6610 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6611 self.assertTrue(seq_decoded.ber_encoded)
6612 self.assertTrue(seq_decoded.bered)
6613 seq_decoded = copy(seq_decoded)
6614 self.assertTrue(seq_decoded.ber_encoded)
6615 self.assertTrue(seq_decoded.bered)
6616 self.assertSequenceEqual(
6617 [obj.encode() for obj in seq_decoded],
6622 class TestGoMarshalVectors(TestCase):
6624 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6625 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6626 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6627 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6628 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6630 class Seq(Sequence):
6632 ("erste", Integer()),
6633 ("zweite", Integer(optional=True))
6636 seq["erste"] = Integer(64)
6637 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6638 seq["erste"] = Integer(0x123456)
6639 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6640 seq["erste"] = Integer(64)
6641 seq["zweite"] = Integer(65)
6642 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6644 class NestedSeq(Sequence):
6648 seq["erste"] = Integer(127)
6649 seq["zweite"] = None
6650 nested = NestedSeq()
6651 nested["nest"] = seq
6652 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6654 self.assertSequenceEqual(
6655 OctetString(b"\x01\x02\x03").encode(),
6656 hexdec("0403010203"),
6659 class Seq(Sequence):
6661 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6664 seq["erste"] = Integer(64)
6665 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6667 class Seq(Sequence):
6669 ("erste", Integer(expl=tag_ctxc(5))),
6672 seq["erste"] = Integer(64)
6673 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6675 class Seq(Sequence):
6678 impl=tag_encode(0, klass=TagClassContext),
6683 seq["erste"] = Null()
6684 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6686 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6688 self.assertSequenceEqual(
6689 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6690 hexdec("170d3730303130313030303030305a"),
6692 self.assertSequenceEqual(
6693 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6694 hexdec("170d3039313131353232353631365a"),
6696 self.assertSequenceEqual(
6697 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6698 hexdec("180f32313030303430353132303130315a"),
6701 class Seq(Sequence):
6703 ("erste", GeneralizedTime()),
6706 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6707 self.assertSequenceEqual(
6709 hexdec("3011180f32303039313131353232353631365a"),
6712 self.assertSequenceEqual(
6713 BitString((1, b"\x80")).encode(),
6716 self.assertSequenceEqual(
6717 BitString((12, b"\x81\xF0")).encode(),
6718 hexdec("03030481f0"),
6721 self.assertSequenceEqual(
6722 ObjectIdentifier("1.2.3.4").encode(),
6723 hexdec("06032a0304"),
6725 self.assertSequenceEqual(
6726 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6727 hexdec("06092a864888932d010105"),
6729 self.assertSequenceEqual(
6730 ObjectIdentifier("2.100.3").encode(),
6731 hexdec("0603813403"),
6734 self.assertSequenceEqual(
6735 PrintableString("test").encode(),
6736 hexdec("130474657374"),
6738 self.assertSequenceEqual(
6739 PrintableString("x" * 127).encode(),
6740 hexdec("137F" + "78" * 127),
6742 self.assertSequenceEqual(
6743 PrintableString("x" * 128).encode(),
6744 hexdec("138180" + "78" * 128),
6746 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6748 class Seq(Sequence):
6750 ("erste", IA5String()),
6753 seq["erste"] = IA5String("test")
6754 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6756 class Seq(Sequence):
6758 ("erste", PrintableString()),
6761 seq["erste"] = PrintableString("test")
6762 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6763 # Asterisk is actually not allowable
6764 PrintableString._allowable_chars |= set(b"*")
6765 seq["erste"] = PrintableString("test*")
6766 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6767 PrintableString._allowable_chars -= set(b"*")
6769 class Seq(Sequence):
6771 ("erste", Any(optional=True)),
6772 ("zweite", Integer()),
6775 seq["zweite"] = Integer(64)
6776 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6781 seq.append(Integer(10))
6782 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6784 class _SeqOf(SequenceOf):
6785 schema = PrintableString()
6787 class SeqOf(SequenceOf):
6790 _seqof.append(PrintableString("1"))
6792 seqof.append(_seqof)
6793 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6795 class Seq(Sequence):
6797 ("erste", Integer(default=1)),
6800 seq["erste"] = Integer(0)
6801 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6802 seq["erste"] = Integer(1)
6803 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6804 seq["erste"] = Integer(2)
6805 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6808 class TestPP(TestCase):
6809 @given(data_strategy())
6810 def test_oid_printing(self, d):
6812 str(ObjectIdentifier(k)): v * 2
6813 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6815 chosen = d.draw(sampled_from(sorted(oids)))
6816 chosen_id = oids[chosen]
6817 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6818 self.assertNotIn(chosen_id, pp_console_row(pp))
6821 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6825 class TestAutoAddSlots(TestCase):
6827 class Inher(Integer):
6830 with self.assertRaises(AttributeError):
6832 inher.unexistent = "whatever"
6835 class TestOIDDefines(TestCase):
6836 @given(data_strategy())
6837 def runTest(self, d):
6838 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6839 value_name_chosen = d.draw(sampled_from(value_names))
6841 ObjectIdentifier(oid)
6842 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6844 oid_chosen = d.draw(sampled_from(oids))
6845 values = d.draw(lists(
6847 min_size=len(value_names),
6848 max_size=len(value_names),
6850 for definable_class in (Any, OctetString, BitString):
6852 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6853 oid: Integer() for oid in oids[:-1]
6856 for i, value_name in enumerate(value_names):
6857 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
6859 class Seq(Sequence):
6862 for value_name, value in zip(value_names, values):
6863 seq[value_name] = definable_class(Integer(value).encode())
6864 seq["type"] = oid_chosen
6865 seq, _ = Seq().decode(seq.encode())
6866 for value_name in value_names:
6867 if value_name == value_name_chosen:
6869 self.assertIsNone(seq[value_name].defined)
6870 if value_name_chosen in oids[:-1]:
6871 self.assertIsNotNone(seq[value_name_chosen].defined)
6872 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6873 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6876 pprint(seq, big_blobs=True, with_decode_path=True)
6879 class TestDefinesByPath(TestCase):
6880 def test_generated(self):
6881 class Seq(Sequence):
6883 ("type", ObjectIdentifier()),
6884 ("value", OctetString(expl=tag_ctxc(123))),
6887 class SeqInner(Sequence):
6889 ("typeInner", ObjectIdentifier()),
6890 ("valueInner", Any()),
6893 class PairValue(SetOf):
6896 class Pair(Sequence):
6898 ("type", ObjectIdentifier()),
6899 ("value", PairValue()),
6902 class Pairs(SequenceOf):
6909 type_octet_stringed,
6911 ObjectIdentifier(oid)
6912 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6914 seq_integered = Seq()
6915 seq_integered["type"] = type_integered
6916 seq_integered["value"] = OctetString(Integer(123).encode())
6917 seq_integered_raw = seq_integered.encode()
6921 (type_octet_stringed, OctetString(b"whatever")),
6922 (type_integered, Integer(123)),
6923 (type_octet_stringed, OctetString(b"whenever")),
6924 (type_integered, Integer(234)),
6926 for t, v in pairs_input:
6929 ("value", PairValue((Any(v),))),
6931 seq_inner = SeqInner()
6932 seq_inner["typeInner"] = type_innered
6933 seq_inner["valueInner"] = Any(pairs)
6934 seq_sequenced = Seq()
6935 seq_sequenced["type"] = type_sequenced
6936 seq_sequenced["value"] = OctetString(seq_inner.encode())
6937 seq_sequenced_raw = seq_sequenced.encode()
6939 list(seq_sequenced.pps())
6940 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6942 defines_by_path = []
6943 ctx_copied = deepcopy(ctx_dummy)
6944 seq_integered, _ = Seq().decode(
6948 self.assertDictEqual(ctx_copied, ctx_dummy)
6949 self.assertIsNone(seq_integered["value"].defined)
6950 defines_by_path.append(
6951 (("type",), ((("value",), {
6952 type_integered: Integer(),
6953 type_sequenced: SeqInner(),
6956 ctx_copied["defines_by_path"] = defines_by_path
6957 seq_integered, _ = Seq().decode(
6961 del ctx_copied["defines_by_path"]
6962 self.assertDictEqual(ctx_copied, ctx_dummy)
6963 self.assertIsNotNone(seq_integered["value"].defined)
6964 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6965 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6966 self.assertTrue(seq_integered_raw[
6967 seq_integered["value"].defined[1].offset:
6968 ].startswith(Integer(123).encode()))
6970 list(seq_integered.pps())
6971 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6973 ctx_copied["defines_by_path"] = defines_by_path
6974 seq_sequenced, _ = Seq().decode(
6978 del ctx_copied["defines_by_path"]
6979 self.assertDictEqual(ctx_copied, ctx_dummy)
6980 self.assertIsNotNone(seq_sequenced["value"].defined)
6981 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6982 seq_inner = seq_sequenced["value"].defined[1]
6983 self.assertIsNone(seq_inner["valueInner"].defined)
6985 list(seq_sequenced.pps())
6986 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6988 defines_by_path.append((
6989 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6990 ((("valueInner",), {type_innered: Pairs()}),),
6992 ctx_copied["defines_by_path"] = defines_by_path
6993 seq_sequenced, _ = Seq().decode(
6997 del ctx_copied["defines_by_path"]
6998 self.assertDictEqual(ctx_copied, ctx_dummy)
6999 self.assertIsNotNone(seq_sequenced["value"].defined)
7000 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7001 seq_inner = seq_sequenced["value"].defined[1]
7002 self.assertIsNotNone(seq_inner["valueInner"].defined)
7003 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7004 pairs = seq_inner["valueInner"].defined[1]
7006 self.assertIsNone(pair["value"][0].defined)
7008 list(seq_sequenced.pps())
7009 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7011 defines_by_path.append((
7014 DecodePathDefBy(type_sequenced),
7016 DecodePathDefBy(type_innered),
7021 type_integered: Integer(),
7022 type_octet_stringed: OctetString(),
7025 ctx_copied["defines_by_path"] = defines_by_path
7026 seq_sequenced, _ = Seq().decode(
7030 del ctx_copied["defines_by_path"]
7031 self.assertDictEqual(ctx_copied, ctx_dummy)
7032 self.assertIsNotNone(seq_sequenced["value"].defined)
7033 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7034 seq_inner = seq_sequenced["value"].defined[1]
7035 self.assertIsNotNone(seq_inner["valueInner"].defined)
7036 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7037 pairs_got = seq_inner["valueInner"].defined[1]
7038 for pair_input, pair_got in zip(pairs_input, pairs_got):
7039 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7040 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7042 list(seq_sequenced.pps())
7043 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7045 @given(oid_strategy(), integers())
7046 def test_simple(self, oid, tgt):
7047 class Inner(Sequence):
7049 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7050 ObjectIdentifier(oid): Integer(),
7054 class Outer(Sequence):
7057 ("tgt", OctetString()),
7061 inner["oid"] = ObjectIdentifier(oid)
7063 outer["inner"] = inner
7064 outer["tgt"] = OctetString(Integer(tgt).encode())
7065 decoded, _ = Outer().decode(outer.encode())
7066 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7068 def test_remaining_data(self):
7069 oid = ObjectIdentifier("1.2.3")
7070 class Seq(Sequence):
7072 ("oid", ObjectIdentifier(defines=((("tgt",), {
7075 ("tgt", OctetString()),
7080 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7082 with assertRaisesRegex(self, DecodeError, "remaining data"):
7083 Seq().decode(seq.encode())
7085 def test_remaining_data_seqof(self):
7086 oid = ObjectIdentifier("1.2.3")
7088 schema = OctetString()
7090 class Seq(Sequence):
7092 ("oid", ObjectIdentifier(defines=((("tgt",), {
7100 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7102 with assertRaisesRegex(self, DecodeError, "remaining data"):
7103 Seq().decode(seq.encode())
7106 class TestAbsDecodePath(TestCase):
7108 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7109 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7111 def test_concat(self, decode_path, rel_path):
7112 dp = abs_decode_path(decode_path, rel_path)
7113 self.assertSequenceEqual(dp, decode_path + rel_path)
7117 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7118 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7120 def test_abs(self, decode_path, rel_path):
7121 self.assertSequenceEqual(
7122 abs_decode_path(decode_path, ("/",) + rel_path),
7127 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7128 integers(min_value=1, max_value=3),
7129 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7131 def test_dots(self, decode_path, number_of_dots, rel_path):
7132 self.assertSequenceEqual(
7133 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7134 decode_path[:-number_of_dots] + rel_path,
7138 class TestStrictDefaultExistence(TestCase):
7139 @given(data_strategy())
7140 def runTest(self, d):
7141 count = d.draw(integers(min_value=1, max_value=10))
7142 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7144 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7145 for i in range(count)
7147 for klass in (Sequence, Set):
7151 for i in range(count):
7152 seq["int%d" % i] = Integer(123)
7154 chosen_choice = "int%d" % chosen
7155 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7156 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
7158 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7159 self.assertTrue(decoded.ber_encoded)
7160 self.assertTrue(decoded.bered)
7161 decoded = copy(decoded)
7162 self.assertTrue(decoded.ber_encoded)
7163 self.assertTrue(decoded.bered)
7164 decoded, _ = seq.decode(raw, ctx={"bered": True})
7165 self.assertTrue(decoded.ber_encoded)
7166 self.assertTrue(decoded.bered)
7167 decoded = copy(decoded)
7168 self.assertTrue(decoded.ber_encoded)
7169 self.assertTrue(decoded.bered)
7172 class TestX690PrefixedType(TestCase):
7174 self.assertSequenceEqual(
7175 VisibleString("Jones").encode(),
7176 hexdec("1A054A6F6E6573"),
7178 self.assertSequenceEqual(
7181 impl=tag_encode(3, klass=TagClassApplication),
7183 hexdec("43054A6F6E6573"),
7185 self.assertSequenceEqual(
7189 impl=tag_encode(3, klass=TagClassApplication),
7193 hexdec("A20743054A6F6E6573"),
7195 self.assertSequenceEqual(
7199 impl=tag_encode(3, klass=TagClassApplication),
7201 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7203 hexdec("670743054A6F6E6573"),
7205 self.assertSequenceEqual(
7206 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7207 hexdec("82054A6F6E6573"),
7211 class TestExplOOB(TestCase):
7213 expl = tag_ctxc(123)
7214 raw = Integer(123).encode() + Integer(234).encode()
7215 raw = b"".join((expl, len_encode(len(raw)), raw))
7216 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
7217 Integer(expl=expl).decode(raw)
7218 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7221 class TestPickleDifferentVersion(TestCase):
7223 pickled = pickle_dumps(Integer(123), pickle_proto)
7225 version_orig = pyderasn.__version__
7226 pyderasn.__version__ += "different"
7227 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
7228 pickle_loads(pickled)
7229 pyderasn.__version__ = version_orig
7230 pickle_loads(pickled)