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)],
6054 def seqof_values_strategy(draw, schema=None, do_expl=False):
6056 schema = draw(sampled_from((Boolean(), Integer())))
6057 bound_min, bound_max = sorted(draw(sets(
6058 integers(min_value=0, max_value=10),
6062 if isinstance(schema, Boolean):
6063 values_generator = booleans().map(Boolean)
6064 elif isinstance(schema, Integer):
6065 values_generator = integers().map(Integer)
6066 values_generator = lists(
6071 values = draw(one_of(none(), values_generator))
6075 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6077 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6078 default = draw(one_of(none(), values_generator))
6079 optional = draw(one_of(none(), booleans()))
6081 draw(integers(min_value=0)),
6082 draw(integers(min_value=0)),
6083 draw(integers(min_value=0)),
6088 (bound_min, bound_max),
6097 class SeqOfMixing(object):
6098 def test_invalid_value_type(self):
6099 with self.assertRaises(InvalidValueType) as err:
6100 self.base_klass(123)
6103 def test_invalid_values_type(self):
6104 class SeqOf(self.base_klass):
6106 with self.assertRaises(InvalidValueType) as err:
6107 SeqOf([Integer(123), Boolean(False), Integer(234)])
6110 def test_schema_required(self):
6111 with assertRaisesRegex(self, ValueError, "schema must be specified"):
6112 self.base_klass.__mro__[1]()
6114 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6115 def test_comparison(self, value1, value2, tag1, tag2):
6116 class SeqOf(self.base_klass):
6118 obj1 = SeqOf([Boolean(value1)])
6119 obj2 = SeqOf([Boolean(value2)])
6120 self.assertEqual(obj1 == obj2, value1 == value2)
6121 self.assertEqual(obj1 != obj2, value1 != value2)
6122 self.assertEqual(obj1 == list(obj2), value1 == value2)
6123 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6124 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6125 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6126 self.assertEqual(obj1 == obj2, tag1 == tag2)
6127 self.assertEqual(obj1 != obj2, tag1 != tag2)
6129 @given(lists(booleans()))
6130 def test_iter(self, values):
6131 class SeqOf(self.base_klass):
6133 obj = SeqOf([Boolean(value) for value in values])
6134 self.assertEqual(len(obj), len(values))
6135 for i, value in enumerate(obj):
6136 self.assertEqual(value, values[i])
6138 @given(data_strategy())
6139 def test_ready(self, d):
6140 ready = [Integer(v) for v in d.draw(lists(
6147 range(d.draw(integers(min_value=1, max_value=5)))
6150 class SeqOf(self.base_klass):
6152 values = d.draw(permutations(ready + non_ready))
6154 for value in values:
6156 self.assertFalse(seqof.ready)
6159 pprint(seqof, big_blobs=True, with_decode_path=True)
6160 with self.assertRaises(ObjNotReady) as err:
6163 for i, value in enumerate(values):
6164 self.assertEqual(seqof[i], value)
6165 if not seqof[i].ready:
6166 seqof[i] = Integer(i)
6167 self.assertTrue(seqof.ready)
6170 pprint(seqof, big_blobs=True, with_decode_path=True)
6172 def test_spec_mismatch(self):
6173 class SeqOf(self.base_klass):
6176 seqof.append(Integer(123))
6177 with self.assertRaises(ValueError):
6178 seqof.append(Boolean(False))
6179 with self.assertRaises(ValueError):
6180 seqof[0] = Boolean(False)
6182 @given(data_strategy())
6183 def test_bounds_satisfied(self, d):
6184 class SeqOf(self.base_klass):
6186 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6187 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6188 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6189 SeqOf(value=value, bounds=(bound_min, bound_max))
6191 @given(data_strategy())
6192 def test_bounds_unsatisfied(self, d):
6193 class SeqOf(self.base_klass):
6195 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6196 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6197 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
6198 with self.assertRaises(BoundsError) as err:
6199 SeqOf(value=value, bounds=(bound_min, bound_max))
6201 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6202 SeqOf(bounds=(bound_min, bound_max)).decode(
6203 SeqOf(value).encode()
6206 value = [Boolean(True)] * d.draw(integers(
6207 min_value=bound_max + 1,
6208 max_value=bound_max + 10,
6210 with self.assertRaises(BoundsError) as err:
6211 SeqOf(value=value, bounds=(bound_min, bound_max))
6213 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6214 SeqOf(bounds=(bound_min, bound_max)).decode(
6215 SeqOf(value).encode()
6219 @given(integers(min_value=1, max_value=10))
6220 def test_out_of_bounds(self, bound_max):
6221 class SeqOf(self.base_klass):
6223 bounds = (0, bound_max)
6225 for _ in range(bound_max):
6226 seqof.append(Integer(123))
6227 with self.assertRaises(BoundsError):
6228 seqof.append(Integer(123))
6230 @given(data_strategy())
6231 def test_call(self, d):
6241 ) = d.draw(seqof_values_strategy())
6243 class SeqOf(self.base_klass):
6244 schema = schema_initial
6245 obj_initial = SeqOf(
6246 value=value_initial,
6247 bounds=bounds_initial,
6250 default=default_initial,
6251 optional=optional_initial or False,
6252 _decoded=_decoded_initial,
6263 ) = d.draw(seqof_values_strategy(
6264 schema=schema_initial,
6265 do_expl=impl_initial is None,
6267 if (default is None) and (obj_initial.default is not None):
6270 (bounds is None) and
6271 (value is not None) and
6272 (bounds_initial is not None) and
6273 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6277 (bounds is None) and
6278 (default is not None) and
6279 (bounds_initial is not None) and
6280 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6292 value_expected = default if value is None else value
6294 default_initial if value_expected is None
6297 value_expected = () if value_expected is None else value_expected
6298 self.assertEqual(obj, value_expected)
6299 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6300 self.assertEqual(obj.expl_tag, expl or expl_initial)
6303 default_initial if default is None else default,
6305 if obj.default is None:
6306 optional = optional_initial if optional is None else optional
6307 optional = False if optional is None else optional
6310 self.assertEqual(obj.optional, optional)
6312 (obj._bound_min, obj._bound_max),
6313 bounds or bounds_initial or (0, float("+inf")),
6316 @given(seqof_values_strategy())
6317 def test_copy(self, values):
6318 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6320 class SeqOf(self.base_klass):
6322 register_class(SeqOf)
6329 optional=optional or False,
6332 for copy_func in copy_funcs:
6333 obj_copied = copy_func(obj)
6334 self.assert_copied_basic_fields(obj, obj_copied)
6335 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6336 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6337 self.assertEqual(obj._value, obj_copied._value)
6341 integers(min_value=1).map(tag_encode),
6343 def test_stripped(self, values, tag_impl):
6344 class SeqOf(self.base_klass):
6345 schema = OctetString()
6346 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6347 with self.assertRaises(NotEnoughData):
6348 obj.decode(obj.encode()[:-1])
6352 integers(min_value=1).map(tag_ctxc),
6354 def test_stripped_expl(self, values, tag_expl):
6355 class SeqOf(self.base_klass):
6356 schema = OctetString()
6357 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6358 with self.assertRaises(NotEnoughData):
6359 obj.decode(obj.encode()[:-1])
6362 integers(min_value=31),
6363 integers(min_value=0),
6366 def test_bad_tag(self, tag, offset, decode_path):
6367 with self.assertRaises(DecodeError) as err:
6368 self.base_klass().decode(
6369 tag_encode(tag)[:-1],
6371 decode_path=decode_path,
6374 self.assertEqual(err.exception.offset, offset)
6375 self.assertEqual(err.exception.decode_path, decode_path)
6378 integers(min_value=128),
6379 integers(min_value=0),
6382 def test_bad_len(self, l, offset, decode_path):
6383 with self.assertRaises(DecodeError) as err:
6384 self.base_klass().decode(
6385 self.base_klass.tag_default + len_encode(l)[:-1],
6387 decode_path=decode_path,
6390 self.assertEqual(err.exception.offset, offset)
6391 self.assertEqual(err.exception.decode_path, decode_path)
6393 @given(binary(min_size=1))
6394 def test_tag_mismatch(self, impl):
6395 assume(impl != self.base_klass.tag_default)
6396 with self.assertRaises(TagMismatch):
6397 self.base_klass(impl=impl).decode(self.base_klass().encode())
6399 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6401 seqof_values_strategy(schema=Integer()),
6402 lists(integers().map(Integer)),
6403 integers(min_value=1).map(tag_ctxc),
6404 integers(min_value=0),
6407 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
6408 _, _, _, _, _, default, optional, _decoded = values
6410 class SeqOf(self.base_klass):
6420 pprint(obj, big_blobs=True, with_decode_path=True)
6421 self.assertFalse(obj.expled)
6422 obj_encoded = obj.encode()
6423 obj_expled = obj(value, expl=tag_expl)
6424 self.assertTrue(obj_expled.expled)
6426 list(obj_expled.pps())
6427 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6428 obj_expled_encoded = obj_expled.encode()
6429 ctx_copied = deepcopy(ctx_dummy)
6430 obj_decoded, tail = obj_expled.decode(
6431 obj_expled_encoded + tail_junk,
6435 self.assertDictEqual(ctx_copied, ctx_dummy)
6437 list(obj_decoded.pps())
6438 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6439 self.assertEqual(tail, tail_junk)
6440 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6441 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6442 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6443 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6445 obj_decoded.expl_llen,
6446 len(len_encode(len(obj_encoded))),
6448 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
6449 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
6452 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
6454 self.assertEqual(obj_decoded.expl_offset, offset)
6455 for obj_inner in obj_decoded:
6456 self.assertIn(obj_inner, obj_decoded)
6457 self.assertSequenceEqual(
6460 obj_inner.offset - offset:
6461 obj_inner.offset + obj_inner.tlvlen - offset
6465 t, _, lv = tag_strip(obj_encoded)
6466 _, _, v = len_decode(lv)
6467 obj_encoded_lenindef = t + LENINDEF + v + EOC
6468 with self.assertRaises(DecodeError):
6469 obj.decode(obj_encoded_lenindef)
6470 obj_decoded_lenindef, tail_lenindef = obj.decode(
6471 obj_encoded_lenindef + tail_junk,
6472 ctx={"bered": True},
6474 self.assertTrue(obj_decoded_lenindef.lenindef)
6475 self.assertTrue(obj_decoded_lenindef.bered)
6476 obj_decoded_lenindef = copy(obj_decoded_lenindef)
6477 self.assertTrue(obj_decoded_lenindef.lenindef)
6478 self.assertTrue(obj_decoded_lenindef.bered)
6479 repr(obj_decoded_lenindef)
6480 list(obj_decoded_lenindef.pps())
6481 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
6482 self.assertEqual(tail_lenindef, tail_junk)
6483 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
6484 with self.assertRaises(DecodeError):
6485 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
6486 with self.assertRaises(DecodeError):
6487 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
6489 assert_exceeding_data(
6491 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
6495 def test_bered(self):
6496 class SeqOf(self.base_klass):
6498 encoded = Boolean(False).encode()
6499 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
6500 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6501 with self.assertRaises(DecodeError):
6502 SeqOf().decode(encoded)
6503 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6504 self.assertFalse(decoded.ber_encoded)
6505 self.assertFalse(decoded.lenindef)
6506 self.assertTrue(decoded.bered)
6507 decoded = copy(decoded)
6508 self.assertFalse(decoded.ber_encoded)
6509 self.assertFalse(decoded.lenindef)
6510 self.assertTrue(decoded.bered)
6512 class SeqOf(self.base_klass):
6513 schema = OctetString()
6514 encoded = OctetString(b"whatever").encode()
6516 tag_encode(form=TagFormConstructed, num=4) +
6518 OctetString(b"whatever").encode() +
6521 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6522 with self.assertRaises(DecodeError):
6523 SeqOf().decode(encoded)
6524 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6525 self.assertFalse(decoded.ber_encoded)
6526 self.assertFalse(decoded.lenindef)
6527 self.assertTrue(decoded.bered)
6528 decoded = copy(decoded)
6529 self.assertFalse(decoded.ber_encoded)
6530 self.assertFalse(decoded.lenindef)
6531 self.assertTrue(decoded.bered)
6534 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
6535 class SeqOf(SequenceOf):
6539 def _test_symmetric_compare_objs(self, obj1, obj2):
6540 self.assertEqual(obj1, obj2)
6541 self.assertSequenceEqual(list(obj1), list(obj2))
6544 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
6549 def _test_symmetric_compare_objs(self, obj1, obj2):
6550 self.assertSetEqual(
6551 set(int(v) for v in obj1),
6552 set(int(v) for v in obj2),
6555 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6556 @given(data_strategy())
6557 def test_sorted(self, d):
6558 values = [OctetString(v) for v in d.draw(lists(binary()))]
6561 schema = OctetString()
6563 seq_encoded = seq.encode()
6564 seq_decoded, _ = seq.decode(seq_encoded)
6565 self.assertSequenceEqual(
6566 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6567 b"".join(sorted([v.encode() for v in values])),
6570 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6571 @given(data_strategy())
6572 def test_unsorted(self, d):
6573 values = [OctetString(v).encode() for v in d.draw(sets(
6574 binary(min_size=1, max_size=5),
6578 values = d.draw(permutations(values))
6579 assume(values != sorted(values))
6580 encoded = b"".join(values)
6581 seq_encoded = b"".join((
6583 len_encode(len(encoded)),
6588 schema = OctetString()
6590 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6591 seq.decode(seq_encoded)
6593 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6594 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6595 self.assertTrue(seq_decoded.ber_encoded)
6596 self.assertTrue(seq_decoded.bered)
6597 seq_decoded = copy(seq_decoded)
6598 self.assertTrue(seq_decoded.ber_encoded)
6599 self.assertTrue(seq_decoded.bered)
6600 self.assertSequenceEqual(
6601 [obj.encode() for obj in seq_decoded],
6606 class TestGoMarshalVectors(TestCase):
6608 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6609 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6610 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6611 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6612 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6614 class Seq(Sequence):
6616 ("erste", Integer()),
6617 ("zweite", Integer(optional=True))
6620 seq["erste"] = Integer(64)
6621 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6622 seq["erste"] = Integer(0x123456)
6623 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6624 seq["erste"] = Integer(64)
6625 seq["zweite"] = Integer(65)
6626 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6628 class NestedSeq(Sequence):
6632 seq["erste"] = Integer(127)
6633 seq["zweite"] = None
6634 nested = NestedSeq()
6635 nested["nest"] = seq
6636 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6638 self.assertSequenceEqual(
6639 OctetString(b"\x01\x02\x03").encode(),
6640 hexdec("0403010203"),
6643 class Seq(Sequence):
6645 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6648 seq["erste"] = Integer(64)
6649 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6651 class Seq(Sequence):
6653 ("erste", Integer(expl=tag_ctxc(5))),
6656 seq["erste"] = Integer(64)
6657 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6659 class Seq(Sequence):
6662 impl=tag_encode(0, klass=TagClassContext),
6667 seq["erste"] = Null()
6668 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6670 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6672 self.assertSequenceEqual(
6673 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6674 hexdec("170d3730303130313030303030305a"),
6676 self.assertSequenceEqual(
6677 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6678 hexdec("170d3039313131353232353631365a"),
6680 self.assertSequenceEqual(
6681 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6682 hexdec("180f32313030303430353132303130315a"),
6685 class Seq(Sequence):
6687 ("erste", GeneralizedTime()),
6690 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6691 self.assertSequenceEqual(
6693 hexdec("3011180f32303039313131353232353631365a"),
6696 self.assertSequenceEqual(
6697 BitString((1, b"\x80")).encode(),
6700 self.assertSequenceEqual(
6701 BitString((12, b"\x81\xF0")).encode(),
6702 hexdec("03030481f0"),
6705 self.assertSequenceEqual(
6706 ObjectIdentifier("1.2.3.4").encode(),
6707 hexdec("06032a0304"),
6709 self.assertSequenceEqual(
6710 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6711 hexdec("06092a864888932d010105"),
6713 self.assertSequenceEqual(
6714 ObjectIdentifier("2.100.3").encode(),
6715 hexdec("0603813403"),
6718 self.assertSequenceEqual(
6719 PrintableString("test").encode(),
6720 hexdec("130474657374"),
6722 self.assertSequenceEqual(
6723 PrintableString("x" * 127).encode(),
6724 hexdec("137F" + "78" * 127),
6726 self.assertSequenceEqual(
6727 PrintableString("x" * 128).encode(),
6728 hexdec("138180" + "78" * 128),
6730 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6732 class Seq(Sequence):
6734 ("erste", IA5String()),
6737 seq["erste"] = IA5String("test")
6738 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6740 class Seq(Sequence):
6742 ("erste", PrintableString()),
6745 seq["erste"] = PrintableString("test")
6746 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6747 # Asterisk is actually not allowable
6748 PrintableString._allowable_chars |= set(b"*")
6749 seq["erste"] = PrintableString("test*")
6750 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6751 PrintableString._allowable_chars -= set(b"*")
6753 class Seq(Sequence):
6755 ("erste", Any(optional=True)),
6756 ("zweite", Integer()),
6759 seq["zweite"] = Integer(64)
6760 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6765 seq.append(Integer(10))
6766 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6768 class _SeqOf(SequenceOf):
6769 schema = PrintableString()
6771 class SeqOf(SequenceOf):
6774 _seqof.append(PrintableString("1"))
6776 seqof.append(_seqof)
6777 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6779 class Seq(Sequence):
6781 ("erste", Integer(default=1)),
6784 seq["erste"] = Integer(0)
6785 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6786 seq["erste"] = Integer(1)
6787 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6788 seq["erste"] = Integer(2)
6789 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6792 class TestPP(TestCase):
6793 @given(data_strategy())
6794 def test_oid_printing(self, d):
6796 str(ObjectIdentifier(k)): v * 2
6797 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6799 chosen = d.draw(sampled_from(sorted(oids)))
6800 chosen_id = oids[chosen]
6801 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6802 self.assertNotIn(chosen_id, pp_console_row(pp))
6805 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6809 class TestAutoAddSlots(TestCase):
6811 class Inher(Integer):
6814 with self.assertRaises(AttributeError):
6816 inher.unexistent = "whatever"
6819 class TestOIDDefines(TestCase):
6820 @given(data_strategy())
6821 def runTest(self, d):
6822 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6823 value_name_chosen = d.draw(sampled_from(value_names))
6825 ObjectIdentifier(oid)
6826 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6828 oid_chosen = d.draw(sampled_from(oids))
6829 values = d.draw(lists(
6831 min_size=len(value_names),
6832 max_size=len(value_names),
6834 for definable_class in (Any, OctetString, BitString):
6836 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6837 oid: Integer() for oid in oids[:-1]
6840 for i, value_name in enumerate(value_names):
6841 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
6843 class Seq(Sequence):
6846 for value_name, value in zip(value_names, values):
6847 seq[value_name] = definable_class(Integer(value).encode())
6848 seq["type"] = oid_chosen
6849 seq, _ = Seq().decode(seq.encode())
6850 for value_name in value_names:
6851 if value_name == value_name_chosen:
6853 self.assertIsNone(seq[value_name].defined)
6854 if value_name_chosen in oids[:-1]:
6855 self.assertIsNotNone(seq[value_name_chosen].defined)
6856 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6857 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6860 pprint(seq, big_blobs=True, with_decode_path=True)
6863 class TestDefinesByPath(TestCase):
6864 def test_generated(self):
6865 class Seq(Sequence):
6867 ("type", ObjectIdentifier()),
6868 ("value", OctetString(expl=tag_ctxc(123))),
6871 class SeqInner(Sequence):
6873 ("typeInner", ObjectIdentifier()),
6874 ("valueInner", Any()),
6877 class PairValue(SetOf):
6880 class Pair(Sequence):
6882 ("type", ObjectIdentifier()),
6883 ("value", PairValue()),
6886 class Pairs(SequenceOf):
6893 type_octet_stringed,
6895 ObjectIdentifier(oid)
6896 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6898 seq_integered = Seq()
6899 seq_integered["type"] = type_integered
6900 seq_integered["value"] = OctetString(Integer(123).encode())
6901 seq_integered_raw = seq_integered.encode()
6905 (type_octet_stringed, OctetString(b"whatever")),
6906 (type_integered, Integer(123)),
6907 (type_octet_stringed, OctetString(b"whenever")),
6908 (type_integered, Integer(234)),
6910 for t, v in pairs_input:
6913 ("value", PairValue((Any(v),))),
6915 seq_inner = SeqInner()
6916 seq_inner["typeInner"] = type_innered
6917 seq_inner["valueInner"] = Any(pairs)
6918 seq_sequenced = Seq()
6919 seq_sequenced["type"] = type_sequenced
6920 seq_sequenced["value"] = OctetString(seq_inner.encode())
6921 seq_sequenced_raw = seq_sequenced.encode()
6923 list(seq_sequenced.pps())
6924 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6926 defines_by_path = []
6927 ctx_copied = deepcopy(ctx_dummy)
6928 seq_integered, _ = Seq().decode(
6932 self.assertDictEqual(ctx_copied, ctx_dummy)
6933 self.assertIsNone(seq_integered["value"].defined)
6934 defines_by_path.append(
6935 (("type",), ((("value",), {
6936 type_integered: Integer(),
6937 type_sequenced: SeqInner(),
6940 ctx_copied["defines_by_path"] = defines_by_path
6941 seq_integered, _ = Seq().decode(
6945 del ctx_copied["defines_by_path"]
6946 self.assertDictEqual(ctx_copied, ctx_dummy)
6947 self.assertIsNotNone(seq_integered["value"].defined)
6948 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6949 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6950 self.assertTrue(seq_integered_raw[
6951 seq_integered["value"].defined[1].offset:
6952 ].startswith(Integer(123).encode()))
6954 list(seq_integered.pps())
6955 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6957 ctx_copied["defines_by_path"] = defines_by_path
6958 seq_sequenced, _ = Seq().decode(
6962 del ctx_copied["defines_by_path"]
6963 self.assertDictEqual(ctx_copied, ctx_dummy)
6964 self.assertIsNotNone(seq_sequenced["value"].defined)
6965 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6966 seq_inner = seq_sequenced["value"].defined[1]
6967 self.assertIsNone(seq_inner["valueInner"].defined)
6969 list(seq_sequenced.pps())
6970 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6972 defines_by_path.append((
6973 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6974 ((("valueInner",), {type_innered: Pairs()}),),
6976 ctx_copied["defines_by_path"] = defines_by_path
6977 seq_sequenced, _ = Seq().decode(
6981 del ctx_copied["defines_by_path"]
6982 self.assertDictEqual(ctx_copied, ctx_dummy)
6983 self.assertIsNotNone(seq_sequenced["value"].defined)
6984 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6985 seq_inner = seq_sequenced["value"].defined[1]
6986 self.assertIsNotNone(seq_inner["valueInner"].defined)
6987 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6988 pairs = seq_inner["valueInner"].defined[1]
6990 self.assertIsNone(pair["value"][0].defined)
6992 list(seq_sequenced.pps())
6993 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6995 defines_by_path.append((
6998 DecodePathDefBy(type_sequenced),
7000 DecodePathDefBy(type_innered),
7005 type_integered: Integer(),
7006 type_octet_stringed: OctetString(),
7009 ctx_copied["defines_by_path"] = defines_by_path
7010 seq_sequenced, _ = Seq().decode(
7014 del ctx_copied["defines_by_path"]
7015 self.assertDictEqual(ctx_copied, ctx_dummy)
7016 self.assertIsNotNone(seq_sequenced["value"].defined)
7017 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7018 seq_inner = seq_sequenced["value"].defined[1]
7019 self.assertIsNotNone(seq_inner["valueInner"].defined)
7020 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7021 pairs_got = seq_inner["valueInner"].defined[1]
7022 for pair_input, pair_got in zip(pairs_input, pairs_got):
7023 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7024 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7026 list(seq_sequenced.pps())
7027 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7029 @given(oid_strategy(), integers())
7030 def test_simple(self, oid, tgt):
7031 class Inner(Sequence):
7033 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7034 ObjectIdentifier(oid): Integer(),
7038 class Outer(Sequence):
7041 ("tgt", OctetString()),
7045 inner["oid"] = ObjectIdentifier(oid)
7047 outer["inner"] = inner
7048 outer["tgt"] = OctetString(Integer(tgt).encode())
7049 decoded, _ = Outer().decode(outer.encode())
7050 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7052 def test_remaining_data(self):
7053 oid = ObjectIdentifier("1.2.3")
7054 class Seq(Sequence):
7056 ("oid", ObjectIdentifier(defines=((("tgt",), {
7059 ("tgt", OctetString()),
7064 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7066 with assertRaisesRegex(self, DecodeError, "remaining data"):
7067 Seq().decode(seq.encode())
7069 def test_remaining_data_seqof(self):
7070 oid = ObjectIdentifier("1.2.3")
7072 schema = OctetString()
7074 class Seq(Sequence):
7076 ("oid", ObjectIdentifier(defines=((("tgt",), {
7084 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7086 with assertRaisesRegex(self, DecodeError, "remaining data"):
7087 Seq().decode(seq.encode())
7090 class TestAbsDecodePath(TestCase):
7092 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7093 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7095 def test_concat(self, decode_path, rel_path):
7096 dp = abs_decode_path(decode_path, rel_path)
7097 self.assertSequenceEqual(dp, decode_path + rel_path)
7101 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7102 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7104 def test_abs(self, decode_path, rel_path):
7105 self.assertSequenceEqual(
7106 abs_decode_path(decode_path, ("/",) + rel_path),
7111 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7112 integers(min_value=1, max_value=3),
7113 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7115 def test_dots(self, decode_path, number_of_dots, rel_path):
7116 self.assertSequenceEqual(
7117 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7118 decode_path[:-number_of_dots] + rel_path,
7122 class TestStrictDefaultExistence(TestCase):
7123 @given(data_strategy())
7124 def runTest(self, d):
7125 count = d.draw(integers(min_value=1, max_value=10))
7126 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7128 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7129 for i in range(count)
7131 for klass in (Sequence, Set):
7135 for i in range(count):
7136 seq["int%d" % i] = Integer(123)
7138 chosen_choice = "int%d" % chosen
7139 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7140 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
7142 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7143 self.assertTrue(decoded.ber_encoded)
7144 self.assertTrue(decoded.bered)
7145 decoded = copy(decoded)
7146 self.assertTrue(decoded.ber_encoded)
7147 self.assertTrue(decoded.bered)
7148 decoded, _ = seq.decode(raw, ctx={"bered": True})
7149 self.assertTrue(decoded.ber_encoded)
7150 self.assertTrue(decoded.bered)
7151 decoded = copy(decoded)
7152 self.assertTrue(decoded.ber_encoded)
7153 self.assertTrue(decoded.bered)
7156 class TestX690PrefixedType(TestCase):
7158 self.assertSequenceEqual(
7159 VisibleString("Jones").encode(),
7160 hexdec("1A054A6F6E6573"),
7162 self.assertSequenceEqual(
7165 impl=tag_encode(3, klass=TagClassApplication),
7167 hexdec("43054A6F6E6573"),
7169 self.assertSequenceEqual(
7173 impl=tag_encode(3, klass=TagClassApplication),
7177 hexdec("A20743054A6F6E6573"),
7179 self.assertSequenceEqual(
7183 impl=tag_encode(3, klass=TagClassApplication),
7185 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7187 hexdec("670743054A6F6E6573"),
7189 self.assertSequenceEqual(
7190 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7191 hexdec("82054A6F6E6573"),
7195 class TestExplOOB(TestCase):
7197 expl = tag_ctxc(123)
7198 raw = Integer(123).encode() + Integer(234).encode()
7199 raw = b"".join((expl, len_encode(len(raw)), raw))
7200 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
7201 Integer(expl=expl).decode(raw)
7202 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7205 class TestPickleDifferentVersion(TestCase):
7207 pickled = pickle_dumps(Integer(123), pickle_proto)
7209 version_orig = pyderasn.__version__
7210 pyderasn.__version__ += "different"
7211 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
7212 pickle_loads(pickled)
7213 pyderasn.__version__ = version_orig
7214 pickle_loads(pickled)