2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2018 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, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from datetime import datetime
20 from string import ascii_letters
21 from string import digits
22 from string import printable
23 from string import whitespace
24 from unittest import TestCase
26 from hypothesis import assume
27 from hypothesis import given
28 from hypothesis import settings
29 from hypothesis.strategies import binary
30 from hypothesis.strategies import booleans
31 from hypothesis.strategies import composite
32 from hypothesis.strategies import data as data_strategy
33 from hypothesis.strategies import datetimes
34 from hypothesis.strategies import dictionaries
35 from hypothesis.strategies import integers
36 from hypothesis.strategies import just
37 from hypothesis.strategies import lists
38 from hypothesis.strategies import none
39 from hypothesis.strategies import one_of
40 from hypothesis.strategies import permutations
41 from hypothesis.strategies import sampled_from
42 from hypothesis.strategies import sets
43 from hypothesis.strategies import text
44 from hypothesis.strategies import tuples
45 from six import assertRaisesRegex
46 from six import binary_type
47 from six import byte2int
48 from six import indexbytes
49 from six import int2byte
50 from six import iterbytes
52 from six import text_type
53 from six import unichr as six_unichr
55 from pyderasn import _pp
56 from pyderasn import abs_decode_path
57 from pyderasn import Any
58 from pyderasn import BitString
59 from pyderasn import BMPString
60 from pyderasn import Boolean
61 from pyderasn import BoundsError
62 from pyderasn import Choice
63 from pyderasn import DecodeError
64 from pyderasn import DecodePathDefBy
65 from pyderasn import Enumerated
66 from pyderasn import EOC
67 from pyderasn import EOC_LEN
68 from pyderasn import GeneralizedTime
69 from pyderasn import GeneralString
70 from pyderasn import GraphicString
71 from pyderasn import hexdec
72 from pyderasn import hexenc
73 from pyderasn import IA5String
74 from pyderasn import Integer
75 from pyderasn import InvalidLength
76 from pyderasn import InvalidOID
77 from pyderasn import InvalidValueType
78 from pyderasn import len_decode
79 from pyderasn import len_encode
80 from pyderasn import LENINDEF
81 from pyderasn import NotEnoughData
82 from pyderasn import Null
83 from pyderasn import NumericString
84 from pyderasn import ObjectIdentifier
85 from pyderasn import ObjNotReady
86 from pyderasn import ObjUnknown
87 from pyderasn import OctetString
88 from pyderasn import pp_console_row
89 from pyderasn import pprint
90 from pyderasn import PrintableString
91 from pyderasn import Sequence
92 from pyderasn import SequenceOf
93 from pyderasn import Set
94 from pyderasn import SetOf
95 from pyderasn import tag_ctxc
96 from pyderasn import tag_ctxp
97 from pyderasn import tag_decode
98 from pyderasn import tag_encode
99 from pyderasn import tag_strip
100 from pyderasn import TagClassApplication
101 from pyderasn import TagClassContext
102 from pyderasn import TagClassPrivate
103 from pyderasn import TagClassUniversal
104 from pyderasn import TagFormConstructed
105 from pyderasn import TagFormPrimitive
106 from pyderasn import TagMismatch
107 from pyderasn import TeletexString
108 from pyderasn import UniversalString
109 from pyderasn import UTCTime
110 from pyderasn import UTF8String
111 from pyderasn import VideotexString
112 from pyderasn import VisibleString
115 settings.register_profile("local", settings(
118 settings.load_profile("local")
119 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
121 tag_classes = sampled_from((
127 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
128 decode_path_strat = lists(integers(), max_size=3).map(
129 lambda decode_path: tuple(str(dp) for dp in decode_path)
133 class TestHex(TestCase):
135 def test_symmetric(self, data):
136 self.assertEqual(hexdec(hexenc(data)), data)
139 class TestTagCoder(TestCase):
140 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
144 integers(min_value=0, max_value=30),
147 def test_short(self, klass, form, num, junk):
148 raw = tag_encode(klass=klass, form=form, num=num)
149 self.assertEqual(tag_decode(raw), (klass, form, num))
150 self.assertEqual(len(raw), 1)
152 byte2int(tag_encode(klass=klass, form=form, num=0)),
153 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
155 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
156 self.assertSequenceEqual(stripped.tobytes(), raw)
157 self.assertEqual(tlen, len(raw))
158 self.assertSequenceEqual(tail, junk)
160 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
164 integers(min_value=31),
167 def test_long(self, klass, form, num, junk):
168 raw = tag_encode(klass=klass, form=form, num=num)
169 self.assertEqual(tag_decode(raw), (klass, form, num))
170 self.assertGreater(len(raw), 1)
172 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
175 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
176 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
177 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
178 self.assertSequenceEqual(stripped.tobytes(), raw)
179 self.assertEqual(tlen, len(raw))
180 self.assertSequenceEqual(tail, junk)
182 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
183 @given(integers(min_value=31))
184 def test_unfinished_tag(self, num):
185 raw = bytearray(tag_encode(num=num))
186 for i in range(1, len(raw)):
188 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
189 tag_strip(bytes(raw))
191 def test_go_vectors_valid(self):
192 for data, (eklass, etag, elen, eform) in (
193 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
194 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
195 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
196 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
197 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
198 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
199 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
200 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
201 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
202 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
204 tag, _, len_encoded = tag_strip(memoryview(data))
205 klass, form, num = tag_decode(tag)
206 _len, _, tail = len_decode(len_encoded)
207 self.assertSequenceEqual(tail, b"")
208 self.assertEqual(klass, eklass)
209 self.assertEqual(num, etag)
210 self.assertEqual(_len, elen)
211 self.assertEqual(form, eform)
213 def test_go_vectors_invalid(self):
221 with self.assertRaises(DecodeError):
222 _, _, len_encoded = tag_strip(memoryview(data))
223 len_decode(len_encoded)
226 integers(min_value=0, max_value=127),
227 integers(min_value=0, max_value=2),
229 def test_long_instead_of_short(self, l, dummy_num):
230 octets = (b"\x00" * dummy_num) + int2byte(l)
231 octets = int2byte((dummy_num + 1) | 0x80) + octets
232 with self.assertRaises(DecodeError):
236 class TestLenCoder(TestCase):
237 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
239 integers(min_value=0, max_value=127),
242 def test_short(self, l, junk):
243 raw = len_encode(l) + junk
244 decoded, llen, tail = len_decode(memoryview(raw))
245 self.assertEqual(decoded, l)
246 self.assertEqual(llen, 1)
247 self.assertEqual(len(raw), 1 + len(junk))
248 self.assertEqual(tail.tobytes(), junk)
250 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
252 integers(min_value=128),
255 def test_long(self, l, junk):
256 raw = len_encode(l) + junk
257 decoded, llen, tail = len_decode(memoryview(raw))
258 self.assertEqual(decoded, l)
259 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
260 self.assertEqual(llen, len(raw) - len(junk))
261 self.assertNotEqual(indexbytes(raw, 1), 0)
262 self.assertSequenceEqual(tail.tobytes(), junk)
264 def test_empty(self):
265 with self.assertRaises(NotEnoughData):
268 @given(integers(min_value=128))
269 def test_stripped(self, _len):
270 with self.assertRaises(NotEnoughData):
271 len_decode(len_encode(_len)[:-1])
274 text_printable = text(alphabet=printable, min_size=1)
278 def text_letters(draw):
279 result = draw(text(alphabet=ascii_letters, min_size=1))
281 result = result.encode("ascii")
285 class CommonMixin(object):
286 def test_tag_default(self):
287 obj = self.base_klass()
288 self.assertEqual(obj.tag, obj.tag_default)
290 def test_simultaneous_impl_expl(self):
291 with self.assertRaises(ValueError):
292 self.base_klass(impl=b"whatever", expl=b"whenever")
294 @given(binary(min_size=1), integers(), integers(), integers())
295 def test_decoded(self, impl, offset, llen, vlen):
296 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
297 self.assertEqual(obj.offset, offset)
298 self.assertEqual(obj.llen, llen)
299 self.assertEqual(obj.vlen, vlen)
300 self.assertEqual(obj.tlen, len(impl))
301 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
303 @given(binary(min_size=1))
304 def test_impl_inherited(self, impl_tag):
305 class Inherited(self.base_klass):
308 self.assertSequenceEqual(obj.impl, impl_tag)
309 self.assertFalse(obj.expled)
312 def test_expl_inherited(self, expl_tag):
313 class Inherited(self.base_klass):
316 self.assertSequenceEqual(obj.expl, expl_tag)
317 self.assertTrue(obj.expled)
319 def assert_copied_basic_fields(self, obj, obj_copied):
320 self.assertEqual(obj, obj_copied)
321 self.assertSequenceEqual(obj.tag, obj_copied.tag)
322 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
323 self.assertEqual(obj.default, obj_copied.default)
324 self.assertEqual(obj.optional, obj_copied.optional)
325 self.assertEqual(obj.offset, obj_copied.offset)
326 self.assertEqual(obj.llen, obj_copied.llen)
327 self.assertEqual(obj.vlen, obj_copied.vlen)
331 def boolean_values_strategy(draw, do_expl=False):
332 value = draw(one_of(none(), booleans()))
336 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
338 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
339 default = draw(one_of(none(), booleans()))
340 optional = draw(one_of(none(), booleans()))
342 draw(integers(min_value=0)),
343 draw(integers(min_value=0)),
344 draw(integers(min_value=0)),
346 return (value, impl, expl, default, optional, _decoded)
349 class BooleanInherited(Boolean):
353 class TestBoolean(CommonMixin, TestCase):
356 def test_invalid_value_type(self):
357 with self.assertRaises(InvalidValueType) as err:
362 def test_optional(self, optional):
363 obj = Boolean(default=Boolean(False), optional=optional)
364 self.assertTrue(obj.optional)
367 def test_ready(self, value):
369 self.assertFalse(obj.ready)
372 with self.assertRaises(ObjNotReady) as err:
376 self.assertTrue(obj.ready)
380 @given(booleans(), booleans(), binary(), binary())
381 def test_comparison(self, value1, value2, tag1, tag2):
382 for klass in (Boolean, BooleanInherited):
385 self.assertEqual(obj1 == obj2, value1 == value2)
386 self.assertEqual(obj1 != obj2, value1 != value2)
387 self.assertEqual(obj1 == bool(obj2), value1 == value2)
388 obj1 = klass(value1, impl=tag1)
389 obj2 = klass(value1, impl=tag2)
390 self.assertEqual(obj1 == obj2, tag1 == tag2)
391 self.assertEqual(obj1 != obj2, tag1 != tag2)
393 @given(data_strategy())
394 def test_call(self, d):
395 for klass in (Boolean, BooleanInherited):
403 ) = d.draw(boolean_values_strategy())
409 optional_initial or False,
419 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
420 obj = obj_initial(value, impl, expl, default, optional)
422 value_expected = default if value is None else value
424 default_initial if value_expected is None
427 self.assertEqual(obj, value_expected)
428 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
429 self.assertEqual(obj.expl_tag, expl or expl_initial)
432 default_initial if default is None else default,
434 if obj.default is None:
435 optional = optional_initial if optional is None else optional
436 optional = False if optional is None else optional
439 self.assertEqual(obj.optional, optional)
441 @given(boolean_values_strategy())
442 def test_copy(self, values):
443 for klass in (Boolean, BooleanInherited):
445 obj_copied = obj.copy()
446 self.assert_copied_basic_fields(obj, obj_copied)
450 integers(min_value=1).map(tag_encode),
452 def test_stripped(self, value, tag_impl):
453 obj = Boolean(value, impl=tag_impl)
454 with self.assertRaises(NotEnoughData):
455 obj.decode(obj.encode()[:-1])
459 integers(min_value=1).map(tag_ctxc),
461 def test_stripped_expl(self, value, tag_expl):
462 obj = Boolean(value, expl=tag_expl)
463 with self.assertRaises(NotEnoughData):
464 obj.decode(obj.encode()[:-1])
467 integers(min_value=31),
468 integers(min_value=0),
471 def test_bad_tag(self, tag, offset, decode_path):
472 with self.assertRaises(DecodeError) as err:
474 tag_encode(tag)[:-1],
476 decode_path=decode_path,
479 self.assertEqual(err.exception.offset, offset)
480 self.assertEqual(err.exception.decode_path, decode_path)
483 integers(min_value=31),
484 integers(min_value=0),
487 def test_bad_expl_tag(self, tag, offset, decode_path):
488 with self.assertRaises(DecodeError) as err:
489 Boolean(expl=Boolean.tag_default).decode(
490 tag_encode(tag)[:-1],
492 decode_path=decode_path,
495 self.assertEqual(err.exception.offset, offset)
496 self.assertEqual(err.exception.decode_path, decode_path)
499 integers(min_value=128),
500 integers(min_value=0),
503 def test_bad_len(self, l, offset, decode_path):
504 with self.assertRaises(DecodeError) as err:
506 Boolean.tag_default + len_encode(l)[:-1],
508 decode_path=decode_path,
511 self.assertEqual(err.exception.offset, offset)
512 self.assertEqual(err.exception.decode_path, decode_path)
515 integers(min_value=128),
516 integers(min_value=0),
519 def test_bad_expl_len(self, l, offset, decode_path):
520 with self.assertRaises(DecodeError) as err:
521 Boolean(expl=Boolean.tag_default).decode(
522 Boolean.tag_default + len_encode(l)[:-1],
524 decode_path=decode_path,
527 self.assertEqual(err.exception.offset, offset)
528 self.assertEqual(err.exception.decode_path, decode_path)
530 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
532 boolean_values_strategy(),
534 integers(min_value=1).map(tag_ctxc),
535 integers(min_value=0),
538 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
539 for klass in (Boolean, BooleanInherited):
540 _, _, _, default, optional, _decoded = values
549 self.assertFalse(obj.expled)
550 obj_encoded = obj.encode()
551 obj_expled = obj(value, expl=tag_expl)
552 self.assertTrue(obj_expled.expled)
555 obj_expled_encoded = obj_expled.encode()
556 obj_decoded, tail = obj_expled.decode(
557 obj_expled_encoded + tail_junk,
562 self.assertEqual(tail, tail_junk)
563 self.assertEqual(obj_decoded, obj_expled)
564 self.assertNotEqual(obj_decoded, obj)
565 self.assertEqual(bool(obj_decoded), bool(obj_expled))
566 self.assertEqual(bool(obj_decoded), bool(obj))
567 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
568 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
569 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
571 obj_decoded.expl_llen,
572 len(len_encode(len(obj_encoded))),
574 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
575 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
578 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
580 self.assertEqual(obj_decoded.expl_offset, offset)
582 @given(integers(min_value=2))
583 def test_invalid_len(self, l):
584 with self.assertRaises(InvalidLength):
585 Boolean().decode(b"".join((
591 @given(integers(min_value=0 + 1, max_value=255 - 1))
592 def test_ber_value(self, value):
593 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
594 Boolean().decode(b"".join((
599 obj, _ = Boolean().decode(
607 self.assertTrue(bool(obj))
608 self.assertTrue(obj.bered)
609 self.assertFalse(obj.lenindef)
612 integers(min_value=1).map(tag_ctxc),
613 binary().filter(lambda x: not x.startswith(EOC)),
615 def test_ber_expl_no_eoc(self, expl, junk):
616 encoded = expl + LENINDEF + Boolean(False).encode()
617 with assertRaisesRegex(self, DecodeError, "no EOC"):
618 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
619 obj, tail = Boolean(expl=expl).decode(
620 encoded + EOC + junk,
623 self.assertTrue(obj.expl_lenindef)
624 self.assertSequenceEqual(tail, junk)
627 integers(min_value=1).map(tag_ctxc),
634 def test_ber_expl(self, expl, values):
640 Boolean(value).encode() +
643 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
645 class SeqOf(SequenceOf):
646 schema = Boolean(expl=expl)
647 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
648 self.assertSequenceEqual(tail, b"")
649 self.assertSequenceEqual([bool(v) for v in seqof], values)
664 len(expl) + 1 + 3 + EOC_LEN,
675 def integer_values_strategy(draw, do_expl=False):
676 bound_min, value, default, bound_max = sorted(draw(sets(
685 _specs = draw(sets(text_letters()))
688 min_size=len(_specs),
689 max_size=len(_specs),
691 _specs = list(zip(_specs, values))
694 bounds = (bound_min, bound_max)
698 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
700 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
703 optional = draw(one_of(none(), booleans()))
705 draw(integers(min_value=0)),
706 draw(integers(min_value=0)),
707 draw(integers(min_value=0)),
709 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
712 class IntegerInherited(Integer):
716 class TestInteger(CommonMixin, TestCase):
719 def test_invalid_value_type(self):
720 with self.assertRaises(InvalidValueType) as err:
724 @given(sets(text_letters(), min_size=2))
725 def test_unknown_name(self, names_input):
726 missing = names_input.pop()
729 schema = [(n, 123) for n in names_input]
730 with self.assertRaises(ObjUnknown) as err:
734 @given(sets(text_letters(), min_size=2))
735 def test_known_name(self, names_input):
737 schema = [(n, 123) for n in names_input]
738 Int(names_input.pop())
741 def test_optional(self, optional):
742 obj = Integer(default=Integer(0), optional=optional)
743 self.assertTrue(obj.optional)
746 def test_ready(self, value):
748 self.assertFalse(obj.ready)
751 with self.assertRaises(ObjNotReady) as err:
755 self.assertTrue(obj.ready)
760 @given(integers(), integers(), binary(), binary())
761 def test_comparison(self, value1, value2, tag1, tag2):
762 for klass in (Integer, IntegerInherited):
765 self.assertEqual(obj1 == obj2, value1 == value2)
766 self.assertEqual(obj1 != obj2, value1 != value2)
767 self.assertEqual(obj1 == int(obj2), value1 == value2)
768 obj1 = klass(value1, impl=tag1)
769 obj2 = klass(value1, impl=tag2)
770 self.assertEqual(obj1 == obj2, tag1 == tag2)
771 self.assertEqual(obj1 != obj2, tag1 != tag2)
773 @given(lists(integers()))
774 def test_sorted_works(self, values):
775 self.assertSequenceEqual(
776 [int(v) for v in sorted(Integer(v) for v in values)],
780 @given(data_strategy())
781 def test_named(self, d):
782 names_input = list(d.draw(sets(text_letters(), min_size=1)))
783 values_input = list(d.draw(sets(
785 min_size=len(names_input),
786 max_size=len(names_input),
788 chosen_name = d.draw(sampled_from(names_input))
789 names_input = dict(zip(names_input, values_input))
793 _int = Int(chosen_name)
794 self.assertEqual(_int.named, chosen_name)
795 self.assertEqual(int(_int), names_input[chosen_name])
797 @given(integers(), integers(min_value=0), integers(min_value=0))
798 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
799 value = bound_min + value_delta
800 bound_max = value + bound_delta
801 Integer(value=value, bounds=(bound_min, bound_max))
803 @given(sets(integers(), min_size=3, max_size=3))
804 def test_bounds_unsatisfied(self, values):
805 values = sorted(values)
806 with self.assertRaises(BoundsError) as err:
807 Integer(value=values[0], bounds=(values[1], values[2]))
809 with self.assertRaises(BoundsError) as err:
810 Integer(value=values[2], bounds=(values[0], values[1]))
813 @given(data_strategy())
814 def test_call(self, d):
815 for klass in (Integer, IntegerInherited):
825 ) = d.draw(integer_values_strategy())
832 optional_initial or False,
845 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
846 if (default is None) and (obj_initial.default is not None):
850 (value is not None) and
851 (bounds_initial is not None) and
852 not (bounds_initial[0] <= value <= bounds_initial[1])
857 (default is not None) and
858 (bounds_initial is not None) and
859 not (bounds_initial[0] <= default <= bounds_initial[1])
862 obj = obj_initial(value, bounds, impl, expl, default, optional)
864 value_expected = default if value is None else value
866 default_initial if value_expected is None
869 self.assertEqual(obj, value_expected)
870 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
871 self.assertEqual(obj.expl_tag, expl or expl_initial)
874 default_initial if default is None else default,
876 if obj.default is None:
877 optional = optional_initial if optional is None else optional
878 optional = False if optional is None else optional
881 self.assertEqual(obj.optional, optional)
883 (obj._bound_min, obj._bound_max),
884 bounds or bounds_initial or (float("-inf"), float("+inf")),
888 {} if _specs_initial is None else dict(_specs_initial),
891 @given(integer_values_strategy())
892 def test_copy(self, values):
893 for klass in (Integer, IntegerInherited):
895 obj_copied = obj.copy()
896 self.assert_copied_basic_fields(obj, obj_copied)
897 self.assertEqual(obj.specs, obj_copied.specs)
898 self.assertEqual(obj._bound_min, obj_copied._bound_min)
899 self.assertEqual(obj._bound_max, obj_copied._bound_max)
900 self.assertEqual(obj._value, obj_copied._value)
904 integers(min_value=1).map(tag_encode),
906 def test_stripped(self, value, tag_impl):
907 obj = Integer(value, impl=tag_impl)
908 with self.assertRaises(NotEnoughData):
909 obj.decode(obj.encode()[:-1])
913 integers(min_value=1).map(tag_ctxc),
915 def test_stripped_expl(self, value, tag_expl):
916 obj = Integer(value, expl=tag_expl)
917 with self.assertRaises(NotEnoughData):
918 obj.decode(obj.encode()[:-1])
920 def test_zero_len(self):
921 with self.assertRaises(NotEnoughData):
922 Integer().decode(b"".join((
928 integers(min_value=31),
929 integers(min_value=0),
932 def test_bad_tag(self, tag, offset, decode_path):
933 with self.assertRaises(DecodeError) as err:
935 tag_encode(tag)[:-1],
937 decode_path=decode_path,
940 self.assertEqual(err.exception.offset, offset)
941 self.assertEqual(err.exception.decode_path, decode_path)
944 integers(min_value=128),
945 integers(min_value=0),
948 def test_bad_len(self, l, offset, decode_path):
949 with self.assertRaises(DecodeError) as err:
951 Integer.tag_default + len_encode(l)[:-1],
953 decode_path=decode_path,
956 self.assertEqual(err.exception.offset, offset)
957 self.assertEqual(err.exception.decode_path, decode_path)
960 sets(integers(), min_size=2, max_size=2),
961 integers(min_value=0),
964 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
965 value, bound_min = list(sorted(ints))
968 bounds = (bound_min, bound_min)
969 with self.assertRaises(DecodeError) as err:
971 Integer(value).encode(),
973 decode_path=decode_path,
976 self.assertEqual(err.exception.offset, offset)
977 self.assertEqual(err.exception.decode_path, decode_path)
979 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
981 integer_values_strategy(),
983 integers(min_value=1).map(tag_ctxc),
984 integers(min_value=0),
987 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
988 for klass in (Integer, IntegerInherited):
989 _, _, _, _, default, optional, _, _decoded = values
998 self.assertFalse(obj.expled)
999 obj_encoded = obj.encode()
1000 obj_expled = obj(value, expl=tag_expl)
1001 self.assertTrue(obj_expled.expled)
1004 obj_expled_encoded = obj_expled.encode()
1005 obj_decoded, tail = obj_expled.decode(
1006 obj_expled_encoded + tail_junk,
1011 self.assertEqual(tail, tail_junk)
1012 self.assertEqual(obj_decoded, obj_expled)
1013 self.assertNotEqual(obj_decoded, obj)
1014 self.assertEqual(int(obj_decoded), int(obj_expled))
1015 self.assertEqual(int(obj_decoded), int(obj))
1016 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1017 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1018 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1020 obj_decoded.expl_llen,
1021 len(len_encode(len(obj_encoded))),
1023 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1024 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1027 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1029 self.assertEqual(obj_decoded.expl_offset, offset)
1031 def test_go_vectors_valid(self):
1032 for data, expect in ((
1036 (b"\xff\x7f", -129),
1040 (b"\xff\x00", -256),
1044 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1045 (b"\x80\x00\x00\x00", -2147483648),
1048 Integer().decode(b"".join((
1049 Integer.tag_default,
1050 len_encode(len(data)),
1056 def test_go_vectors_invalid(self):
1061 with self.assertRaises(DecodeError):
1062 Integer().decode(b"".join((
1063 Integer.tag_default,
1064 len_encode(len(data)),
1070 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1073 if draw(booleans()):
1074 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1076 integers(min_value=0, max_value=255),
1077 min_size=len(schema),
1078 max_size=len(schema),
1080 schema = list(zip(schema, bits))
1082 def _value(value_required):
1083 if not value_required and draw(booleans()):
1085 generation_choice = 0
1087 generation_choice = draw(sampled_from((1, 2, 3)))
1088 if generation_choice == 1 or draw(booleans()):
1089 return "'%s'B" % "".join(draw(lists(
1090 sampled_from(("0", "1")),
1091 max_size=len(schema),
1093 elif generation_choice == 2 or draw(booleans()):
1094 return draw(binary(max_size=len(schema) // 8))
1095 elif generation_choice == 3 or draw(booleans()):
1096 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1098 value = _value(value_required)
1099 default = _value(value_required=False)
1103 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1105 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1106 optional = draw(one_of(none(), booleans()))
1108 draw(integers(min_value=0)),
1109 draw(integers(min_value=0)),
1110 draw(integers(min_value=0)),
1112 return (schema, value, impl, expl, default, optional, _decoded)
1115 class BitStringInherited(BitString):
1119 class TestBitString(CommonMixin, TestCase):
1120 base_klass = BitString
1122 @given(lists(booleans()))
1123 def test_b_encoding(self, bits):
1124 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1125 self.assertEqual(obj.bit_len, len(bits))
1126 self.assertSequenceEqual(list(obj), bits)
1127 for i, bit in enumerate(bits):
1128 self.assertEqual(obj[i], bit)
1130 @given(lists(booleans()))
1131 def test_out_of_bounds_bits(self, bits):
1132 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1133 for i in range(len(bits), len(bits) * 2):
1134 self.assertFalse(obj[i])
1136 def test_bad_b_encoding(self):
1137 with self.assertRaises(ValueError):
1138 BitString("'010120101'B")
1141 integers(min_value=1, max_value=255),
1142 integers(min_value=1, max_value=255),
1144 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1145 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1146 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1147 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1149 class BS(BitString):
1150 schema = (("whatever", 0),)
1151 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1152 self.assertEqual(obj.bit_len, leading_zeros + 1)
1153 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1155 def test_zero_len(self):
1156 with self.assertRaises(NotEnoughData):
1157 BitString().decode(b"".join((
1158 BitString.tag_default,
1162 def test_invalid_value_type(self):
1163 with self.assertRaises(InvalidValueType) as err:
1166 with self.assertRaises(InvalidValueType) as err:
1170 def test_obj_unknown(self):
1171 with self.assertRaises(ObjUnknown) as err:
1172 BitString(b"whatever")["whenever"]
1175 def test_get_invalid_type(self):
1176 with self.assertRaises(InvalidValueType) as err:
1177 BitString(b"whatever")[(1, 2, 3)]
1180 @given(data_strategy())
1181 def test_unknown_name(self, d):
1182 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1183 missing = _schema.pop()
1185 class BS(BitString):
1186 schema = [(n, i) for i, n in enumerate(_schema)]
1187 with self.assertRaises(ObjUnknown) as err:
1192 def test_optional(self, optional):
1193 obj = BitString(default=BitString(b""), optional=optional)
1194 self.assertTrue(obj.optional)
1197 def test_ready(self, value):
1199 self.assertFalse(obj.ready)
1202 with self.assertRaises(ObjNotReady) as err:
1205 obj = BitString(value)
1206 self.assertTrue(obj.ready)
1211 tuples(integers(min_value=0), binary()),
1212 tuples(integers(min_value=0), binary()),
1216 def test_comparison(self, value1, value2, tag1, tag2):
1217 for klass in (BitString, BitStringInherited):
1218 obj1 = klass(value1)
1219 obj2 = klass(value2)
1220 self.assertEqual(obj1 == obj2, value1 == value2)
1221 self.assertEqual(obj1 != obj2, value1 != value2)
1222 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1223 obj1 = klass(value1, impl=tag1)
1224 obj2 = klass(value1, impl=tag2)
1225 self.assertEqual(obj1 == obj2, tag1 == tag2)
1226 self.assertEqual(obj1 != obj2, tag1 != tag2)
1228 @given(data_strategy())
1229 def test_call(self, d):
1230 for klass in (BitString, BitStringInherited):
1239 ) = d.draw(bit_string_values_strategy())
1242 schema = schema_initial
1244 value=value_initial,
1247 default=default_initial,
1248 optional=optional_initial or False,
1249 _decoded=_decoded_initial,
1259 ) = d.draw(bit_string_values_strategy(
1260 schema=schema_initial,
1261 do_expl=impl_initial is None,
1270 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1271 self.assertEqual(obj.expl_tag, expl or expl_initial)
1272 if obj.default is None:
1273 optional = optional_initial if optional is None else optional
1274 optional = False if optional is None else optional
1277 self.assertEqual(obj.optional, optional)
1278 self.assertEqual(obj.specs, obj_initial.specs)
1280 @given(bit_string_values_strategy())
1281 def test_copy(self, values):
1282 for klass in (BitString, BitStringInherited):
1283 _schema, value, impl, expl, default, optional, _decoded = values
1292 optional=optional or False,
1295 obj_copied = obj.copy()
1296 self.assert_copied_basic_fields(obj, obj_copied)
1297 self.assertEqual(obj.specs, obj_copied.specs)
1298 self.assertEqual(obj._value, obj_copied._value)
1302 integers(min_value=1).map(tag_encode),
1304 def test_stripped(self, value, tag_impl):
1305 obj = BitString(value, impl=tag_impl)
1306 with self.assertRaises(NotEnoughData):
1307 obj.decode(obj.encode()[:-1])
1311 integers(min_value=1).map(tag_ctxc),
1313 def test_stripped_expl(self, value, tag_expl):
1314 obj = BitString(value, expl=tag_expl)
1315 with self.assertRaises(NotEnoughData):
1316 obj.decode(obj.encode()[:-1])
1319 integers(min_value=31),
1320 integers(min_value=0),
1323 def test_bad_tag(self, tag, offset, decode_path):
1324 with self.assertRaises(DecodeError) as err:
1326 tag_encode(tag)[:-1],
1328 decode_path=decode_path,
1331 self.assertEqual(err.exception.offset, offset)
1332 self.assertEqual(err.exception.decode_path, decode_path)
1335 integers(min_value=128),
1336 integers(min_value=0),
1339 def test_bad_len(self, l, offset, decode_path):
1340 with self.assertRaises(DecodeError) as err:
1342 BitString.tag_default + len_encode(l)[:-1],
1344 decode_path=decode_path,
1347 self.assertEqual(err.exception.offset, offset)
1348 self.assertEqual(err.exception.decode_path, decode_path)
1350 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1351 @given(data_strategy())
1352 def test_symmetric(self, d):
1361 ) = d.draw(bit_string_values_strategy(value_required=True))
1362 tail_junk = d.draw(binary(max_size=5))
1363 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1364 offset = d.draw(integers(min_value=0))
1365 for klass in (BitString, BitStringInherited):
1376 self.assertFalse(obj.expled)
1377 obj_encoded = obj.encode()
1378 obj_expled = obj(value, expl=tag_expl)
1379 self.assertTrue(obj_expled.expled)
1382 obj_expled_encoded = obj_expled.encode()
1383 obj_decoded, tail = obj_expled.decode(
1384 obj_expled_encoded + tail_junk,
1389 self.assertEqual(tail, tail_junk)
1390 self.assertEqual(obj_decoded, obj_expled)
1391 self.assertNotEqual(obj_decoded, obj)
1392 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1393 self.assertEqual(bytes(obj_decoded), bytes(obj))
1394 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1395 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1396 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1398 obj_decoded.expl_llen,
1399 len(len_encode(len(obj_encoded))),
1401 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1402 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1405 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1407 self.assertEqual(obj_decoded.expl_offset, offset)
1408 if isinstance(value, tuple):
1409 self.assertSetEqual(set(value), set(obj_decoded.named))
1413 @given(integers(min_value=1, max_value=255))
1414 def test_bad_zero_value(self, pad_size):
1415 with self.assertRaises(DecodeError):
1416 BitString().decode(b"".join((
1417 BitString.tag_default,
1422 def test_go_vectors_invalid(self):
1428 with self.assertRaises(DecodeError):
1429 BitString().decode(b"".join((
1430 BitString.tag_default,
1435 def test_go_vectors_valid(self):
1436 obj, _ = BitString().decode(b"".join((
1437 BitString.tag_default,
1441 self.assertEqual(bytes(obj), b"")
1442 self.assertEqual(obj.bit_len, 0)
1444 obj, _ = BitString().decode(b"".join((
1445 BitString.tag_default,
1449 self.assertEqual(bytes(obj), b"\x00")
1450 self.assertEqual(obj.bit_len, 1)
1452 obj = BitString((16, b"\x82\x40"))
1453 self.assertTrue(obj[0])
1454 self.assertFalse(obj[1])
1455 self.assertTrue(obj[6])
1456 self.assertTrue(obj[9])
1457 self.assertFalse(obj[17])
1460 integers(min_value=1, max_value=30),
1463 binary(min_size=1, max_size=5),
1465 binary(min_size=1, max_size=5),
1473 lists(booleans(), min_size=1),
1476 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1477 def chunk_constructed(contents):
1479 tag_encode(form=TagFormConstructed, num=3) +
1481 b"".join(BitString(content).encode() for content in contents) +
1485 payload_expected = b""
1486 bit_len_expected = 0
1487 for chunk_input in chunk_inputs:
1488 if isinstance(chunk_input, binary_type):
1489 chunks.append(BitString(chunk_input).encode())
1490 payload_expected += chunk_input
1491 bit_len_expected += len(chunk_input) * 8
1493 chunks.append(chunk_constructed(chunk_input))
1494 payload = b"".join(chunk_input)
1495 payload_expected += payload
1496 bit_len_expected += len(payload) * 8
1497 chunk_last = BitString("'%s'B" % "".join(
1498 "1" if bit else "0" for bit in chunk_last_bits
1500 payload_expected += bytes(chunk_last)
1501 bit_len_expected += chunk_last.bit_len
1502 encoded_indefinite = (
1503 tag_encode(form=TagFormConstructed, num=impl) +
1506 chunk_last.encode() +
1509 encoded_definite = (
1510 tag_encode(form=TagFormConstructed, num=impl) +
1511 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1515 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1516 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1517 for lenindef_expected, encoded in (
1518 (True, encoded_indefinite),
1519 (False, encoded_definite),
1521 obj, tail = BitString(impl=tag_encode(impl)).decode(
1523 ctx={"bered": True},
1525 self.assertSequenceEqual(tail, junk)
1526 self.assertEqual(obj.bit_len, bit_len_expected)
1527 self.assertSequenceEqual(bytes(obj), payload_expected)
1528 self.assertTrue(obj.bered)
1529 self.assertEqual(obj.lenindef, lenindef_expected)
1530 self.assertEqual(len(encoded), obj.tlvlen)
1533 integers(min_value=0),
1536 def test_ber_definite_too_short(self, offset, decode_path):
1537 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1539 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1541 decode_path=decode_path,
1542 ctx={"bered": True},
1544 self.assertEqual(err.exception.decode_path, decode_path)
1545 self.assertEqual(err.exception.offset, offset)
1548 integers(min_value=0),
1551 def test_ber_definite_no_data(self, offset, decode_path):
1552 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1554 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1556 decode_path=decode_path,
1557 ctx={"bered": True},
1559 self.assertEqual(err.exception.decode_path, decode_path)
1560 self.assertEqual(err.exception.offset, offset)
1563 integers(min_value=0),
1565 integers(min_value=1, max_value=3),
1567 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1568 bs = BitString(b"data").encode()
1569 with self.assertRaises(NotEnoughData) as err:
1571 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1573 decode_path=decode_path,
1574 ctx={"bered": True},
1576 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1577 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1580 integers(min_value=0),
1582 integers(min_value=1, max_value=3),
1584 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1585 bs = BitString(b"data").encode()
1586 bs_longer = BitString(b"data-longer").encode()
1587 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1590 tag_encode(3, form=TagFormConstructed) +
1591 len_encode((chunks + 1) * len(bs)) +
1596 decode_path=decode_path,
1597 ctx={"bered": True},
1599 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1600 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1603 integers(min_value=0),
1606 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1607 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1609 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1611 decode_path=decode_path,
1612 ctx={"bered": True},
1614 self.assertEqual(err.exception.decode_path, decode_path)
1615 self.assertEqual(err.exception.offset, offset)
1617 @given(data_strategy())
1618 def test_ber_indefinite_not_multiple(self, d):
1619 bs_short = BitString("'A'H").encode()
1620 bs_full = BitString("'AA'H").encode()
1621 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1622 chunks.append(bs_short)
1623 d.draw(permutations(chunks))
1624 chunks.append(bs_short)
1625 offset = d.draw(integers(min_value=0))
1626 decode_path = d.draw(decode_path_strat)
1627 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1630 tag_encode(3, form=TagFormConstructed) +
1636 decode_path=decode_path,
1637 ctx={"bered": True},
1640 err.exception.decode_path,
1641 decode_path + (str(chunks.index(bs_short)),),
1644 err.exception.offset,
1645 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1648 def test_x690_vector(self):
1649 vector = BitString("'0A3B5F291CD'H")
1650 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1651 self.assertSequenceEqual(tail, b"")
1652 self.assertEqual(obj, vector)
1653 obj, tail = BitString().decode(
1654 hexdec("23800303000A3B0305045F291CD00000"),
1655 ctx={"bered": True},
1657 self.assertSequenceEqual(tail, b"")
1658 self.assertEqual(obj, vector)
1659 self.assertTrue(obj.bered)
1660 self.assertTrue(obj.lenindef)
1664 def octet_string_values_strategy(draw, do_expl=False):
1665 bound_min, bound_max = sorted(draw(sets(
1666 integers(min_value=0, max_value=1 << 7),
1670 value = draw(one_of(
1672 binary(min_size=bound_min, max_size=bound_max),
1674 default = draw(one_of(
1676 binary(min_size=bound_min, max_size=bound_max),
1679 if draw(booleans()):
1680 bounds = (bound_min, bound_max)
1684 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1686 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1687 optional = draw(one_of(none(), booleans()))
1689 draw(integers(min_value=0)),
1690 draw(integers(min_value=0)),
1691 draw(integers(min_value=0)),
1693 return (value, bounds, impl, expl, default, optional, _decoded)
1696 class OctetStringInherited(OctetString):
1700 class TestOctetString(CommonMixin, TestCase):
1701 base_klass = OctetString
1703 def test_invalid_value_type(self):
1704 with self.assertRaises(InvalidValueType) as err:
1705 OctetString(text_type(123))
1709 def test_optional(self, optional):
1710 obj = OctetString(default=OctetString(b""), optional=optional)
1711 self.assertTrue(obj.optional)
1714 def test_ready(self, value):
1716 self.assertFalse(obj.ready)
1719 with self.assertRaises(ObjNotReady) as err:
1722 obj = OctetString(value)
1723 self.assertTrue(obj.ready)
1727 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1728 def test_comparison(self, value1, value2, tag1, tag2):
1729 for klass in (OctetString, OctetStringInherited):
1730 obj1 = klass(value1)
1731 obj2 = klass(value2)
1732 self.assertEqual(obj1 == obj2, value1 == value2)
1733 self.assertEqual(obj1 != obj2, value1 != value2)
1734 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1735 obj1 = klass(value1, impl=tag1)
1736 obj2 = klass(value1, impl=tag2)
1737 self.assertEqual(obj1 == obj2, tag1 == tag2)
1738 self.assertEqual(obj1 != obj2, tag1 != tag2)
1740 @given(lists(binary()))
1741 def test_sorted_works(self, values):
1742 self.assertSequenceEqual(
1743 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1747 @given(data_strategy())
1748 def test_bounds_satisfied(self, d):
1749 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1750 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1751 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1752 OctetString(value=value, bounds=(bound_min, bound_max))
1754 @given(data_strategy())
1755 def test_bounds_unsatisfied(self, d):
1756 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1757 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1758 value = d.draw(binary(max_size=bound_min - 1))
1759 with self.assertRaises(BoundsError) as err:
1760 OctetString(value=value, bounds=(bound_min, bound_max))
1762 value = d.draw(binary(min_size=bound_max + 1))
1763 with self.assertRaises(BoundsError) as err:
1764 OctetString(value=value, bounds=(bound_min, bound_max))
1767 @given(data_strategy())
1768 def test_call(self, d):
1769 for klass in (OctetString, OctetStringInherited):
1778 ) = d.draw(octet_string_values_strategy())
1779 obj_initial = klass(
1785 optional_initial or False,
1796 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1797 if (default is None) and (obj_initial.default is not None):
1800 (bounds is None) and
1801 (value is not None) and
1802 (bounds_initial is not None) and
1803 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1807 (bounds is None) and
1808 (default is not None) and
1809 (bounds_initial is not None) and
1810 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1813 obj = obj_initial(value, bounds, impl, expl, default, optional)
1815 value_expected = default if value is None else value
1817 default_initial if value_expected is None
1820 self.assertEqual(obj, value_expected)
1821 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1822 self.assertEqual(obj.expl_tag, expl or expl_initial)
1825 default_initial if default is None else default,
1827 if obj.default is None:
1828 optional = optional_initial if optional is None else optional
1829 optional = False if optional is None else optional
1832 self.assertEqual(obj.optional, optional)
1834 (obj._bound_min, obj._bound_max),
1835 bounds or bounds_initial or (0, float("+inf")),
1838 @given(octet_string_values_strategy())
1839 def test_copy(self, values):
1840 for klass in (OctetString, OctetStringInherited):
1841 obj = klass(*values)
1842 obj_copied = obj.copy()
1843 self.assert_copied_basic_fields(obj, obj_copied)
1844 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1845 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1846 self.assertEqual(obj._value, obj_copied._value)
1850 integers(min_value=1).map(tag_encode),
1852 def test_stripped(self, value, tag_impl):
1853 obj = OctetString(value, impl=tag_impl)
1854 with self.assertRaises(NotEnoughData):
1855 obj.decode(obj.encode()[:-1])
1859 integers(min_value=1).map(tag_ctxc),
1861 def test_stripped_expl(self, value, tag_expl):
1862 obj = OctetString(value, expl=tag_expl)
1863 with self.assertRaises(NotEnoughData):
1864 obj.decode(obj.encode()[:-1])
1867 integers(min_value=31),
1868 integers(min_value=0),
1871 def test_bad_tag(self, tag, offset, decode_path):
1872 with self.assertRaises(DecodeError) as err:
1873 OctetString().decode(
1874 tag_encode(tag)[:-1],
1876 decode_path=decode_path,
1879 self.assertEqual(err.exception.offset, offset)
1880 self.assertEqual(err.exception.decode_path, decode_path)
1883 integers(min_value=128),
1884 integers(min_value=0),
1887 def test_bad_len(self, l, offset, decode_path):
1888 with self.assertRaises(DecodeError) as err:
1889 OctetString().decode(
1890 OctetString.tag_default + len_encode(l)[:-1],
1892 decode_path=decode_path,
1895 self.assertEqual(err.exception.offset, offset)
1896 self.assertEqual(err.exception.decode_path, decode_path)
1899 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1900 integers(min_value=0),
1903 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1904 value, bound_min = list(sorted(ints))
1906 class String(OctetString):
1907 bounds = (bound_min, bound_min)
1908 with self.assertRaises(DecodeError) as err:
1910 OctetString(b"\x00" * value).encode(),
1912 decode_path=decode_path,
1915 self.assertEqual(err.exception.offset, offset)
1916 self.assertEqual(err.exception.decode_path, decode_path)
1918 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1920 octet_string_values_strategy(),
1922 integers(min_value=1).map(tag_ctxc),
1923 integers(min_value=0),
1926 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1927 for klass in (OctetString, OctetStringInherited):
1928 _, _, _, _, default, optional, _decoded = values
1937 self.assertFalse(obj.expled)
1938 obj_encoded = obj.encode()
1939 obj_expled = obj(value, expl=tag_expl)
1940 self.assertTrue(obj_expled.expled)
1943 obj_expled_encoded = obj_expled.encode()
1944 obj_decoded, tail = obj_expled.decode(
1945 obj_expled_encoded + tail_junk,
1950 self.assertEqual(tail, tail_junk)
1951 self.assertEqual(obj_decoded, obj_expled)
1952 self.assertNotEqual(obj_decoded, obj)
1953 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1954 self.assertEqual(bytes(obj_decoded), bytes(obj))
1955 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1956 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1957 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1959 obj_decoded.expl_llen,
1960 len(len_encode(len(obj_encoded))),
1962 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1963 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1966 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1968 self.assertEqual(obj_decoded.expl_offset, offset)
1971 integers(min_value=1, max_value=30),
1974 binary(min_size=1, max_size=5),
1976 binary(min_size=1, max_size=5),
1986 def test_constructed(self, impl, chunk_inputs, junk):
1987 def chunk_constructed(contents):
1989 tag_encode(form=TagFormConstructed, num=4) +
1991 b"".join(OctetString(content).encode() for content in contents) +
1995 payload_expected = b""
1996 for chunk_input in chunk_inputs:
1997 if isinstance(chunk_input, binary_type):
1998 chunks.append(OctetString(chunk_input).encode())
1999 payload_expected += chunk_input
2001 chunks.append(chunk_constructed(chunk_input))
2002 payload = b"".join(chunk_input)
2003 payload_expected += payload
2004 encoded_indefinite = (
2005 tag_encode(form=TagFormConstructed, num=impl) +
2010 encoded_definite = (
2011 tag_encode(form=TagFormConstructed, num=impl) +
2012 len_encode(len(b"".join(chunks))) +
2015 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2016 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2017 for lenindef_expected, encoded in (
2018 (True, encoded_indefinite),
2019 (False, encoded_definite),
2021 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2023 ctx={"bered": True},
2025 self.assertSequenceEqual(tail, junk)
2026 self.assertSequenceEqual(bytes(obj), payload_expected)
2027 self.assertTrue(obj.bered)
2028 self.assertEqual(obj.lenindef, lenindef_expected)
2029 self.assertEqual(len(encoded), obj.tlvlen)
2032 integers(min_value=0),
2035 def test_ber_definite_too_short(self, offset, decode_path):
2036 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2037 OctetString().decode(
2038 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2040 decode_path=decode_path,
2041 ctx={"bered": True},
2043 self.assertEqual(err.exception.decode_path, decode_path)
2044 self.assertEqual(err.exception.offset, offset)
2047 integers(min_value=0),
2049 integers(min_value=1, max_value=3),
2051 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2052 bs = OctetString(b"data").encode()
2053 with self.assertRaises(NotEnoughData) as err:
2054 OctetString().decode(
2055 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2057 decode_path=decode_path,
2058 ctx={"bered": True},
2060 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2061 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2064 integers(min_value=0),
2066 integers(min_value=1, max_value=3),
2068 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2069 bs = OctetString(b"data").encode()
2070 bs_longer = OctetString(b"data-longer").encode()
2071 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2072 OctetString().decode(
2074 tag_encode(4, form=TagFormConstructed) +
2075 len_encode((chunks + 1) * len(bs)) +
2080 decode_path=decode_path,
2081 ctx={"bered": True},
2083 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2084 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2088 def null_values_strategy(draw, do_expl=False):
2092 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2094 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2095 optional = draw(one_of(none(), booleans()))
2097 draw(integers(min_value=0)),
2098 draw(integers(min_value=0)),
2099 draw(integers(min_value=0)),
2101 return (impl, expl, optional, _decoded)
2104 class NullInherited(Null):
2108 class TestNull(CommonMixin, TestCase):
2111 def test_ready(self):
2113 self.assertTrue(obj.ready)
2117 @given(binary(), binary())
2118 def test_comparison(self, tag1, tag2):
2119 for klass in (Null, NullInherited):
2120 obj1 = klass(impl=tag1)
2121 obj2 = klass(impl=tag2)
2122 self.assertEqual(obj1 == obj2, tag1 == tag2)
2123 self.assertEqual(obj1 != obj2, tag1 != tag2)
2124 self.assertNotEqual(obj1, tag2)
2126 @given(data_strategy())
2127 def test_call(self, d):
2128 for klass in (Null, NullInherited):
2134 ) = d.draw(null_values_strategy())
2135 obj_initial = klass(
2138 optional=optional_initial or False,
2139 _decoded=_decoded_initial,
2146 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2147 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2148 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2149 self.assertEqual(obj.expl_tag, expl or expl_initial)
2150 optional = optional_initial if optional is None else optional
2151 optional = False if optional is None else optional
2152 self.assertEqual(obj.optional, optional)
2154 @given(null_values_strategy())
2155 def test_copy(self, values):
2156 for klass in (Null, NullInherited):
2157 impl, expl, optional, _decoded = values
2161 optional=optional or False,
2164 obj_copied = obj.copy()
2165 self.assert_copied_basic_fields(obj, obj_copied)
2167 @given(integers(min_value=1).map(tag_encode))
2168 def test_stripped(self, tag_impl):
2169 obj = Null(impl=tag_impl)
2170 with self.assertRaises(NotEnoughData):
2171 obj.decode(obj.encode()[:-1])
2173 @given(integers(min_value=1).map(tag_ctxc))
2174 def test_stripped_expl(self, tag_expl):
2175 obj = Null(expl=tag_expl)
2176 with self.assertRaises(NotEnoughData):
2177 obj.decode(obj.encode()[:-1])
2180 integers(min_value=31),
2181 integers(min_value=0),
2184 def test_bad_tag(self, tag, offset, decode_path):
2185 with self.assertRaises(DecodeError) as err:
2187 tag_encode(tag)[:-1],
2189 decode_path=decode_path,
2192 self.assertEqual(err.exception.offset, offset)
2193 self.assertEqual(err.exception.decode_path, decode_path)
2196 integers(min_value=128),
2197 integers(min_value=0),
2200 def test_bad_len(self, l, offset, decode_path):
2201 with self.assertRaises(DecodeError) as err:
2203 Null.tag_default + len_encode(l)[:-1],
2205 decode_path=decode_path,
2208 self.assertEqual(err.exception.offset, offset)
2209 self.assertEqual(err.exception.decode_path, decode_path)
2211 @given(binary(min_size=1))
2212 def test_tag_mismatch(self, impl):
2213 assume(impl != Null.tag_default)
2214 with self.assertRaises(TagMismatch):
2215 Null(impl=impl).decode(Null().encode())
2218 null_values_strategy(),
2219 integers(min_value=1).map(tag_ctxc),
2220 integers(min_value=0),
2223 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2224 for klass in (Null, NullInherited):
2225 _, _, optional, _decoded = values
2226 obj = klass(optional=optional, _decoded=_decoded)
2229 self.assertFalse(obj.expled)
2230 obj_encoded = obj.encode()
2231 obj_expled = obj(expl=tag_expl)
2232 self.assertTrue(obj_expled.expled)
2235 obj_expled_encoded = obj_expled.encode()
2236 obj_decoded, tail = obj_expled.decode(
2237 obj_expled_encoded + tail_junk,
2242 self.assertEqual(tail, tail_junk)
2243 self.assertEqual(obj_decoded, obj_expled)
2244 self.assertNotEqual(obj_decoded, obj)
2245 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2246 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2247 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2249 obj_decoded.expl_llen,
2250 len(len_encode(len(obj_encoded))),
2252 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2253 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2256 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2258 self.assertEqual(obj_decoded.expl_offset, offset)
2260 @given(integers(min_value=1))
2261 def test_invalid_len(self, l):
2262 with self.assertRaises(InvalidLength):
2263 Null().decode(b"".join((
2270 def oid_strategy(draw):
2271 first_arc = draw(integers(min_value=0, max_value=2))
2273 if first_arc in (0, 1):
2274 second_arc = draw(integers(min_value=0, max_value=39))
2276 second_arc = draw(integers(min_value=0))
2277 other_arcs = draw(lists(integers(min_value=0)))
2278 return tuple([first_arc, second_arc] + other_arcs)
2282 def oid_values_strategy(draw, do_expl=False):
2283 value = draw(one_of(none(), oid_strategy()))
2287 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2289 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2290 default = draw(one_of(none(), oid_strategy()))
2291 optional = draw(one_of(none(), booleans()))
2293 draw(integers(min_value=0)),
2294 draw(integers(min_value=0)),
2295 draw(integers(min_value=0)),
2297 return (value, impl, expl, default, optional, _decoded)
2300 class ObjectIdentifierInherited(ObjectIdentifier):
2304 class TestObjectIdentifier(CommonMixin, TestCase):
2305 base_klass = ObjectIdentifier
2307 def test_invalid_value_type(self):
2308 with self.assertRaises(InvalidValueType) as err:
2309 ObjectIdentifier(123)
2313 def test_optional(self, optional):
2314 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2315 self.assertTrue(obj.optional)
2317 @given(oid_strategy())
2318 def test_ready(self, value):
2319 obj = ObjectIdentifier()
2320 self.assertFalse(obj.ready)
2323 with self.assertRaises(ObjNotReady) as err:
2326 obj = ObjectIdentifier(value)
2327 self.assertTrue(obj.ready)
2332 @given(oid_strategy(), oid_strategy(), binary(), binary())
2333 def test_comparison(self, value1, value2, tag1, tag2):
2334 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2335 obj1 = klass(value1)
2336 obj2 = klass(value2)
2337 self.assertEqual(obj1 == obj2, value1 == value2)
2338 self.assertEqual(obj1 != obj2, value1 != value2)
2339 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2340 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2341 obj1 = klass(value1, impl=tag1)
2342 obj2 = klass(value1, impl=tag2)
2343 self.assertEqual(obj1 == obj2, tag1 == tag2)
2344 self.assertEqual(obj1 != obj2, tag1 != tag2)
2346 @given(lists(oid_strategy()))
2347 def test_sorted_works(self, values):
2348 self.assertSequenceEqual(
2349 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2353 @given(data_strategy())
2354 def test_call(self, d):
2355 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2363 ) = d.draw(oid_values_strategy())
2364 obj_initial = klass(
2365 value=value_initial,
2368 default=default_initial,
2369 optional=optional_initial or False,
2370 _decoded=_decoded_initial,
2379 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2388 value_expected = default if value is None else value
2390 default_initial if value_expected is None
2393 self.assertEqual(obj, value_expected)
2394 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2395 self.assertEqual(obj.expl_tag, expl or expl_initial)
2398 default_initial if default is None else default,
2400 if obj.default is None:
2401 optional = optional_initial if optional is None else optional
2402 optional = False if optional is None else optional
2405 self.assertEqual(obj.optional, optional)
2407 @given(oid_values_strategy())
2408 def test_copy(self, values):
2409 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2426 obj_copied = obj.copy()
2427 self.assert_copied_basic_fields(obj, obj_copied)
2428 self.assertEqual(obj._value, obj_copied._value)
2430 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2433 integers(min_value=1).map(tag_encode),
2435 def test_stripped(self, value, tag_impl):
2436 obj = ObjectIdentifier(value, impl=tag_impl)
2437 with self.assertRaises(NotEnoughData):
2438 obj.decode(obj.encode()[:-1])
2442 integers(min_value=1).map(tag_ctxc),
2444 def test_stripped_expl(self, value, tag_expl):
2445 obj = ObjectIdentifier(value, expl=tag_expl)
2446 with self.assertRaises(NotEnoughData):
2447 obj.decode(obj.encode()[:-1])
2450 integers(min_value=31),
2451 integers(min_value=0),
2454 def test_bad_tag(self, tag, offset, decode_path):
2455 with self.assertRaises(DecodeError) as err:
2456 ObjectIdentifier().decode(
2457 tag_encode(tag)[:-1],
2459 decode_path=decode_path,
2462 self.assertEqual(err.exception.offset, offset)
2463 self.assertEqual(err.exception.decode_path, decode_path)
2466 integers(min_value=128),
2467 integers(min_value=0),
2470 def test_bad_len(self, l, offset, decode_path):
2471 with self.assertRaises(DecodeError) as err:
2472 ObjectIdentifier().decode(
2473 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2475 decode_path=decode_path,
2478 self.assertEqual(err.exception.offset, offset)
2479 self.assertEqual(err.exception.decode_path, decode_path)
2481 def test_zero_oid(self):
2482 with self.assertRaises(NotEnoughData):
2483 ObjectIdentifier().decode(
2484 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2487 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2488 @given(oid_strategy())
2489 def test_unfinished_oid(self, value):
2490 assume(list(value)[-1] > 255)
2491 obj_encoded = ObjectIdentifier(value).encode()
2492 obj, _ = ObjectIdentifier().decode(obj_encoded)
2493 data = obj_encoded[obj.tlen + obj.llen:-1]
2495 ObjectIdentifier.tag_default,
2496 len_encode(len(data)),
2499 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2502 @given(integers(min_value=0))
2503 def test_invalid_short(self, value):
2504 with self.assertRaises(InvalidOID):
2505 ObjectIdentifier((value,))
2506 with self.assertRaises(InvalidOID):
2507 ObjectIdentifier("%d" % value)
2509 @given(integers(min_value=3), integers(min_value=0))
2510 def test_invalid_first_arc(self, first_arc, second_arc):
2511 with self.assertRaises(InvalidOID):
2512 ObjectIdentifier((first_arc, second_arc))
2513 with self.assertRaises(InvalidOID):
2514 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2516 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2517 def test_invalid_second_arc(self, first_arc, second_arc):
2518 with self.assertRaises(InvalidOID):
2519 ObjectIdentifier((first_arc, second_arc))
2520 with self.assertRaises(InvalidOID):
2521 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2523 @given(text(alphabet=ascii_letters + ".", min_size=1))
2524 def test_junk(self, oid):
2525 with self.assertRaises(InvalidOID):
2526 ObjectIdentifier(oid)
2528 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2529 @given(oid_strategy())
2530 def test_validness(self, oid):
2531 obj = ObjectIdentifier(oid)
2532 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2537 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2539 oid_values_strategy(),
2541 integers(min_value=1).map(tag_ctxc),
2542 integers(min_value=0),
2545 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2546 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2547 _, _, _, default, optional, _decoded = values
2556 self.assertFalse(obj.expled)
2557 obj_encoded = obj.encode()
2558 obj_expled = obj(value, expl=tag_expl)
2559 self.assertTrue(obj_expled.expled)
2562 obj_expled_encoded = obj_expled.encode()
2563 obj_decoded, tail = obj_expled.decode(
2564 obj_expled_encoded + tail_junk,
2569 self.assertEqual(tail, tail_junk)
2570 self.assertEqual(obj_decoded, obj_expled)
2571 self.assertNotEqual(obj_decoded, obj)
2572 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2573 self.assertEqual(tuple(obj_decoded), tuple(obj))
2574 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2575 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2576 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2578 obj_decoded.expl_llen,
2579 len(len_encode(len(obj_encoded))),
2581 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2582 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2585 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2587 self.assertEqual(obj_decoded.expl_offset, offset)
2590 oid_strategy().map(ObjectIdentifier),
2591 oid_strategy().map(ObjectIdentifier),
2593 def test_add(self, oid1, oid2):
2594 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2595 for oid_to_add in (oid2, tuple(oid2)):
2596 self.assertEqual(oid1 + oid_to_add, oid_expect)
2597 with self.assertRaises(InvalidValueType):
2600 def test_go_vectors_valid(self):
2601 for data, expect in (
2603 (b"\x55\x02", (2, 5, 2)),
2604 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2605 (b"\x81\x34\x03", (2, 100, 3)),
2608 ObjectIdentifier().decode(b"".join((
2609 ObjectIdentifier.tag_default,
2610 len_encode(len(data)),
2616 def test_go_vectors_invalid(self):
2617 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2618 with self.assertRaises(DecodeError):
2619 ObjectIdentifier().decode(b"".join((
2620 Integer.tag_default,
2621 len_encode(len(data)),
2625 def test_x690_vector(self):
2627 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2628 ObjectIdentifier((2, 999, 3)),
2633 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2635 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2636 values = list(draw(sets(
2638 min_size=len(schema),
2639 max_size=len(schema),
2641 schema = list(zip(schema, values))
2642 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2646 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2648 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2649 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2650 optional = draw(one_of(none(), booleans()))
2652 draw(integers(min_value=0)),
2653 draw(integers(min_value=0)),
2654 draw(integers(min_value=0)),
2656 return (schema, value, impl, expl, default, optional, _decoded)
2659 class TestEnumerated(CommonMixin, TestCase):
2660 class EWhatever(Enumerated):
2661 schema = (("whatever", 0),)
2663 base_klass = EWhatever
2665 def test_schema_required(self):
2666 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2669 def test_invalid_value_type(self):
2670 with self.assertRaises(InvalidValueType) as err:
2671 self.base_klass((1, 2))
2674 @given(sets(text_letters(), min_size=2))
2675 def test_unknown_name(self, schema_input):
2676 missing = schema_input.pop()
2678 class E(Enumerated):
2679 schema = [(n, 123) for n in schema_input]
2680 with self.assertRaises(ObjUnknown) as err:
2685 sets(text_letters(), min_size=2),
2686 sets(integers(), min_size=2),
2688 def test_unknown_value(self, schema_input, values_input):
2690 missing_value = values_input.pop()
2691 _input = list(zip(schema_input, values_input))
2693 class E(Enumerated):
2695 with self.assertRaises(DecodeError) as err:
2700 def test_optional(self, optional):
2701 obj = self.base_klass(default="whatever", optional=optional)
2702 self.assertTrue(obj.optional)
2704 def test_ready(self):
2705 obj = self.base_klass()
2706 self.assertFalse(obj.ready)
2709 with self.assertRaises(ObjNotReady) as err:
2712 obj = self.base_klass("whatever")
2713 self.assertTrue(obj.ready)
2717 @given(integers(), integers(), binary(), binary())
2718 def test_comparison(self, value1, value2, tag1, tag2):
2719 class E(Enumerated):
2721 ("whatever0", value1),
2722 ("whatever1", value2),
2725 class EInherited(E):
2727 for klass in (E, EInherited):
2728 obj1 = klass(value1)
2729 obj2 = klass(value2)
2730 self.assertEqual(obj1 == obj2, value1 == value2)
2731 self.assertEqual(obj1 != obj2, value1 != value2)
2732 self.assertEqual(obj1 == int(obj2), value1 == value2)
2733 obj1 = klass(value1, impl=tag1)
2734 obj2 = klass(value1, impl=tag2)
2735 self.assertEqual(obj1 == obj2, tag1 == tag2)
2736 self.assertEqual(obj1 != obj2, tag1 != tag2)
2738 @given(data_strategy())
2739 def test_call(self, d):
2748 ) = d.draw(enumerated_values_strategy())
2750 class E(Enumerated):
2751 schema = schema_initial
2753 value=value_initial,
2756 default=default_initial,
2757 optional=optional_initial or False,
2758 _decoded=_decoded_initial,
2768 ) = d.draw(enumerated_values_strategy(
2769 schema=schema_initial,
2770 do_expl=impl_initial is None,
2780 value_expected = default if value is None else value
2782 default_initial if value_expected is None
2787 dict(schema_initial).get(value_expected, value_expected),
2789 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2790 self.assertEqual(obj.expl_tag, expl or expl_initial)
2793 default_initial if default is None else default,
2795 if obj.default is None:
2796 optional = optional_initial if optional is None else optional
2797 optional = False if optional is None else optional
2800 self.assertEqual(obj.optional, optional)
2801 self.assertEqual(obj.specs, dict(schema_initial))
2803 @given(enumerated_values_strategy())
2804 def test_copy(self, values):
2805 schema_input, value, impl, expl, default, optional, _decoded = values
2807 class E(Enumerated):
2808 schema = schema_input
2817 obj_copied = obj.copy()
2818 self.assert_copied_basic_fields(obj, obj_copied)
2819 self.assertEqual(obj.specs, obj_copied.specs)
2821 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2822 @given(data_strategy())
2823 def test_symmetric(self, d):
2824 schema_input, _, _, _, default, optional, _decoded = d.draw(
2825 enumerated_values_strategy(),
2827 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2828 offset = d.draw(integers(min_value=0))
2829 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2830 tail_junk = d.draw(binary(max_size=5))
2832 class E(Enumerated):
2833 schema = schema_input
2842 self.assertFalse(obj.expled)
2843 obj_encoded = obj.encode()
2844 obj_expled = obj(value, expl=tag_expl)
2845 self.assertTrue(obj_expled.expled)
2848 obj_expled_encoded = obj_expled.encode()
2849 obj_decoded, tail = obj_expled.decode(
2850 obj_expled_encoded + tail_junk,
2855 self.assertEqual(tail, tail_junk)
2856 self.assertEqual(obj_decoded, obj_expled)
2857 self.assertNotEqual(obj_decoded, obj)
2858 self.assertEqual(int(obj_decoded), int(obj_expled))
2859 self.assertEqual(int(obj_decoded), int(obj))
2860 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2861 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2862 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2864 obj_decoded.expl_llen,
2865 len(len_encode(len(obj_encoded))),
2867 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2868 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2871 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2873 self.assertEqual(obj_decoded.expl_offset, offset)
2877 def string_values_strategy(draw, alphabet, do_expl=False):
2878 bound_min, bound_max = sorted(draw(sets(
2879 integers(min_value=0, max_value=1 << 7),
2883 value = draw(one_of(
2885 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2887 default = draw(one_of(
2889 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2892 if draw(booleans()):
2893 bounds = (bound_min, bound_max)
2897 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2899 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2900 optional = draw(one_of(none(), booleans()))
2902 draw(integers(min_value=0)),
2903 draw(integers(min_value=0)),
2904 draw(integers(min_value=0)),
2906 return (value, bounds, impl, expl, default, optional, _decoded)
2909 class StringMixin(object):
2910 def test_invalid_value_type(self):
2911 with self.assertRaises(InvalidValueType) as err:
2912 self.base_klass((1, 2))
2915 def text_alphabet(self):
2916 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2917 return printable + whitespace
2921 def test_optional(self, optional):
2922 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2923 self.assertTrue(obj.optional)
2925 @given(data_strategy())
2926 def test_ready(self, d):
2927 obj = self.base_klass()
2928 self.assertFalse(obj.ready)
2932 with self.assertRaises(ObjNotReady) as err:
2935 value = d.draw(text(alphabet=self.text_alphabet()))
2936 obj = self.base_klass(value)
2937 self.assertTrue(obj.ready)
2942 @given(data_strategy())
2943 def test_comparison(self, d):
2944 value1 = d.draw(text(alphabet=self.text_alphabet()))
2945 value2 = d.draw(text(alphabet=self.text_alphabet()))
2946 tag1 = d.draw(binary(min_size=1))
2947 tag2 = d.draw(binary(min_size=1))
2948 obj1 = self.base_klass(value1)
2949 obj2 = self.base_klass(value2)
2950 self.assertEqual(obj1 == obj2, value1 == value2)
2951 self.assertEqual(obj1 != obj2, value1 != value2)
2952 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2953 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2954 obj1 = self.base_klass(value1, impl=tag1)
2955 obj2 = self.base_klass(value1, impl=tag2)
2956 self.assertEqual(obj1 == obj2, tag1 == tag2)
2957 self.assertEqual(obj1 != obj2, tag1 != tag2)
2959 @given(data_strategy())
2960 def test_bounds_satisfied(self, d):
2961 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2962 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2963 value = d.draw(text(
2964 alphabet=self.text_alphabet(),
2968 self.base_klass(value=value, bounds=(bound_min, bound_max))
2970 @given(data_strategy())
2971 def test_bounds_unsatisfied(self, d):
2972 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2973 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2974 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2975 with self.assertRaises(BoundsError) as err:
2976 self.base_klass(value=value, bounds=(bound_min, bound_max))
2978 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2979 with self.assertRaises(BoundsError) as err:
2980 self.base_klass(value=value, bounds=(bound_min, bound_max))
2983 @given(data_strategy())
2984 def test_call(self, d):
2993 ) = d.draw(string_values_strategy(self.text_alphabet()))
2994 obj_initial = self.base_klass(
3000 optional_initial or False,
3011 ) = d.draw(string_values_strategy(
3012 self.text_alphabet(),
3013 do_expl=impl_initial is None,
3015 if (default is None) and (obj_initial.default is not None):
3018 (bounds is None) and
3019 (value is not None) and
3020 (bounds_initial is not None) and
3021 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3025 (bounds is None) and
3026 (default is not None) and
3027 (bounds_initial is not None) and
3028 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3031 obj = obj_initial(value, bounds, impl, expl, default, optional)
3033 value_expected = default if value is None else value
3035 default_initial if value_expected is None
3038 self.assertEqual(obj, value_expected)
3039 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3040 self.assertEqual(obj.expl_tag, expl or expl_initial)
3043 default_initial if default is None else default,
3045 if obj.default is None:
3046 optional = optional_initial if optional is None else optional
3047 optional = False if optional is None else optional
3050 self.assertEqual(obj.optional, optional)
3052 (obj._bound_min, obj._bound_max),
3053 bounds or bounds_initial or (0, float("+inf")),
3056 @given(data_strategy())
3057 def test_copy(self, d):
3058 values = d.draw(string_values_strategy(self.text_alphabet()))
3059 obj = self.base_klass(*values)
3060 obj_copied = obj.copy()
3061 self.assert_copied_basic_fields(obj, obj_copied)
3062 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3063 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3064 self.assertEqual(obj._value, obj_copied._value)
3066 @given(data_strategy())
3067 def test_stripped(self, d):
3068 value = d.draw(text(alphabet=self.text_alphabet()))
3069 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3070 obj = self.base_klass(value, impl=tag_impl)
3071 with self.assertRaises(NotEnoughData):
3072 obj.decode(obj.encode()[:-1])
3074 @given(data_strategy())
3075 def test_stripped_expl(self, d):
3076 value = d.draw(text(alphabet=self.text_alphabet()))
3077 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3078 obj = self.base_klass(value, expl=tag_expl)
3079 with self.assertRaises(NotEnoughData):
3080 obj.decode(obj.encode()[:-1])
3083 integers(min_value=31),
3084 integers(min_value=0),
3087 def test_bad_tag(self, tag, offset, decode_path):
3088 with self.assertRaises(DecodeError) as err:
3089 self.base_klass().decode(
3090 tag_encode(tag)[:-1],
3092 decode_path=decode_path,
3095 self.assertEqual(err.exception.offset, offset)
3096 self.assertEqual(err.exception.decode_path, decode_path)
3099 integers(min_value=128),
3100 integers(min_value=0),
3103 def test_bad_len(self, l, offset, decode_path):
3104 with self.assertRaises(DecodeError) as err:
3105 self.base_klass().decode(
3106 self.base_klass.tag_default + len_encode(l)[:-1],
3108 decode_path=decode_path,
3111 self.assertEqual(err.exception.offset, offset)
3112 self.assertEqual(err.exception.decode_path, decode_path)
3115 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3116 integers(min_value=0),
3119 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3120 value, bound_min = list(sorted(ints))
3122 class String(self.base_klass):
3123 # Multiply this value by four, to satisfy UTF-32 bounds
3124 # (4 bytes per character) validation
3125 bounds = (bound_min * 4, bound_min * 4)
3126 with self.assertRaises(DecodeError) as err:
3128 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3130 decode_path=decode_path,
3133 self.assertEqual(err.exception.offset, offset)
3134 self.assertEqual(err.exception.decode_path, decode_path)
3136 @given(data_strategy())
3137 def test_symmetric(self, d):
3138 values = d.draw(string_values_strategy(self.text_alphabet()))
3139 value = d.draw(text(alphabet=self.text_alphabet()))
3140 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3141 offset = d.draw(integers(min_value=0))
3142 tail_junk = d.draw(binary(max_size=5))
3143 _, _, _, _, default, optional, _decoded = values
3144 obj = self.base_klass(
3152 self.assertFalse(obj.expled)
3153 obj_encoded = obj.encode()
3154 obj_expled = obj(value, expl=tag_expl)
3155 self.assertTrue(obj_expled.expled)
3158 obj_expled_encoded = obj_expled.encode()
3159 obj_decoded, tail = obj_expled.decode(
3160 obj_expled_encoded + tail_junk,
3165 self.assertEqual(tail, tail_junk)
3166 self.assertEqual(obj_decoded, obj_expled)
3167 self.assertNotEqual(obj_decoded, obj)
3168 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3169 self.assertEqual(bytes(obj_decoded), bytes(obj))
3170 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3171 self.assertEqual(text_type(obj_decoded), text_type(obj))
3172 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3173 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3174 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3176 obj_decoded.expl_llen,
3177 len(len_encode(len(obj_encoded))),
3179 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3180 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3183 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3185 self.assertEqual(obj_decoded.expl_offset, offset)
3188 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3189 base_klass = UTF8String
3192 class UnicodeDecodeErrorMixin(object):
3194 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3198 def test_unicode_decode_error(self, cyrillic_text):
3199 with self.assertRaises(DecodeError):
3200 self.base_klass(cyrillic_text)
3203 class TestNumericString(StringMixin, CommonMixin, TestCase):
3204 base_klass = NumericString
3206 def text_alphabet(self):
3209 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3210 def test_non_numeric(self, cyrillic_text):
3211 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3212 self.base_klass(cyrillic_text)
3215 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3216 integers(min_value=0),
3219 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3220 value, bound_min = list(sorted(ints))
3222 class String(self.base_klass):
3223 bounds = (bound_min, bound_min)
3224 with self.assertRaises(DecodeError) as err:
3226 self.base_klass(b"1" * value).encode(),
3228 decode_path=decode_path,
3231 self.assertEqual(err.exception.offset, offset)
3232 self.assertEqual(err.exception.decode_path, decode_path)
3235 class TestPrintableString(
3236 UnicodeDecodeErrorMixin,
3241 base_klass = PrintableString
3244 class TestTeletexString(
3245 UnicodeDecodeErrorMixin,
3250 base_klass = TeletexString
3253 class TestVideotexString(
3254 UnicodeDecodeErrorMixin,
3259 base_klass = VideotexString
3262 class TestIA5String(
3263 UnicodeDecodeErrorMixin,
3268 base_klass = IA5String
3271 class TestGraphicString(
3272 UnicodeDecodeErrorMixin,
3277 base_klass = GraphicString
3280 class TestVisibleString(
3281 UnicodeDecodeErrorMixin,
3286 base_klass = VisibleString
3288 def test_x690_vector(self):
3289 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3290 self.assertSequenceEqual(tail, b"")
3291 self.assertEqual(str(obj), "Jones")
3292 self.assertFalse(obj.bered)
3293 self.assertFalse(obj.lenindef)
3295 obj, tail = VisibleString().decode(
3296 hexdec("3A0904034A6F6E04026573"),
3297 ctx={"bered": True},
3299 self.assertSequenceEqual(tail, b"")
3300 self.assertEqual(str(obj), "Jones")
3301 self.assertTrue(obj.bered)
3302 self.assertFalse(obj.lenindef)
3304 obj, tail = VisibleString().decode(
3305 hexdec("3A8004034A6F6E040265730000"),
3306 ctx={"bered": True},
3308 self.assertSequenceEqual(tail, b"")
3309 self.assertEqual(str(obj), "Jones")
3310 self.assertTrue(obj.bered)
3311 self.assertTrue(obj.lenindef)
3314 class TestGeneralString(
3315 UnicodeDecodeErrorMixin,
3320 base_klass = GeneralString
3323 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3324 base_klass = UniversalString
3327 class TestBMPString(StringMixin, CommonMixin, TestCase):
3328 base_klass = BMPString
3332 def generalized_time_values_strategy(
3340 if draw(booleans()):
3341 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3343 value = value.replace(microsecond=0)
3345 if draw(booleans()):
3346 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3348 default = default.replace(microsecond=0)
3352 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3354 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3355 optional = draw(one_of(none(), booleans()))
3357 draw(integers(min_value=0)),
3358 draw(integers(min_value=0)),
3359 draw(integers(min_value=0)),
3361 return (value, impl, expl, default, optional, _decoded)
3364 class TimeMixin(object):
3365 def test_invalid_value_type(self):
3366 with self.assertRaises(InvalidValueType) as err:
3367 self.base_klass(datetime.now().timetuple())
3370 @given(data_strategy())
3371 def test_optional(self, d):
3372 default = d.draw(datetimes(
3373 min_value=self.min_datetime,
3374 max_value=self.max_datetime,
3376 optional = d.draw(booleans())
3377 obj = self.base_klass(default=default, optional=optional)
3378 self.assertTrue(obj.optional)
3380 @given(data_strategy())
3381 def test_ready(self, d):
3382 obj = self.base_klass()
3383 self.assertFalse(obj.ready)
3386 with self.assertRaises(ObjNotReady) as err:
3389 value = d.draw(datetimes(min_value=self.min_datetime))
3390 obj = self.base_klass(value)
3391 self.assertTrue(obj.ready)
3395 @given(data_strategy())
3396 def test_comparison(self, d):
3397 value1 = d.draw(datetimes(
3398 min_value=self.min_datetime,
3399 max_value=self.max_datetime,
3401 value2 = d.draw(datetimes(
3402 min_value=self.min_datetime,
3403 max_value=self.max_datetime,
3405 tag1 = d.draw(binary(min_size=1))
3406 tag2 = d.draw(binary(min_size=1))
3408 value1 = value1.replace(microsecond=0)
3409 value2 = value2.replace(microsecond=0)
3410 obj1 = self.base_klass(value1)
3411 obj2 = self.base_klass(value2)
3412 self.assertEqual(obj1 == obj2, value1 == value2)
3413 self.assertEqual(obj1 != obj2, value1 != value2)
3414 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3415 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3416 obj1 = self.base_klass(value1, impl=tag1)
3417 obj2 = self.base_klass(value1, impl=tag2)
3418 self.assertEqual(obj1 == obj2, tag1 == tag2)
3419 self.assertEqual(obj1 != obj2, tag1 != tag2)
3421 @given(data_strategy())
3422 def test_call(self, d):
3430 ) = d.draw(generalized_time_values_strategy(
3431 min_datetime=self.min_datetime,
3432 max_datetime=self.max_datetime,
3433 omit_ms=self.omit_ms,
3435 obj_initial = self.base_klass(
3436 value=value_initial,
3439 default=default_initial,
3440 optional=optional_initial or False,
3441 _decoded=_decoded_initial,
3450 ) = d.draw(generalized_time_values_strategy(
3451 min_datetime=self.min_datetime,
3452 max_datetime=self.max_datetime,
3453 omit_ms=self.omit_ms,
3454 do_expl=impl_initial is None,
3464 value_expected = default if value is None else value
3466 default_initial if value_expected is None
3469 self.assertEqual(obj, value_expected)
3470 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3471 self.assertEqual(obj.expl_tag, expl or expl_initial)
3474 default_initial if default is None else default,
3476 if obj.default is None:
3477 optional = optional_initial if optional is None else optional
3478 optional = False if optional is None else optional
3481 self.assertEqual(obj.optional, optional)
3483 @given(data_strategy())
3484 def test_copy(self, d):
3485 values = d.draw(generalized_time_values_strategy(
3486 min_datetime=self.min_datetime,
3487 max_datetime=self.max_datetime,
3489 obj = self.base_klass(*values)
3490 obj_copied = obj.copy()
3491 self.assert_copied_basic_fields(obj, obj_copied)
3492 self.assertEqual(obj._value, obj_copied._value)
3494 @given(data_strategy())
3495 def test_stripped(self, d):
3496 value = d.draw(datetimes(
3497 min_value=self.min_datetime,
3498 max_value=self.max_datetime,
3500 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3501 obj = self.base_klass(value, impl=tag_impl)
3502 with self.assertRaises(NotEnoughData):
3503 obj.decode(obj.encode()[:-1])
3505 @given(data_strategy())
3506 def test_stripped_expl(self, d):
3507 value = d.draw(datetimes(
3508 min_value=self.min_datetime,
3509 max_value=self.max_datetime,
3511 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3512 obj = self.base_klass(value, expl=tag_expl)
3513 with self.assertRaises(NotEnoughData):
3514 obj.decode(obj.encode()[:-1])
3516 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3517 @given(data_strategy())
3518 def test_symmetric(self, d):
3519 values = d.draw(generalized_time_values_strategy(
3520 min_datetime=self.min_datetime,
3521 max_datetime=self.max_datetime,
3523 value = d.draw(datetimes(
3524 min_value=self.min_datetime,
3525 max_value=self.max_datetime,
3527 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3528 offset = d.draw(integers(min_value=0))
3529 tail_junk = d.draw(binary(max_size=5))
3530 _, _, _, default, optional, _decoded = values
3531 obj = self.base_klass(
3539 self.assertFalse(obj.expled)
3540 obj_encoded = obj.encode()
3541 obj_expled = obj(value, expl=tag_expl)
3542 self.assertTrue(obj_expled.expled)
3545 obj_expled_encoded = obj_expled.encode()
3546 obj_decoded, tail = obj_expled.decode(
3547 obj_expled_encoded + tail_junk,
3552 self.assertEqual(tail, tail_junk)
3553 self.assertEqual(obj_decoded, obj_expled)
3554 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3555 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3556 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3557 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3558 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3560 obj_decoded.expl_llen,
3561 len(len_encode(len(obj_encoded))),
3563 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3564 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3567 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3569 self.assertEqual(obj_decoded.expl_offset, offset)
3572 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3573 base_klass = GeneralizedTime
3575 min_datetime = datetime(1900, 1, 1)
3576 max_datetime = datetime(9999, 12, 31)
3578 def test_go_vectors_invalid(self):
3590 b"-20100102030410Z",
3591 b"2010-0102030410Z",
3592 b"2010-0002030410Z",
3593 b"201001-02030410Z",
3594 b"20100102-030410Z",
3595 b"2010010203-0410Z",
3596 b"201001020304-10Z",
3597 # These ones are INVALID in *DER*, but accepted
3598 # by Go's encoding/asn1
3599 b"20100102030405+0607",
3600 b"20100102030405-0607",
3602 with self.assertRaises(DecodeError) as err:
3603 GeneralizedTime(data)
3606 def test_go_vectors_valid(self):
3608 GeneralizedTime(b"20100102030405Z").todatetime(),
3609 datetime(2010, 1, 2, 3, 4, 5, 0),
3612 def test_encoding(self):
3613 raw = GeneralizedTime(b"20100102030405Z").encode()
3614 with assertRaisesRegex(self, DecodeError, "encoding"):
3615 GeneralizedTime().decode(raw.replace(b"201001", "привет".encode("utf-8")))
3616 with self.assertRaises(DecodeError):
3617 GeneralizedTime().decode(raw.replace(b"20100", b"hello"))
3620 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3621 base_klass = UTCTime
3623 min_datetime = datetime(2000, 1, 1)
3624 max_datetime = datetime(2049, 12, 31)
3626 def test_go_vectors_invalid(self):
3652 # These ones are INVALID in *DER*, but accepted
3653 # by Go's encoding/asn1
3654 b"910506164540-0700",
3655 b"910506164540+0730",
3659 with self.assertRaises(DecodeError) as err:
3663 def test_go_vectors_valid(self):
3665 UTCTime(b"910506234540Z").todatetime(),
3666 datetime(1991, 5, 6, 23, 45, 40, 0),
3669 @given(integers(min_value=0, max_value=49))
3670 def test_pre50(self, year):
3672 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3676 @given(integers(min_value=50, max_value=99))
3677 def test_post50(self, year):
3679 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3683 def test_encoding(self):
3684 raw = UTCTime(b"910506234540Z").encode()
3685 with assertRaisesRegex(self, DecodeError, "encoding"):
3686 UTCTime().decode(raw.replace(b"910506", "привет".encode("utf-8")))
3687 with self.assertRaises(DecodeError):
3688 UTCTime().decode(raw.replace(b"91050", b"hello"))
3692 def any_values_strategy(draw, do_expl=False):
3693 value = draw(one_of(none(), binary()))
3696 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3697 optional = draw(one_of(none(), booleans()))
3699 draw(integers(min_value=0)),
3700 draw(integers(min_value=0)),
3701 draw(integers(min_value=0)),
3703 return (value, expl, optional, _decoded)
3706 class AnyInherited(Any):
3710 class TestAny(CommonMixin, TestCase):
3713 def test_invalid_value_type(self):
3714 with self.assertRaises(InvalidValueType) as err:
3719 def test_optional(self, optional):
3720 obj = Any(optional=optional)
3721 self.assertEqual(obj.optional, optional)
3724 def test_ready(self, value):
3726 self.assertFalse(obj.ready)
3729 with self.assertRaises(ObjNotReady) as err:
3733 self.assertTrue(obj.ready)
3738 def test_basic(self, value):
3739 integer_encoded = Integer(value).encode()
3741 Any(integer_encoded),
3742 Any(Integer(value)),
3743 Any(Any(Integer(value))),
3745 self.assertSequenceEqual(bytes(obj), integer_encoded)
3747 obj.decode(obj.encode())[0].vlen,
3748 len(integer_encoded),
3752 self.assertSequenceEqual(obj.encode(), integer_encoded)
3754 @given(binary(), binary())
3755 def test_comparison(self, value1, value2):
3756 for klass in (Any, AnyInherited):
3757 obj1 = klass(value1)
3758 obj2 = klass(value2)
3759 self.assertEqual(obj1 == obj2, value1 == value2)
3760 self.assertEqual(obj1 != obj2, value1 != value2)
3761 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3763 @given(data_strategy())
3764 def test_call(self, d):
3765 for klass in (Any, AnyInherited):
3771 ) = d.draw(any_values_strategy())
3772 obj_initial = klass(
3775 optional_initial or False,
3783 ) = d.draw(any_values_strategy(do_expl=True))
3784 obj = obj_initial(value, expl, optional)
3786 value_expected = None if value is None else value
3787 self.assertEqual(obj, value_expected)
3788 self.assertEqual(obj.expl_tag, expl or expl_initial)
3789 if obj.default is None:
3790 optional = optional_initial if optional is None else optional
3791 optional = False if optional is None else optional
3792 self.assertEqual(obj.optional, optional)
3794 def test_simultaneous_impl_expl(self):
3795 # override it, as Any does not have implicit tag
3798 def test_decoded(self):
3799 # override it, as Any does not have implicit tag
3802 @given(any_values_strategy())
3803 def test_copy(self, values):
3804 for klass in (Any, AnyInherited):
3805 obj = klass(*values)
3806 obj_copied = obj.copy()
3807 self.assert_copied_basic_fields(obj, obj_copied)
3808 self.assertEqual(obj._value, obj_copied._value)
3810 @given(binary().map(OctetString))
3811 def test_stripped(self, value):
3813 with self.assertRaises(NotEnoughData):
3814 obj.decode(obj.encode()[:-1])
3818 integers(min_value=1).map(tag_ctxc),
3820 def test_stripped_expl(self, value, tag_expl):
3821 obj = Any(value, expl=tag_expl)
3822 with self.assertRaises(NotEnoughData):
3823 obj.decode(obj.encode()[:-1])
3826 integers(min_value=31),
3827 integers(min_value=0),
3830 def test_bad_tag(self, tag, offset, decode_path):
3831 with self.assertRaises(DecodeError) as err:
3833 tag_encode(tag)[:-1],
3835 decode_path=decode_path,
3838 self.assertEqual(err.exception.offset, offset)
3839 self.assertEqual(err.exception.decode_path, decode_path)
3842 integers(min_value=128),
3843 integers(min_value=0),
3846 def test_bad_len(self, l, offset, decode_path):
3847 with self.assertRaises(DecodeError) as err:
3849 Any.tag_default + len_encode(l)[:-1],
3851 decode_path=decode_path,
3854 self.assertEqual(err.exception.offset, offset)
3855 self.assertEqual(err.exception.decode_path, decode_path)
3857 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3859 any_values_strategy(),
3860 integers().map(lambda x: Integer(x).encode()),
3861 integers(min_value=1).map(tag_ctxc),
3862 integers(min_value=0),
3865 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3866 for klass in (Any, AnyInherited):
3867 _, _, optional, _decoded = values
3868 obj = klass(value=value, optional=optional, _decoded=_decoded)
3871 self.assertFalse(obj.expled)
3872 obj_encoded = obj.encode()
3873 obj_expled = obj(value, expl=tag_expl)
3874 self.assertTrue(obj_expled.expled)
3877 obj_expled_encoded = obj_expled.encode()
3878 obj_decoded, tail = obj_expled.decode(
3879 obj_expled_encoded + tail_junk,
3884 self.assertEqual(tail, tail_junk)
3885 self.assertEqual(obj_decoded, obj_expled)
3886 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3887 self.assertEqual(bytes(obj_decoded), bytes(obj))
3888 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3889 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3890 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3892 obj_decoded.expl_llen,
3893 len(len_encode(len(obj_encoded))),
3895 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3896 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3899 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3901 self.assertEqual(obj_decoded.expl_offset, offset)
3902 self.assertEqual(obj_decoded.tlen, 0)
3903 self.assertEqual(obj_decoded.llen, 0)
3904 self.assertEqual(obj_decoded.vlen, len(value))
3907 integers(min_value=1).map(tag_ctxc),
3908 integers(min_value=0, max_value=3),
3909 integers(min_value=0),
3913 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
3914 chunk = Boolean(False, expl=expl).encode()
3916 OctetString.tag_default +
3918 b"".join([chunk] * chunks) +
3921 obj, tail = Any().decode(
3924 decode_path=decode_path,
3925 ctx={"bered": True},
3927 self.assertSequenceEqual(tail, junk)
3928 self.assertEqual(obj.offset, offset)
3929 self.assertEqual(obj.tlvlen, len(encoded))
3930 with self.assertRaises(NotEnoughData) as err:
3934 decode_path=decode_path,
3935 ctx={"bered": True},
3937 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
3938 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
3942 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3944 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3945 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
3947 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
3948 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
3950 min_size=len(names),
3951 max_size=len(names),
3954 (name, Integer(**tag_kwargs))
3955 for name, tag_kwargs in zip(names, tags)
3958 if value_required or draw(booleans()):
3959 value = draw(tuples(
3960 sampled_from([name for name, _ in schema]),
3961 integers().map(Integer),
3965 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3966 default = draw(one_of(
3968 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3970 optional = draw(one_of(none(), booleans()))
3972 draw(integers(min_value=0)),
3973 draw(integers(min_value=0)),
3974 draw(integers(min_value=0)),
3976 return (schema, value, expl, default, optional, _decoded)
3979 class ChoiceInherited(Choice):
3983 class TestChoice(CommonMixin, TestCase):
3985 schema = (("whatever", Boolean()),)
3988 def test_schema_required(self):
3989 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3992 def test_impl_forbidden(self):
3993 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3994 Choice(impl=b"whatever")
3996 def test_invalid_value_type(self):
3997 with self.assertRaises(InvalidValueType) as err:
3998 self.base_klass(123)
4000 with self.assertRaises(ObjUnknown) as err:
4001 self.base_klass(("whenever", Boolean(False)))
4003 with self.assertRaises(InvalidValueType) as err:
4004 self.base_klass(("whatever", Integer(123)))
4008 def test_optional(self, optional):
4009 obj = self.base_klass(
4010 default=self.base_klass(("whatever", Boolean(False))),
4013 self.assertTrue(obj.optional)
4016 def test_ready(self, value):
4017 obj = self.base_klass()
4018 self.assertFalse(obj.ready)
4021 self.assertIsNone(obj["whatever"])
4022 with self.assertRaises(ObjNotReady) as err:
4025 obj["whatever"] = Boolean()
4026 self.assertFalse(obj.ready)
4029 obj["whatever"] = Boolean(value)
4030 self.assertTrue(obj.ready)
4034 @given(booleans(), booleans())
4035 def test_comparison(self, value1, value2):
4036 class WahlInherited(self.base_klass):
4038 for klass in (self.base_klass, WahlInherited):
4039 obj1 = klass(("whatever", Boolean(value1)))
4040 obj2 = klass(("whatever", Boolean(value2)))
4041 self.assertEqual(obj1 == obj2, value1 == value2)
4042 self.assertEqual(obj1 != obj2, value1 != value2)
4043 self.assertEqual(obj1 == obj2._value, value1 == value2)
4044 self.assertFalse(obj1 == obj2._value[1])
4046 @given(data_strategy())
4047 def test_call(self, d):
4048 for klass in (Choice, ChoiceInherited):
4056 ) = d.draw(choice_values_strategy())
4059 schema = schema_initial
4061 value=value_initial,
4063 default=default_initial,
4064 optional=optional_initial or False,
4065 _decoded=_decoded_initial,
4074 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4075 obj = obj_initial(value, expl, default, optional)
4077 value_expected = default if value is None else value
4079 default_initial if value_expected is None
4082 self.assertEqual(obj.choice, value_expected[0])
4083 self.assertEqual(obj.value, int(value_expected[1]))
4084 self.assertEqual(obj.expl_tag, expl or expl_initial)
4085 default_expect = default_initial if default is None else default
4086 if default_expect is not None:
4087 self.assertEqual(obj.default.choice, default_expect[0])
4088 self.assertEqual(obj.default.value, int(default_expect[1]))
4089 if obj.default is None:
4090 optional = optional_initial if optional is None else optional
4091 optional = False if optional is None else optional
4094 self.assertEqual(obj.optional, optional)
4095 self.assertEqual(obj.specs, obj_initial.specs)
4097 def test_simultaneous_impl_expl(self):
4098 # override it, as Any does not have implicit tag
4101 def test_decoded(self):
4102 # override it, as Any does not have implicit tag
4105 @given(choice_values_strategy())
4106 def test_copy(self, values):
4107 _schema, value, expl, default, optional, _decoded = values
4109 class Wahl(self.base_klass):
4115 optional=optional or False,
4118 obj_copied = obj.copy()
4119 self.assertIsNone(obj.tag)
4120 self.assertIsNone(obj_copied.tag)
4121 # hack for assert_copied_basic_fields
4122 obj.tag = "whatever"
4123 obj_copied.tag = "whatever"
4124 self.assert_copied_basic_fields(obj, obj_copied)
4125 self.assertEqual(obj._value, obj_copied._value)
4126 self.assertEqual(obj.specs, obj_copied.specs)
4129 def test_stripped(self, value):
4130 obj = self.base_klass(("whatever", Boolean(value)))
4131 with self.assertRaises(NotEnoughData):
4132 obj.decode(obj.encode()[:-1])
4136 integers(min_value=1).map(tag_ctxc),
4138 def test_stripped_expl(self, value, tag_expl):
4139 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4140 with self.assertRaises(NotEnoughData):
4141 obj.decode(obj.encode()[:-1])
4143 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4144 @given(data_strategy())
4145 def test_symmetric(self, d):
4146 _schema, value, _, default, optional, _decoded = d.draw(
4147 choice_values_strategy(value_required=True)
4149 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4150 offset = d.draw(integers(min_value=0))
4151 tail_junk = d.draw(binary(max_size=5))
4153 class Wahl(self.base_klass):
4163 self.assertFalse(obj.expled)
4164 obj_encoded = obj.encode()
4165 obj_expled = obj(value, expl=tag_expl)
4166 self.assertTrue(obj_expled.expled)
4169 obj_expled_encoded = obj_expled.encode()
4170 obj_decoded, tail = obj_expled.decode(
4171 obj_expled_encoded + tail_junk,
4176 self.assertEqual(tail, tail_junk)
4177 self.assertEqual(obj_decoded, obj_expled)
4178 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4179 self.assertEqual(obj_decoded.value, obj_expled.value)
4180 self.assertEqual(obj_decoded.choice, obj.choice)
4181 self.assertEqual(obj_decoded.value, obj.value)
4182 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4183 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4184 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4186 obj_decoded.expl_llen,
4187 len(len_encode(len(obj_encoded))),
4189 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4190 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4193 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4195 self.assertEqual(obj_decoded.expl_offset, offset)
4196 self.assertSequenceEqual(
4198 obj_decoded.value.fulloffset - offset:
4199 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4205 def test_set_get(self, value):
4208 ("erste", Boolean()),
4209 ("zweite", Integer()),
4212 with self.assertRaises(ObjUnknown) as err:
4213 obj["whatever"] = "whenever"
4214 with self.assertRaises(InvalidValueType) as err:
4215 obj["zweite"] = Boolean(False)
4216 obj["zweite"] = Integer(value)
4218 with self.assertRaises(ObjUnknown) as err:
4221 self.assertIsNone(obj["erste"])
4222 self.assertEqual(obj["zweite"], Integer(value))
4224 def test_tag_mismatch(self):
4227 ("erste", Boolean()),
4229 int_encoded = Integer(123).encode()
4230 bool_encoded = Boolean(False).encode()
4232 obj.decode(bool_encoded)
4233 with self.assertRaises(TagMismatch):
4234 obj.decode(int_encoded)
4236 def test_tag_mismatch_underlying(self):
4237 class SeqOfBoolean(SequenceOf):
4240 class SeqOfInteger(SequenceOf):
4245 ("erste", SeqOfBoolean()),
4248 int_encoded = SeqOfInteger((Integer(123),)).encode()
4249 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4251 obj.decode(bool_encoded)
4252 with self.assertRaises(TagMismatch) as err:
4253 obj.decode(int_encoded)
4254 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4258 def seq_values_strategy(draw, seq_klass, do_expl=False):
4260 if draw(booleans()):
4263 k: v for k, v in draw(dictionaries(
4266 booleans().map(Boolean),
4267 integers().map(Integer),
4272 if draw(booleans()):
4273 schema = list(draw(dictionaries(
4276 booleans().map(Boolean),
4277 integers().map(Integer),
4283 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4285 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4287 if draw(booleans()):
4288 default = seq_klass()
4290 k: v for k, v in draw(dictionaries(
4293 booleans().map(Boolean),
4294 integers().map(Integer),
4298 optional = draw(one_of(none(), booleans()))
4300 draw(integers(min_value=0)),
4301 draw(integers(min_value=0)),
4302 draw(integers(min_value=0)),
4304 return (value, schema, impl, expl, default, optional, _decoded)
4308 def sequence_strategy(draw, seq_klass):
4309 inputs = draw(lists(
4311 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4312 tuples(just(Integer), integers(), one_of(none(), integers())),
4317 integers(min_value=1),
4318 min_size=len(inputs),
4319 max_size=len(inputs),
4322 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4323 for tag, expled in zip(tags, draw(lists(
4325 min_size=len(inputs),
4326 max_size=len(inputs),
4330 for i, optional in enumerate(draw(lists(
4331 sampled_from(("required", "optional", "empty")),
4332 min_size=len(inputs),
4333 max_size=len(inputs),
4335 if optional in ("optional", "empty"):
4336 inits[i]["optional"] = True
4337 if optional == "empty":
4339 empties = set(empties)
4340 names = list(draw(sets(
4342 min_size=len(inputs),
4343 max_size=len(inputs),
4346 for i, (klass, value, default) in enumerate(inputs):
4347 schema.append((names[i], klass(default=default, **inits[i])))
4348 seq_name = draw(text_letters())
4349 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4352 for i, (klass, value, default) in enumerate(inputs):
4359 "default_value": None if spec.default is None else default,
4363 expect["optional"] = True
4365 expect["presented"] = True
4366 expect["value"] = value
4368 expect["optional"] = True
4369 if default is not None and default == value:
4370 expect["presented"] = False
4371 seq[name] = klass(value)
4372 expects.append(expect)
4377 def sequences_strategy(draw, seq_klass):
4378 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4380 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4381 for tag, expled in zip(tags, draw(lists(
4388 i for i, is_default in enumerate(draw(lists(
4394 names = list(draw(sets(
4399 seq_expectses = draw(lists(
4400 sequence_strategy(seq_klass=seq_klass),
4404 seqs = [seq for seq, _ in seq_expectses]
4406 for i, (name, seq) in enumerate(zip(names, seqs)):
4409 seq(default=(seq if i in defaulted else None), **inits[i]),
4411 seq_name = draw(text_letters())
4412 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4415 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4418 "expects": expects_inner,
4421 seq_outer[name] = seq_inner
4422 if seq_outer.specs[name].default is None:
4423 expect["presented"] = True
4424 expect_outers.append(expect)
4425 return seq_outer, expect_outers
4428 class SeqMixing(object):
4429 def test_invalid_value_type(self):
4430 with self.assertRaises(InvalidValueType) as err:
4431 self.base_klass(123)
4434 def test_invalid_value_type_set(self):
4435 class Seq(self.base_klass):
4436 schema = (("whatever", Boolean()),)
4438 with self.assertRaises(InvalidValueType) as err:
4439 seq["whatever"] = Integer(123)
4443 def test_optional(self, optional):
4444 obj = self.base_klass(default=self.base_klass(), optional=optional)
4445 self.assertTrue(obj.optional)
4447 @given(data_strategy())
4448 def test_ready(self, d):
4450 str(i): v for i, v in enumerate(d.draw(lists(
4457 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4464 for name in d.draw(permutations(
4465 list(ready.keys()) + list(non_ready.keys()),
4467 schema_input.append((name, Boolean()))
4469 class Seq(self.base_klass):
4470 schema = tuple(schema_input)
4472 for name in ready.keys():
4474 seq[name] = Boolean()
4475 self.assertFalse(seq.ready)
4478 for name, value in ready.items():
4479 seq[name] = Boolean(value)
4480 self.assertFalse(seq.ready)
4483 with self.assertRaises(ObjNotReady) as err:
4486 for name, value in non_ready.items():
4487 seq[name] = Boolean(value)
4488 self.assertTrue(seq.ready)
4492 @given(data_strategy())
4493 def test_call(self, d):
4494 class SeqInherited(self.base_klass):
4496 for klass in (self.base_klass, SeqInherited):
4505 ) = d.draw(seq_values_strategy(seq_klass=klass))
4506 obj_initial = klass(
4512 optional_initial or False,
4523 ) = d.draw(seq_values_strategy(
4525 do_expl=impl_initial is None,
4527 obj = obj_initial(value, impl, expl, default, optional)
4528 value_expected = default if value is None else value
4530 default_initial if value_expected is None
4533 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4534 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4535 self.assertEqual(obj.expl_tag, expl or expl_initial)
4537 {} if obj.default is None else obj.default._value,
4538 getattr(default_initial if default is None else default, "_value", {}),
4540 if obj.default is None:
4541 optional = optional_initial if optional is None else optional
4542 optional = False if optional is None else optional
4545 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4546 self.assertEqual(obj.optional, optional)
4548 @given(data_strategy())
4549 def test_copy(self, d):
4550 class SeqInherited(self.base_klass):
4552 for klass in (self.base_klass, SeqInherited):
4553 values = d.draw(seq_values_strategy(seq_klass=klass))
4554 obj = klass(*values)
4555 obj_copied = obj.copy()
4556 self.assert_copied_basic_fields(obj, obj_copied)
4557 self.assertEqual(obj.specs, obj_copied.specs)
4558 self.assertEqual(obj._value, obj_copied._value)
4560 @given(data_strategy())
4561 def test_stripped(self, d):
4562 value = d.draw(integers())
4563 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4565 class Seq(self.base_klass):
4567 schema = (("whatever", Integer()),)
4569 seq["whatever"] = Integer(value)
4570 with self.assertRaises(NotEnoughData):
4571 seq.decode(seq.encode()[:-1])
4573 @given(data_strategy())
4574 def test_stripped_expl(self, d):
4575 value = d.draw(integers())
4576 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4578 class Seq(self.base_klass):
4580 schema = (("whatever", Integer()),)
4582 seq["whatever"] = Integer(value)
4583 with self.assertRaises(NotEnoughData):
4584 seq.decode(seq.encode()[:-1])
4586 @given(binary(min_size=2))
4587 def test_non_tag_mismatch_raised(self, junk):
4589 _, _, len_encoded = tag_strip(memoryview(junk))
4590 len_decode(len_encoded)
4596 class Seq(self.base_klass):
4598 ("whatever", Integer()),
4600 ("whenever", Integer()),
4603 seq["whatever"] = Integer(123)
4604 seq["junk"] = Any(junk)
4605 seq["whenever"] = Integer(123)
4606 with self.assertRaises(DecodeError):
4607 seq.decode(seq.encode())
4610 integers(min_value=31),
4611 integers(min_value=0),
4614 def test_bad_tag(self, tag, offset, decode_path):
4615 with self.assertRaises(DecodeError) as err:
4616 self.base_klass().decode(
4617 tag_encode(tag)[:-1],
4619 decode_path=decode_path,
4622 self.assertEqual(err.exception.offset, offset)
4623 self.assertEqual(err.exception.decode_path, decode_path)
4626 integers(min_value=128),
4627 integers(min_value=0),
4630 def test_bad_len(self, l, offset, decode_path):
4631 with self.assertRaises(DecodeError) as err:
4632 self.base_klass().decode(
4633 self.base_klass.tag_default + len_encode(l)[:-1],
4635 decode_path=decode_path,
4638 self.assertEqual(err.exception.offset, offset)
4639 self.assertEqual(err.exception.decode_path, decode_path)
4641 def _assert_expects(self, seq, expects):
4642 for expect in expects:
4644 seq.specs[expect["name"]].optional,
4647 if expect["default_value"] is not None:
4649 seq.specs[expect["name"]].default,
4650 expect["default_value"],
4652 if expect["presented"]:
4653 self.assertIn(expect["name"], seq)
4654 self.assertEqual(seq[expect["name"]], expect["value"])
4656 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4657 @given(data_strategy())
4658 def test_symmetric(self, d):
4659 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4660 tail_junk = d.draw(binary(max_size=5))
4661 self.assertTrue(seq.ready)
4662 self.assertFalse(seq.decoded)
4663 self._assert_expects(seq, expects)
4666 self.assertTrue(seq.ready)
4667 seq_encoded = seq.encode()
4668 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4669 self.assertFalse(seq_decoded.lenindef)
4671 t, _, lv = tag_strip(seq_encoded)
4672 _, _, v = len_decode(lv)
4673 seq_encoded_lenindef = t + LENINDEF + v + EOC
4674 seq_decoded_lenindef, tail_lenindef = seq.decode(
4675 seq_encoded_lenindef + tail_junk,
4676 ctx={"bered": True},
4678 self.assertTrue(seq_decoded_lenindef.lenindef)
4679 with self.assertRaises(DecodeError):
4680 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4681 with self.assertRaises(DecodeError):
4682 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4683 repr(seq_decoded_lenindef)
4684 pprint(seq_decoded_lenindef)
4685 self.assertTrue(seq_decoded_lenindef.ready)
4687 for decoded, decoded_tail, encoded in (
4688 (seq_decoded, tail, seq_encoded),
4689 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4691 self.assertEqual(decoded_tail, tail_junk)
4692 self._assert_expects(decoded, expects)
4693 self.assertEqual(seq, decoded)
4694 self.assertEqual(decoded.encode(), seq_encoded)
4695 self.assertEqual(decoded.tlvlen, len(encoded))
4696 for expect in expects:
4697 if not expect["presented"]:
4698 self.assertNotIn(expect["name"], decoded)
4700 self.assertIn(expect["name"], decoded)
4701 obj = decoded[expect["name"]]
4702 self.assertTrue(obj.decoded)
4703 offset = obj.expl_offset if obj.expled else obj.offset
4704 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4705 self.assertSequenceEqual(
4706 seq_encoded[offset:offset + tlvlen],
4710 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4711 @given(data_strategy())
4712 def test_symmetric_with_seq(self, d):
4713 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4714 self.assertTrue(seq.ready)
4715 seq_encoded = seq.encode()
4716 seq_decoded, tail = seq.decode(seq_encoded)
4717 self.assertEqual(tail, b"")
4718 self.assertTrue(seq.ready)
4719 self.assertEqual(seq, seq_decoded)
4720 self.assertEqual(seq_decoded.encode(), seq_encoded)
4721 for expect_outer in expect_outers:
4722 if not expect_outer["presented"]:
4723 self.assertNotIn(expect_outer["name"], seq_decoded)
4725 self.assertIn(expect_outer["name"], seq_decoded)
4726 obj = seq_decoded[expect_outer["name"]]
4727 self.assertTrue(obj.decoded)
4728 offset = obj.expl_offset if obj.expled else obj.offset
4729 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4730 self.assertSequenceEqual(
4731 seq_encoded[offset:offset + tlvlen],
4734 self._assert_expects(obj, expect_outer["expects"])
4736 @given(data_strategy())
4737 def test_default_disappears(self, d):
4738 _schema = list(d.draw(dictionaries(
4740 sets(integers(), min_size=2, max_size=2),
4744 class Seq(self.base_klass):
4746 (n, Integer(default=d))
4747 for n, (_, d) in _schema
4750 for name, (value, _) in _schema:
4751 seq[name] = Integer(value)
4752 self.assertEqual(len(seq._value), len(_schema))
4753 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4754 self.assertGreater(len(seq.encode()), len(empty_seq))
4755 for name, (_, default) in _schema:
4756 seq[name] = Integer(default)
4757 self.assertEqual(len(seq._value), 0)
4758 self.assertSequenceEqual(seq.encode(), empty_seq)
4760 @given(data_strategy())
4761 def test_encoded_default_accepted(self, d):
4762 _schema = list(d.draw(dictionaries(
4767 tags = [tag_encode(tag) for tag in d.draw(sets(
4768 integers(min_value=0),
4769 min_size=len(_schema),
4770 max_size=len(_schema),
4773 class SeqWithoutDefault(self.base_klass):
4775 (n, Integer(impl=t))
4776 for (n, _), t in zip(_schema, tags)
4778 seq_without_default = SeqWithoutDefault()
4779 for name, value in _schema:
4780 seq_without_default[name] = Integer(value)
4781 seq_encoded = seq_without_default.encode()
4783 class SeqWithDefault(self.base_klass):
4785 (n, Integer(default=v, impl=t))
4786 for (n, v), t in zip(_schema, tags)
4788 seq_with_default = SeqWithDefault()
4789 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4790 for name, value in _schema:
4791 self.assertEqual(seq_decoded[name], seq_with_default[name])
4792 self.assertEqual(seq_decoded[name], value)
4794 @given(data_strategy())
4795 def test_missing_from_spec(self, d):
4796 names = list(d.draw(sets(text_letters(), min_size=2)))
4797 tags = [tag_encode(tag) for tag in d.draw(sets(
4798 integers(min_value=0),
4799 min_size=len(names),
4800 max_size=len(names),
4802 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4804 class SeqFull(self.base_klass):
4805 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4806 seq_full = SeqFull()
4807 for i, name in enumerate(names):
4808 seq_full[name] = Integer(i)
4809 seq_encoded = seq_full.encode()
4810 altered = names_tags[:-2] + names_tags[-1:]
4812 class SeqMissing(self.base_klass):
4813 schema = [(n, Integer(impl=t)) for n, t in altered]
4814 seq_missing = SeqMissing()
4815 with self.assertRaises(TagMismatch):
4816 seq_missing.decode(seq_encoded)
4819 class TestSequence(SeqMixing, CommonMixin, TestCase):
4820 base_klass = Sequence
4826 def test_remaining(self, value, junk):
4827 class Seq(Sequence):
4829 ("whatever", Integer()),
4831 int_encoded = Integer(value).encode()
4833 Sequence.tag_default,
4834 len_encode(len(int_encoded + junk)),
4837 with assertRaisesRegex(self, DecodeError, "remaining"):
4838 Seq().decode(junked)
4840 @given(sets(text_letters(), min_size=2))
4841 def test_obj_unknown(self, names):
4842 missing = names.pop()
4844 class Seq(Sequence):
4845 schema = [(n, Boolean()) for n in names]
4847 with self.assertRaises(ObjUnknown) as err:
4850 with self.assertRaises(ObjUnknown) as err:
4851 seq[missing] = Boolean()
4854 def test_x690_vector(self):
4855 class Seq(Sequence):
4857 ("name", IA5String()),
4860 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4861 self.assertEqual(seq["name"], "Smith")
4862 self.assertEqual(seq["ok"], True)
4865 class TestSet(SeqMixing, CommonMixin, TestCase):
4868 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4869 @given(data_strategy())
4870 def test_sorted(self, d):
4872 tag_encode(tag) for tag in
4873 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4877 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4879 for name, _ in Seq.schema:
4880 seq[name] = OctetString(b"")
4881 seq_encoded = seq.encode()
4882 seq_decoded, _ = seq.decode(seq_encoded)
4883 self.assertSequenceEqual(
4884 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4885 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4890 def seqof_values_strategy(draw, schema=None, do_expl=False):
4892 schema = draw(sampled_from((Boolean(), Integer())))
4893 bound_min, bound_max = sorted(draw(sets(
4894 integers(min_value=0, max_value=10),
4898 if isinstance(schema, Boolean):
4899 values_generator = booleans().map(Boolean)
4900 elif isinstance(schema, Integer):
4901 values_generator = integers().map(Integer)
4902 values_generator = lists(
4907 values = draw(one_of(none(), values_generator))
4911 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4913 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4914 default = draw(one_of(none(), values_generator))
4915 optional = draw(one_of(none(), booleans()))
4917 draw(integers(min_value=0)),
4918 draw(integers(min_value=0)),
4919 draw(integers(min_value=0)),
4924 (bound_min, bound_max),
4933 class SeqOfMixing(object):
4934 def test_invalid_value_type(self):
4935 with self.assertRaises(InvalidValueType) as err:
4936 self.base_klass(123)
4939 def test_invalid_values_type(self):
4940 class SeqOf(self.base_klass):
4942 with self.assertRaises(InvalidValueType) as err:
4943 SeqOf([Integer(123), Boolean(False), Integer(234)])
4946 def test_schema_required(self):
4947 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4948 self.base_klass.__mro__[1]()
4950 @given(booleans(), booleans(), binary(), binary())
4951 def test_comparison(self, value1, value2, tag1, tag2):
4952 class SeqOf(self.base_klass):
4954 obj1 = SeqOf([Boolean(value1)])
4955 obj2 = SeqOf([Boolean(value2)])
4956 self.assertEqual(obj1 == obj2, value1 == value2)
4957 self.assertEqual(obj1 != obj2, value1 != value2)
4958 self.assertEqual(obj1 == list(obj2), value1 == value2)
4959 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4960 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4961 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4962 self.assertEqual(obj1 == obj2, tag1 == tag2)
4963 self.assertEqual(obj1 != obj2, tag1 != tag2)
4965 @given(lists(booleans()))
4966 def test_iter(self, values):
4967 class SeqOf(self.base_klass):
4969 obj = SeqOf([Boolean(value) for value in values])
4970 self.assertEqual(len(obj), len(values))
4971 for i, value in enumerate(obj):
4972 self.assertEqual(value, values[i])
4974 @given(data_strategy())
4975 def test_ready(self, d):
4976 ready = [Integer(v) for v in d.draw(lists(
4983 range(d.draw(integers(min_value=1, max_value=5)))
4986 class SeqOf(self.base_klass):
4988 values = d.draw(permutations(ready + non_ready))
4990 for value in values:
4992 self.assertFalse(seqof.ready)
4995 with self.assertRaises(ObjNotReady) as err:
4998 for i, value in enumerate(values):
4999 self.assertEqual(seqof[i], value)
5000 if not seqof[i].ready:
5001 seqof[i] = Integer(i)
5002 self.assertTrue(seqof.ready)
5006 def test_spec_mismatch(self):
5007 class SeqOf(self.base_klass):
5010 seqof.append(Integer(123))
5011 with self.assertRaises(ValueError):
5012 seqof.append(Boolean(False))
5013 with self.assertRaises(ValueError):
5014 seqof[0] = Boolean(False)
5016 @given(data_strategy())
5017 def test_bounds_satisfied(self, d):
5018 class SeqOf(self.base_klass):
5020 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5021 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5022 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5023 SeqOf(value=value, bounds=(bound_min, bound_max))
5025 @given(data_strategy())
5026 def test_bounds_unsatisfied(self, d):
5027 class SeqOf(self.base_klass):
5029 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5030 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5031 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
5032 with self.assertRaises(BoundsError) as err:
5033 SeqOf(value=value, bounds=(bound_min, bound_max))
5035 value = [Boolean()] * d.draw(integers(
5036 min_value=bound_max + 1,
5037 max_value=bound_max + 10,
5039 with self.assertRaises(BoundsError) as err:
5040 SeqOf(value=value, bounds=(bound_min, bound_max))
5043 @given(integers(min_value=1, max_value=10))
5044 def test_out_of_bounds(self, bound_max):
5045 class SeqOf(self.base_klass):
5047 bounds = (0, bound_max)
5049 for _ in range(bound_max):
5050 seqof.append(Integer(123))
5051 with self.assertRaises(BoundsError):
5052 seqof.append(Integer(123))
5054 @given(data_strategy())
5055 def test_call(self, d):
5065 ) = d.draw(seqof_values_strategy())
5067 class SeqOf(self.base_klass):
5068 schema = schema_initial
5069 obj_initial = SeqOf(
5070 value=value_initial,
5071 bounds=bounds_initial,
5074 default=default_initial,
5075 optional=optional_initial or False,
5076 _decoded=_decoded_initial,
5087 ) = d.draw(seqof_values_strategy(
5088 schema=schema_initial,
5089 do_expl=impl_initial is None,
5091 if (default is None) and (obj_initial.default is not None):
5094 (bounds is None) and
5095 (value is not None) and
5096 (bounds_initial is not None) and
5097 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5101 (bounds is None) and
5102 (default is not None) and
5103 (bounds_initial is not None) and
5104 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5116 value_expected = default if value is None else value
5118 default_initial if value_expected is None
5121 value_expected = () if value_expected is None else value_expected
5122 self.assertEqual(obj, value_expected)
5123 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5124 self.assertEqual(obj.expl_tag, expl or expl_initial)
5127 default_initial if default is None else default,
5129 if obj.default is None:
5130 optional = optional_initial if optional is None else optional
5131 optional = False if optional is None else optional
5134 self.assertEqual(obj.optional, optional)
5136 (obj._bound_min, obj._bound_max),
5137 bounds or bounds_initial or (0, float("+inf")),
5140 @given(seqof_values_strategy())
5141 def test_copy(self, values):
5142 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5144 class SeqOf(self.base_klass):
5152 optional=optional or False,
5155 obj_copied = obj.copy()
5156 self.assert_copied_basic_fields(obj, obj_copied)
5157 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5158 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5159 self.assertEqual(obj._value, obj_copied._value)
5163 integers(min_value=1).map(tag_encode),
5165 def test_stripped(self, values, tag_impl):
5166 class SeqOf(self.base_klass):
5167 schema = OctetString()
5168 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5169 with self.assertRaises(NotEnoughData):
5170 obj.decode(obj.encode()[:-1])
5174 integers(min_value=1).map(tag_ctxc),
5176 def test_stripped_expl(self, values, tag_expl):
5177 class SeqOf(self.base_klass):
5178 schema = OctetString()
5179 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5180 with self.assertRaises(NotEnoughData):
5181 obj.decode(obj.encode()[:-1])
5184 integers(min_value=31),
5185 integers(min_value=0),
5188 def test_bad_tag(self, tag, offset, decode_path):
5189 with self.assertRaises(DecodeError) as err:
5190 self.base_klass().decode(
5191 tag_encode(tag)[:-1],
5193 decode_path=decode_path,
5196 self.assertEqual(err.exception.offset, offset)
5197 self.assertEqual(err.exception.decode_path, decode_path)
5200 integers(min_value=128),
5201 integers(min_value=0),
5204 def test_bad_len(self, l, offset, decode_path):
5205 with self.assertRaises(DecodeError) as err:
5206 self.base_klass().decode(
5207 self.base_klass.tag_default + len_encode(l)[:-1],
5209 decode_path=decode_path,
5212 self.assertEqual(err.exception.offset, offset)
5213 self.assertEqual(err.exception.decode_path, decode_path)
5215 @given(binary(min_size=1))
5216 def test_tag_mismatch(self, impl):
5217 assume(impl != self.base_klass.tag_default)
5218 with self.assertRaises(TagMismatch):
5219 self.base_klass(impl=impl).decode(self.base_klass().encode())
5221 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5223 seqof_values_strategy(schema=Integer()),
5224 lists(integers().map(Integer)),
5225 integers(min_value=1).map(tag_ctxc),
5226 integers(min_value=0),
5229 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5230 _, _, _, _, _, default, optional, _decoded = values
5232 class SeqOf(self.base_klass):
5242 self.assertFalse(obj.expled)
5243 obj_encoded = obj.encode()
5244 obj_expled = obj(value, expl=tag_expl)
5245 self.assertTrue(obj_expled.expled)
5248 obj_expled_encoded = obj_expled.encode()
5249 obj_decoded, tail = obj_expled.decode(
5250 obj_expled_encoded + tail_junk,
5255 self.assertEqual(tail, tail_junk)
5256 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5257 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5258 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5259 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5261 obj_decoded.expl_llen,
5262 len(len_encode(len(obj_encoded))),
5264 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5265 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5268 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5270 self.assertEqual(obj_decoded.expl_offset, offset)
5271 for obj_inner in obj_decoded:
5272 self.assertIn(obj_inner, obj_decoded)
5273 self.assertSequenceEqual(
5276 obj_inner.offset - offset:
5277 obj_inner.offset + obj_inner.tlvlen - offset
5281 t, _, lv = tag_strip(obj_encoded)
5282 _, _, v = len_decode(lv)
5283 obj_encoded_lenindef = t + LENINDEF + v + EOC
5284 obj_decoded_lenindef, tail_lenindef = obj.decode(
5285 obj_encoded_lenindef + tail_junk,
5286 ctx={"bered": True},
5288 self.assertTrue(obj_decoded_lenindef.lenindef)
5289 repr(obj_decoded_lenindef)
5290 pprint(obj_decoded_lenindef)
5291 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5292 with self.assertRaises(DecodeError):
5293 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5294 with self.assertRaises(DecodeError):
5295 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5298 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5299 class SeqOf(SequenceOf):
5303 def _test_symmetric_compare_objs(self, obj1, obj2):
5304 self.assertEqual(obj1, obj2)
5305 self.assertSequenceEqual(list(obj1), list(obj2))
5308 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5313 def _test_symmetric_compare_objs(self, obj1, obj2):
5314 self.assertSetEqual(
5315 set(int(v) for v in obj1),
5316 set(int(v) for v in obj2),
5319 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5320 @given(data_strategy())
5321 def test_sorted(self, d):
5322 values = [OctetString(v) for v in d.draw(lists(binary()))]
5325 schema = OctetString()
5327 seq_encoded = seq.encode()
5328 seq_decoded, _ = seq.decode(seq_encoded)
5329 self.assertSequenceEqual(
5330 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5331 b"".join(sorted([v.encode() for v in values])),
5335 class TestGoMarshalVectors(TestCase):
5337 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5338 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5339 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5340 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5341 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5343 class Seq(Sequence):
5345 ("erste", Integer()),
5346 ("zweite", Integer(optional=True))
5349 seq["erste"] = Integer(64)
5350 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5351 seq["erste"] = Integer(0x123456)
5352 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5353 seq["erste"] = Integer(64)
5354 seq["zweite"] = Integer(65)
5355 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5357 class NestedSeq(Sequence):
5361 seq["erste"] = Integer(127)
5362 seq["zweite"] = None
5363 nested = NestedSeq()
5364 nested["nest"] = seq
5365 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5367 self.assertSequenceEqual(
5368 OctetString(b"\x01\x02\x03").encode(),
5369 hexdec("0403010203"),
5372 class Seq(Sequence):
5374 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5377 seq["erste"] = Integer(64)
5378 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5380 class Seq(Sequence):
5382 ("erste", Integer(expl=tag_ctxc(5))),
5385 seq["erste"] = Integer(64)
5386 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5388 class Seq(Sequence):
5391 impl=tag_encode(0, klass=TagClassContext),
5396 seq["erste"] = Null()
5397 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5399 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5401 self.assertSequenceEqual(
5402 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5403 hexdec("170d3730303130313030303030305a"),
5405 self.assertSequenceEqual(
5406 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5407 hexdec("170d3039313131353232353631365a"),
5409 self.assertSequenceEqual(
5410 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5411 hexdec("180f32313030303430353132303130315a"),
5414 class Seq(Sequence):
5416 ("erste", GeneralizedTime()),
5419 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5420 self.assertSequenceEqual(
5422 hexdec("3011180f32303039313131353232353631365a"),
5425 self.assertSequenceEqual(
5426 BitString((1, b"\x80")).encode(),
5429 self.assertSequenceEqual(
5430 BitString((12, b"\x81\xF0")).encode(),
5431 hexdec("03030481f0"),
5434 self.assertSequenceEqual(
5435 ObjectIdentifier("1.2.3.4").encode(),
5436 hexdec("06032a0304"),
5438 self.assertSequenceEqual(
5439 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5440 hexdec("06092a864888932d010105"),
5442 self.assertSequenceEqual(
5443 ObjectIdentifier("2.100.3").encode(),
5444 hexdec("0603813403"),
5447 self.assertSequenceEqual(
5448 PrintableString("test").encode(),
5449 hexdec("130474657374"),
5451 self.assertSequenceEqual(
5452 PrintableString("x" * 127).encode(),
5453 hexdec("137F" + "78" * 127),
5455 self.assertSequenceEqual(
5456 PrintableString("x" * 128).encode(),
5457 hexdec("138180" + "78" * 128),
5459 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5461 class Seq(Sequence):
5463 ("erste", IA5String()),
5466 seq["erste"] = IA5String("test")
5467 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5469 class Seq(Sequence):
5471 ("erste", PrintableString()),
5474 seq["erste"] = PrintableString("test")
5475 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5476 seq["erste"] = PrintableString("test*")
5477 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5479 class Seq(Sequence):
5481 ("erste", Any(optional=True)),
5482 ("zweite", Integer()),
5485 seq["zweite"] = Integer(64)
5486 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5491 seq.append(Integer(10))
5492 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5494 class _SeqOf(SequenceOf):
5495 schema = PrintableString()
5497 class SeqOf(SequenceOf):
5500 _seqof.append(PrintableString("1"))
5502 seqof.append(_seqof)
5503 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5505 class Seq(Sequence):
5507 ("erste", Integer(default=1)),
5510 seq["erste"] = Integer(0)
5511 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5512 seq["erste"] = Integer(1)
5513 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5514 seq["erste"] = Integer(2)
5515 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5518 class TestPP(TestCase):
5519 @given(data_strategy())
5520 def test_oid_printing(self, d):
5522 str(ObjectIdentifier(k)): v * 2
5523 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5525 chosen = d.draw(sampled_from(sorted(oids)))
5526 chosen_id = oids[chosen]
5527 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5528 self.assertNotIn(chosen_id, pp_console_row(pp))
5529 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5532 class TestAutoAddSlots(TestCase):
5534 class Inher(Integer):
5537 with self.assertRaises(AttributeError):
5539 inher.unexistent = "whatever"
5542 class TestOIDDefines(TestCase):
5543 @given(data_strategy())
5544 def runTest(self, d):
5545 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5546 value_name_chosen = d.draw(sampled_from(value_names))
5548 ObjectIdentifier(oid)
5549 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5551 oid_chosen = d.draw(sampled_from(oids))
5552 values = d.draw(lists(
5554 min_size=len(value_names),
5555 max_size=len(value_names),
5558 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5559 oid: Integer() for oid in oids[:-1]
5562 for i, value_name in enumerate(value_names):
5563 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5565 class Seq(Sequence):
5568 for value_name, value in zip(value_names, values):
5569 seq[value_name] = Any(Integer(value).encode())
5570 seq["type"] = oid_chosen
5571 seq, _ = Seq().decode(seq.encode())
5572 for value_name in value_names:
5573 if value_name == value_name_chosen:
5575 self.assertIsNone(seq[value_name].defined)
5576 if value_name_chosen in oids[:-1]:
5577 self.assertIsNotNone(seq[value_name_chosen].defined)
5578 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5579 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5582 class TestDefinesByPath(TestCase):
5583 def test_generated(self):
5584 class Seq(Sequence):
5586 ("type", ObjectIdentifier()),
5587 ("value", OctetString(expl=tag_ctxc(123))),
5590 class SeqInner(Sequence):
5592 ("typeInner", ObjectIdentifier()),
5593 ("valueInner", Any()),
5596 class PairValue(SetOf):
5599 class Pair(Sequence):
5601 ("type", ObjectIdentifier()),
5602 ("value", PairValue()),
5605 class Pairs(SequenceOf):
5612 type_octet_stringed,
5614 ObjectIdentifier(oid)
5615 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5617 seq_integered = Seq()
5618 seq_integered["type"] = type_integered
5619 seq_integered["value"] = OctetString(Integer(123).encode())
5620 seq_integered_raw = seq_integered.encode()
5624 (type_octet_stringed, OctetString(b"whatever")),
5625 (type_integered, Integer(123)),
5626 (type_octet_stringed, OctetString(b"whenever")),
5627 (type_integered, Integer(234)),
5629 for t, v in pairs_input:
5632 pair["value"] = PairValue((Any(v),))
5634 seq_inner = SeqInner()
5635 seq_inner["typeInner"] = type_innered
5636 seq_inner["valueInner"] = Any(pairs)
5637 seq_sequenced = Seq()
5638 seq_sequenced["type"] = type_sequenced
5639 seq_sequenced["value"] = OctetString(seq_inner.encode())
5640 seq_sequenced_raw = seq_sequenced.encode()
5642 defines_by_path = []
5643 seq_integered, _ = Seq().decode(seq_integered_raw)
5644 self.assertIsNone(seq_integered["value"].defined)
5645 defines_by_path.append(
5646 (("type",), ((("value",), {
5647 type_integered: Integer(),
5648 type_sequenced: SeqInner(),
5651 seq_integered, _ = Seq().decode(
5653 ctx={"defines_by_path": defines_by_path},
5655 self.assertIsNotNone(seq_integered["value"].defined)
5656 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5657 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5658 self.assertTrue(seq_integered_raw[
5659 seq_integered["value"].defined[1].offset:
5660 ].startswith(Integer(123).encode()))
5662 seq_sequenced, _ = Seq().decode(
5664 ctx={"defines_by_path": defines_by_path},
5666 self.assertIsNotNone(seq_sequenced["value"].defined)
5667 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5668 seq_inner = seq_sequenced["value"].defined[1]
5669 self.assertIsNone(seq_inner["valueInner"].defined)
5671 defines_by_path.append((
5672 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5673 ((("valueInner",), {type_innered: Pairs()}),),
5675 seq_sequenced, _ = Seq().decode(
5677 ctx={"defines_by_path": defines_by_path},
5679 self.assertIsNotNone(seq_sequenced["value"].defined)
5680 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5681 seq_inner = seq_sequenced["value"].defined[1]
5682 self.assertIsNotNone(seq_inner["valueInner"].defined)
5683 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5684 pairs = seq_inner["valueInner"].defined[1]
5686 self.assertIsNone(pair["value"][0].defined)
5688 defines_by_path.append((
5691 DecodePathDefBy(type_sequenced),
5693 DecodePathDefBy(type_innered),
5698 type_integered: Integer(),
5699 type_octet_stringed: OctetString(),
5702 seq_sequenced, _ = Seq().decode(
5704 ctx={"defines_by_path": defines_by_path},
5706 self.assertIsNotNone(seq_sequenced["value"].defined)
5707 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5708 seq_inner = seq_sequenced["value"].defined[1]
5709 self.assertIsNotNone(seq_inner["valueInner"].defined)
5710 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5711 pairs_got = seq_inner["valueInner"].defined[1]
5712 for pair_input, pair_got in zip(pairs_input, pairs_got):
5713 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5714 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5716 @given(oid_strategy(), integers())
5717 def test_simple(self, oid, tgt):
5718 class Inner(Sequence):
5720 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5721 ObjectIdentifier(oid): Integer(),
5725 class Outer(Sequence):
5728 ("tgt", OctetString()),
5732 inner["oid"] = ObjectIdentifier(oid)
5734 outer["inner"] = inner
5735 outer["tgt"] = OctetString(Integer(tgt).encode())
5736 decoded, _ = Outer().decode(outer.encode())
5737 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5740 class TestAbsDecodePath(TestCase):
5742 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5743 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5745 def test_concat(self, decode_path, rel_path):
5746 self.assertSequenceEqual(
5747 abs_decode_path(decode_path, rel_path),
5748 decode_path + rel_path,
5752 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5753 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5755 def test_abs(self, decode_path, rel_path):
5756 self.assertSequenceEqual(
5757 abs_decode_path(decode_path, ("/",) + rel_path),
5762 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5763 integers(min_value=1, max_value=3),
5764 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5766 def test_dots(self, decode_path, number_of_dots, rel_path):
5767 self.assertSequenceEqual(
5768 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5769 decode_path[:-number_of_dots] + rel_path,
5773 class TestStrictDefaultExistence(TestCase):
5774 @given(data_strategy())
5775 def runTest(self, d):
5776 count = d.draw(integers(min_value=1, max_value=10))
5777 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5779 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5780 for i in range(count)
5783 class Seq(Sequence):
5786 for i in range(count):
5787 seq["int%d" % i] = Integer(123)
5789 chosen = "int%d" % chosen
5790 seq.specs[chosen] = seq.specs[chosen](default=123)
5792 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5793 seq.decode(raw, ctx={"strict_default_existence": True})
5796 class TestX690PrefixedType(TestCase):
5798 self.assertSequenceEqual(
5799 VisibleString("Jones").encode(),
5800 hexdec("1A054A6F6E6573"),
5802 self.assertSequenceEqual(
5805 impl=tag_encode(3, klass=TagClassApplication),
5807 hexdec("43054A6F6E6573"),
5809 self.assertSequenceEqual(
5813 impl=tag_encode(3, klass=TagClassApplication),
5817 hexdec("A20743054A6F6E6573"),
5819 self.assertSequenceEqual(
5823 impl=tag_encode(3, klass=TagClassApplication),
5825 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5827 hexdec("670743054A6F6E6573"),
5829 self.assertSequenceEqual(
5830 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5831 hexdec("82054A6F6E6573"),