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),
3613 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3614 base_klass = UTCTime
3616 min_datetime = datetime(2000, 1, 1)
3617 max_datetime = datetime(2049, 12, 31)
3619 def test_go_vectors_invalid(self):
3645 # These ones are INVALID in *DER*, but accepted
3646 # by Go's encoding/asn1
3647 b"910506164540-0700",
3648 b"910506164540+0730",
3652 with self.assertRaises(DecodeError) as err:
3656 def test_go_vectors_valid(self):
3658 UTCTime(b"910506234540Z").todatetime(),
3659 datetime(1991, 5, 6, 23, 45, 40, 0),
3662 @given(integers(min_value=0, max_value=49))
3663 def test_pre50(self, year):
3665 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3669 @given(integers(min_value=50, max_value=99))
3670 def test_post50(self, year):
3672 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3678 def any_values_strategy(draw, do_expl=False):
3679 value = draw(one_of(none(), binary()))
3682 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3683 optional = draw(one_of(none(), booleans()))
3685 draw(integers(min_value=0)),
3686 draw(integers(min_value=0)),
3687 draw(integers(min_value=0)),
3689 return (value, expl, optional, _decoded)
3692 class AnyInherited(Any):
3696 class TestAny(CommonMixin, TestCase):
3699 def test_invalid_value_type(self):
3700 with self.assertRaises(InvalidValueType) as err:
3705 def test_optional(self, optional):
3706 obj = Any(optional=optional)
3707 self.assertEqual(obj.optional, optional)
3710 def test_ready(self, value):
3712 self.assertFalse(obj.ready)
3715 with self.assertRaises(ObjNotReady) as err:
3719 self.assertTrue(obj.ready)
3724 def test_basic(self, value):
3725 integer_encoded = Integer(value).encode()
3727 Any(integer_encoded),
3728 Any(Integer(value)),
3729 Any(Any(Integer(value))),
3731 self.assertSequenceEqual(bytes(obj), integer_encoded)
3733 obj.decode(obj.encode())[0].vlen,
3734 len(integer_encoded),
3738 self.assertSequenceEqual(obj.encode(), integer_encoded)
3740 @given(binary(), binary())
3741 def test_comparison(self, value1, value2):
3742 for klass in (Any, AnyInherited):
3743 obj1 = klass(value1)
3744 obj2 = klass(value2)
3745 self.assertEqual(obj1 == obj2, value1 == value2)
3746 self.assertEqual(obj1 != obj2, value1 != value2)
3747 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3749 @given(data_strategy())
3750 def test_call(self, d):
3751 for klass in (Any, AnyInherited):
3757 ) = d.draw(any_values_strategy())
3758 obj_initial = klass(
3761 optional_initial or False,
3769 ) = d.draw(any_values_strategy(do_expl=True))
3770 obj = obj_initial(value, expl, optional)
3772 value_expected = None if value is None else value
3773 self.assertEqual(obj, value_expected)
3774 self.assertEqual(obj.expl_tag, expl or expl_initial)
3775 if obj.default is None:
3776 optional = optional_initial if optional is None else optional
3777 optional = False if optional is None else optional
3778 self.assertEqual(obj.optional, optional)
3780 def test_simultaneous_impl_expl(self):
3781 # override it, as Any does not have implicit tag
3784 def test_decoded(self):
3785 # override it, as Any does not have implicit tag
3788 @given(any_values_strategy())
3789 def test_copy(self, values):
3790 for klass in (Any, AnyInherited):
3791 obj = klass(*values)
3792 obj_copied = obj.copy()
3793 self.assert_copied_basic_fields(obj, obj_copied)
3794 self.assertEqual(obj._value, obj_copied._value)
3796 @given(binary().map(OctetString))
3797 def test_stripped(self, value):
3799 with self.assertRaises(NotEnoughData):
3800 obj.decode(obj.encode()[:-1])
3804 integers(min_value=1).map(tag_ctxc),
3806 def test_stripped_expl(self, value, tag_expl):
3807 obj = Any(value, expl=tag_expl)
3808 with self.assertRaises(NotEnoughData):
3809 obj.decode(obj.encode()[:-1])
3812 integers(min_value=31),
3813 integers(min_value=0),
3816 def test_bad_tag(self, tag, offset, decode_path):
3817 with self.assertRaises(DecodeError) as err:
3819 tag_encode(tag)[:-1],
3821 decode_path=decode_path,
3824 self.assertEqual(err.exception.offset, offset)
3825 self.assertEqual(err.exception.decode_path, decode_path)
3828 integers(min_value=128),
3829 integers(min_value=0),
3832 def test_bad_len(self, l, offset, decode_path):
3833 with self.assertRaises(DecodeError) as err:
3835 Any.tag_default + len_encode(l)[:-1],
3837 decode_path=decode_path,
3840 self.assertEqual(err.exception.offset, offset)
3841 self.assertEqual(err.exception.decode_path, decode_path)
3843 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3845 any_values_strategy(),
3846 integers().map(lambda x: Integer(x).encode()),
3847 integers(min_value=1).map(tag_ctxc),
3848 integers(min_value=0),
3851 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3852 for klass in (Any, AnyInherited):
3853 _, _, optional, _decoded = values
3854 obj = klass(value=value, optional=optional, _decoded=_decoded)
3857 self.assertFalse(obj.expled)
3858 obj_encoded = obj.encode()
3859 obj_expled = obj(value, expl=tag_expl)
3860 self.assertTrue(obj_expled.expled)
3863 obj_expled_encoded = obj_expled.encode()
3864 obj_decoded, tail = obj_expled.decode(
3865 obj_expled_encoded + tail_junk,
3870 self.assertEqual(tail, tail_junk)
3871 self.assertEqual(obj_decoded, obj_expled)
3872 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3873 self.assertEqual(bytes(obj_decoded), bytes(obj))
3874 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3875 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3876 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3878 obj_decoded.expl_llen,
3879 len(len_encode(len(obj_encoded))),
3881 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3882 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3885 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3887 self.assertEqual(obj_decoded.expl_offset, offset)
3888 self.assertEqual(obj_decoded.tlen, 0)
3889 self.assertEqual(obj_decoded.llen, 0)
3890 self.assertEqual(obj_decoded.vlen, len(value))
3893 integers(min_value=1).map(tag_ctxc),
3894 integers(min_value=0, max_value=3),
3895 integers(min_value=0),
3899 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
3900 chunk = Boolean(False, expl=expl).encode()
3902 OctetString.tag_default +
3904 b"".join([chunk] * chunks) +
3907 obj, tail = Any().decode(
3910 decode_path=decode_path,
3911 ctx={"bered": True},
3913 self.assertSequenceEqual(tail, junk)
3914 self.assertEqual(obj.offset, offset)
3915 self.assertEqual(obj.tlvlen, len(encoded))
3916 with self.assertRaises(NotEnoughData) as err:
3920 decode_path=decode_path,
3921 ctx={"bered": True},
3923 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
3924 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
3928 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3930 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3931 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
3933 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
3934 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
3936 min_size=len(names),
3937 max_size=len(names),
3940 (name, Integer(**tag_kwargs))
3941 for name, tag_kwargs in zip(names, tags)
3944 if value_required or draw(booleans()):
3945 value = draw(tuples(
3946 sampled_from([name for name, _ in schema]),
3947 integers().map(Integer),
3951 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3952 default = draw(one_of(
3954 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3956 optional = draw(one_of(none(), booleans()))
3958 draw(integers(min_value=0)),
3959 draw(integers(min_value=0)),
3960 draw(integers(min_value=0)),
3962 return (schema, value, expl, default, optional, _decoded)
3965 class ChoiceInherited(Choice):
3969 class TestChoice(CommonMixin, TestCase):
3971 schema = (("whatever", Boolean()),)
3974 def test_schema_required(self):
3975 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3978 def test_impl_forbidden(self):
3979 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3980 Choice(impl=b"whatever")
3982 def test_invalid_value_type(self):
3983 with self.assertRaises(InvalidValueType) as err:
3984 self.base_klass(123)
3986 with self.assertRaises(ObjUnknown) as err:
3987 self.base_klass(("whenever", Boolean(False)))
3989 with self.assertRaises(InvalidValueType) as err:
3990 self.base_klass(("whatever", Integer(123)))
3994 def test_optional(self, optional):
3995 obj = self.base_klass(
3996 default=self.base_klass(("whatever", Boolean(False))),
3999 self.assertTrue(obj.optional)
4002 def test_ready(self, value):
4003 obj = self.base_klass()
4004 self.assertFalse(obj.ready)
4007 self.assertIsNone(obj["whatever"])
4008 with self.assertRaises(ObjNotReady) as err:
4011 obj["whatever"] = Boolean()
4012 self.assertFalse(obj.ready)
4015 obj["whatever"] = Boolean(value)
4016 self.assertTrue(obj.ready)
4020 @given(booleans(), booleans())
4021 def test_comparison(self, value1, value2):
4022 class WahlInherited(self.base_klass):
4024 for klass in (self.base_klass, WahlInherited):
4025 obj1 = klass(("whatever", Boolean(value1)))
4026 obj2 = klass(("whatever", Boolean(value2)))
4027 self.assertEqual(obj1 == obj2, value1 == value2)
4028 self.assertEqual(obj1 != obj2, value1 != value2)
4029 self.assertEqual(obj1 == obj2._value, value1 == value2)
4030 self.assertFalse(obj1 == obj2._value[1])
4032 @given(data_strategy())
4033 def test_call(self, d):
4034 for klass in (Choice, ChoiceInherited):
4042 ) = d.draw(choice_values_strategy())
4045 schema = schema_initial
4047 value=value_initial,
4049 default=default_initial,
4050 optional=optional_initial or False,
4051 _decoded=_decoded_initial,
4060 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4061 obj = obj_initial(value, expl, default, optional)
4063 value_expected = default if value is None else value
4065 default_initial if value_expected is None
4068 self.assertEqual(obj.choice, value_expected[0])
4069 self.assertEqual(obj.value, int(value_expected[1]))
4070 self.assertEqual(obj.expl_tag, expl or expl_initial)
4071 default_expect = default_initial if default is None else default
4072 if default_expect is not None:
4073 self.assertEqual(obj.default.choice, default_expect[0])
4074 self.assertEqual(obj.default.value, int(default_expect[1]))
4075 if obj.default is None:
4076 optional = optional_initial if optional is None else optional
4077 optional = False if optional is None else optional
4080 self.assertEqual(obj.optional, optional)
4081 self.assertEqual(obj.specs, obj_initial.specs)
4083 def test_simultaneous_impl_expl(self):
4084 # override it, as Any does not have implicit tag
4087 def test_decoded(self):
4088 # override it, as Any does not have implicit tag
4091 @given(choice_values_strategy())
4092 def test_copy(self, values):
4093 _schema, value, expl, default, optional, _decoded = values
4095 class Wahl(self.base_klass):
4101 optional=optional or False,
4104 obj_copied = obj.copy()
4105 self.assertIsNone(obj.tag)
4106 self.assertIsNone(obj_copied.tag)
4107 # hack for assert_copied_basic_fields
4108 obj.tag = "whatever"
4109 obj_copied.tag = "whatever"
4110 self.assert_copied_basic_fields(obj, obj_copied)
4111 self.assertEqual(obj._value, obj_copied._value)
4112 self.assertEqual(obj.specs, obj_copied.specs)
4115 def test_stripped(self, value):
4116 obj = self.base_klass(("whatever", Boolean(value)))
4117 with self.assertRaises(NotEnoughData):
4118 obj.decode(obj.encode()[:-1])
4122 integers(min_value=1).map(tag_ctxc),
4124 def test_stripped_expl(self, value, tag_expl):
4125 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4126 with self.assertRaises(NotEnoughData):
4127 obj.decode(obj.encode()[:-1])
4129 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4130 @given(data_strategy())
4131 def test_symmetric(self, d):
4132 _schema, value, _, default, optional, _decoded = d.draw(
4133 choice_values_strategy(value_required=True)
4135 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4136 offset = d.draw(integers(min_value=0))
4137 tail_junk = d.draw(binary(max_size=5))
4139 class Wahl(self.base_klass):
4149 self.assertFalse(obj.expled)
4150 obj_encoded = obj.encode()
4151 obj_expled = obj(value, expl=tag_expl)
4152 self.assertTrue(obj_expled.expled)
4155 obj_expled_encoded = obj_expled.encode()
4156 obj_decoded, tail = obj_expled.decode(
4157 obj_expled_encoded + tail_junk,
4162 self.assertEqual(tail, tail_junk)
4163 self.assertEqual(obj_decoded, obj_expled)
4164 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4165 self.assertEqual(obj_decoded.value, obj_expled.value)
4166 self.assertEqual(obj_decoded.choice, obj.choice)
4167 self.assertEqual(obj_decoded.value, obj.value)
4168 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4169 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4170 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4172 obj_decoded.expl_llen,
4173 len(len_encode(len(obj_encoded))),
4175 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4176 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4179 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4181 self.assertEqual(obj_decoded.expl_offset, offset)
4182 self.assertSequenceEqual(
4184 obj_decoded.value.fulloffset - offset:
4185 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
4191 def test_set_get(self, value):
4194 ("erste", Boolean()),
4195 ("zweite", Integer()),
4198 with self.assertRaises(ObjUnknown) as err:
4199 obj["whatever"] = "whenever"
4200 with self.assertRaises(InvalidValueType) as err:
4201 obj["zweite"] = Boolean(False)
4202 obj["zweite"] = Integer(value)
4204 with self.assertRaises(ObjUnknown) as err:
4207 self.assertIsNone(obj["erste"])
4208 self.assertEqual(obj["zweite"], Integer(value))
4210 def test_tag_mismatch(self):
4213 ("erste", Boolean()),
4215 int_encoded = Integer(123).encode()
4216 bool_encoded = Boolean(False).encode()
4218 obj.decode(bool_encoded)
4219 with self.assertRaises(TagMismatch):
4220 obj.decode(int_encoded)
4222 def test_tag_mismatch_underlying(self):
4223 class SeqOfBoolean(SequenceOf):
4226 class SeqOfInteger(SequenceOf):
4231 ("erste", SeqOfBoolean()),
4234 int_encoded = SeqOfInteger((Integer(123),)).encode()
4235 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4237 obj.decode(bool_encoded)
4238 with self.assertRaises(TagMismatch) as err:
4239 obj.decode(int_encoded)
4240 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4244 def seq_values_strategy(draw, seq_klass, do_expl=False):
4246 if draw(booleans()):
4249 k: v for k, v in draw(dictionaries(
4252 booleans().map(Boolean),
4253 integers().map(Integer),
4258 if draw(booleans()):
4259 schema = list(draw(dictionaries(
4262 booleans().map(Boolean),
4263 integers().map(Integer),
4269 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4271 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4273 if draw(booleans()):
4274 default = seq_klass()
4276 k: v for k, v in draw(dictionaries(
4279 booleans().map(Boolean),
4280 integers().map(Integer),
4284 optional = draw(one_of(none(), booleans()))
4286 draw(integers(min_value=0)),
4287 draw(integers(min_value=0)),
4288 draw(integers(min_value=0)),
4290 return (value, schema, impl, expl, default, optional, _decoded)
4294 def sequence_strategy(draw, seq_klass):
4295 inputs = draw(lists(
4297 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4298 tuples(just(Integer), integers(), one_of(none(), integers())),
4303 integers(min_value=1),
4304 min_size=len(inputs),
4305 max_size=len(inputs),
4308 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4309 for tag, expled in zip(tags, draw(lists(
4311 min_size=len(inputs),
4312 max_size=len(inputs),
4316 for i, optional in enumerate(draw(lists(
4317 sampled_from(("required", "optional", "empty")),
4318 min_size=len(inputs),
4319 max_size=len(inputs),
4321 if optional in ("optional", "empty"):
4322 inits[i]["optional"] = True
4323 if optional == "empty":
4325 empties = set(empties)
4326 names = list(draw(sets(
4328 min_size=len(inputs),
4329 max_size=len(inputs),
4332 for i, (klass, value, default) in enumerate(inputs):
4333 schema.append((names[i], klass(default=default, **inits[i])))
4334 seq_name = draw(text_letters())
4335 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4338 for i, (klass, value, default) in enumerate(inputs):
4345 "default_value": None if spec.default is None else default,
4349 expect["optional"] = True
4351 expect["presented"] = True
4352 expect["value"] = value
4354 expect["optional"] = True
4355 if default is not None and default == value:
4356 expect["presented"] = False
4357 seq[name] = klass(value)
4358 expects.append(expect)
4363 def sequences_strategy(draw, seq_klass):
4364 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4366 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4367 for tag, expled in zip(tags, draw(lists(
4374 i for i, is_default in enumerate(draw(lists(
4380 names = list(draw(sets(
4385 seq_expectses = draw(lists(
4386 sequence_strategy(seq_klass=seq_klass),
4390 seqs = [seq for seq, _ in seq_expectses]
4392 for i, (name, seq) in enumerate(zip(names, seqs)):
4395 seq(default=(seq if i in defaulted else None), **inits[i]),
4397 seq_name = draw(text_letters())
4398 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4401 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4404 "expects": expects_inner,
4407 seq_outer[name] = seq_inner
4408 if seq_outer.specs[name].default is None:
4409 expect["presented"] = True
4410 expect_outers.append(expect)
4411 return seq_outer, expect_outers
4414 class SeqMixing(object):
4415 def test_invalid_value_type(self):
4416 with self.assertRaises(InvalidValueType) as err:
4417 self.base_klass(123)
4420 def test_invalid_value_type_set(self):
4421 class Seq(self.base_klass):
4422 schema = (("whatever", Boolean()),)
4424 with self.assertRaises(InvalidValueType) as err:
4425 seq["whatever"] = Integer(123)
4429 def test_optional(self, optional):
4430 obj = self.base_klass(default=self.base_klass(), optional=optional)
4431 self.assertTrue(obj.optional)
4433 @given(data_strategy())
4434 def test_ready(self, d):
4436 str(i): v for i, v in enumerate(d.draw(lists(
4443 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4450 for name in d.draw(permutations(
4451 list(ready.keys()) + list(non_ready.keys()),
4453 schema_input.append((name, Boolean()))
4455 class Seq(self.base_klass):
4456 schema = tuple(schema_input)
4458 for name in ready.keys():
4460 seq[name] = Boolean()
4461 self.assertFalse(seq.ready)
4464 for name, value in ready.items():
4465 seq[name] = Boolean(value)
4466 self.assertFalse(seq.ready)
4469 with self.assertRaises(ObjNotReady) as err:
4472 for name, value in non_ready.items():
4473 seq[name] = Boolean(value)
4474 self.assertTrue(seq.ready)
4478 @given(data_strategy())
4479 def test_call(self, d):
4480 class SeqInherited(self.base_klass):
4482 for klass in (self.base_klass, SeqInherited):
4491 ) = d.draw(seq_values_strategy(seq_klass=klass))
4492 obj_initial = klass(
4498 optional_initial or False,
4509 ) = d.draw(seq_values_strategy(
4511 do_expl=impl_initial is None,
4513 obj = obj_initial(value, impl, expl, default, optional)
4514 value_expected = default if value is None else value
4516 default_initial if value_expected is None
4519 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4520 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4521 self.assertEqual(obj.expl_tag, expl or expl_initial)
4523 {} if obj.default is None else obj.default._value,
4524 getattr(default_initial if default is None else default, "_value", {}),
4526 if obj.default is None:
4527 optional = optional_initial if optional is None else optional
4528 optional = False if optional is None else optional
4531 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4532 self.assertEqual(obj.optional, optional)
4534 @given(data_strategy())
4535 def test_copy(self, d):
4536 class SeqInherited(self.base_klass):
4538 for klass in (self.base_klass, SeqInherited):
4539 values = d.draw(seq_values_strategy(seq_klass=klass))
4540 obj = klass(*values)
4541 obj_copied = obj.copy()
4542 self.assert_copied_basic_fields(obj, obj_copied)
4543 self.assertEqual(obj.specs, obj_copied.specs)
4544 self.assertEqual(obj._value, obj_copied._value)
4546 @given(data_strategy())
4547 def test_stripped(self, d):
4548 value = d.draw(integers())
4549 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4551 class Seq(self.base_klass):
4553 schema = (("whatever", Integer()),)
4555 seq["whatever"] = Integer(value)
4556 with self.assertRaises(NotEnoughData):
4557 seq.decode(seq.encode()[:-1])
4559 @given(data_strategy())
4560 def test_stripped_expl(self, d):
4561 value = d.draw(integers())
4562 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4564 class Seq(self.base_klass):
4566 schema = (("whatever", Integer()),)
4568 seq["whatever"] = Integer(value)
4569 with self.assertRaises(NotEnoughData):
4570 seq.decode(seq.encode()[:-1])
4572 @given(binary(min_size=2))
4573 def test_non_tag_mismatch_raised(self, junk):
4575 _, _, len_encoded = tag_strip(memoryview(junk))
4576 len_decode(len_encoded)
4582 class Seq(self.base_klass):
4584 ("whatever", Integer()),
4586 ("whenever", Integer()),
4589 seq["whatever"] = Integer(123)
4590 seq["junk"] = Any(junk)
4591 seq["whenever"] = Integer(123)
4592 with self.assertRaises(DecodeError):
4593 seq.decode(seq.encode())
4596 integers(min_value=31),
4597 integers(min_value=0),
4600 def test_bad_tag(self, tag, offset, decode_path):
4601 with self.assertRaises(DecodeError) as err:
4602 self.base_klass().decode(
4603 tag_encode(tag)[:-1],
4605 decode_path=decode_path,
4608 self.assertEqual(err.exception.offset, offset)
4609 self.assertEqual(err.exception.decode_path, decode_path)
4612 integers(min_value=128),
4613 integers(min_value=0),
4616 def test_bad_len(self, l, offset, decode_path):
4617 with self.assertRaises(DecodeError) as err:
4618 self.base_klass().decode(
4619 self.base_klass.tag_default + len_encode(l)[:-1],
4621 decode_path=decode_path,
4624 self.assertEqual(err.exception.offset, offset)
4625 self.assertEqual(err.exception.decode_path, decode_path)
4627 def _assert_expects(self, seq, expects):
4628 for expect in expects:
4630 seq.specs[expect["name"]].optional,
4633 if expect["default_value"] is not None:
4635 seq.specs[expect["name"]].default,
4636 expect["default_value"],
4638 if expect["presented"]:
4639 self.assertIn(expect["name"], seq)
4640 self.assertEqual(seq[expect["name"]], expect["value"])
4642 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4643 @given(data_strategy())
4644 def test_symmetric(self, d):
4645 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4646 tail_junk = d.draw(binary(max_size=5))
4647 self.assertTrue(seq.ready)
4648 self.assertFalse(seq.decoded)
4649 self._assert_expects(seq, expects)
4652 self.assertTrue(seq.ready)
4653 seq_encoded = seq.encode()
4654 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4655 self.assertFalse(seq_decoded.lenindef)
4657 t, _, lv = tag_strip(seq_encoded)
4658 _, _, v = len_decode(lv)
4659 seq_encoded_lenindef = t + LENINDEF + v + EOC
4660 seq_decoded_lenindef, tail_lenindef = seq.decode(
4661 seq_encoded_lenindef + tail_junk,
4662 ctx={"bered": True},
4664 self.assertTrue(seq_decoded_lenindef.lenindef)
4665 with self.assertRaises(DecodeError):
4666 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4667 with self.assertRaises(DecodeError):
4668 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4669 repr(seq_decoded_lenindef)
4670 pprint(seq_decoded_lenindef)
4671 self.assertTrue(seq_decoded_lenindef.ready)
4673 for decoded, decoded_tail, encoded in (
4674 (seq_decoded, tail, seq_encoded),
4675 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4677 self.assertEqual(decoded_tail, tail_junk)
4678 self._assert_expects(decoded, expects)
4679 self.assertEqual(seq, decoded)
4680 self.assertEqual(decoded.encode(), seq_encoded)
4681 self.assertEqual(decoded.tlvlen, len(encoded))
4682 for expect in expects:
4683 if not expect["presented"]:
4684 self.assertNotIn(expect["name"], decoded)
4686 self.assertIn(expect["name"], decoded)
4687 obj = decoded[expect["name"]]
4688 self.assertTrue(obj.decoded)
4689 offset = obj.expl_offset if obj.expled else obj.offset
4690 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4691 self.assertSequenceEqual(
4692 seq_encoded[offset:offset + tlvlen],
4696 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4697 @given(data_strategy())
4698 def test_symmetric_with_seq(self, d):
4699 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4700 self.assertTrue(seq.ready)
4701 seq_encoded = seq.encode()
4702 seq_decoded, tail = seq.decode(seq_encoded)
4703 self.assertEqual(tail, b"")
4704 self.assertTrue(seq.ready)
4705 self.assertEqual(seq, seq_decoded)
4706 self.assertEqual(seq_decoded.encode(), seq_encoded)
4707 for expect_outer in expect_outers:
4708 if not expect_outer["presented"]:
4709 self.assertNotIn(expect_outer["name"], seq_decoded)
4711 self.assertIn(expect_outer["name"], seq_decoded)
4712 obj = seq_decoded[expect_outer["name"]]
4713 self.assertTrue(obj.decoded)
4714 offset = obj.expl_offset if obj.expled else obj.offset
4715 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4716 self.assertSequenceEqual(
4717 seq_encoded[offset:offset + tlvlen],
4720 self._assert_expects(obj, expect_outer["expects"])
4722 @given(data_strategy())
4723 def test_default_disappears(self, d):
4724 _schema = list(d.draw(dictionaries(
4726 sets(integers(), min_size=2, max_size=2),
4730 class Seq(self.base_klass):
4732 (n, Integer(default=d))
4733 for n, (_, d) in _schema
4736 for name, (value, _) in _schema:
4737 seq[name] = Integer(value)
4738 self.assertEqual(len(seq._value), len(_schema))
4739 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4740 self.assertGreater(len(seq.encode()), len(empty_seq))
4741 for name, (_, default) in _schema:
4742 seq[name] = Integer(default)
4743 self.assertEqual(len(seq._value), 0)
4744 self.assertSequenceEqual(seq.encode(), empty_seq)
4746 @given(data_strategy())
4747 def test_encoded_default_accepted(self, d):
4748 _schema = list(d.draw(dictionaries(
4753 tags = [tag_encode(tag) for tag in d.draw(sets(
4754 integers(min_value=0),
4755 min_size=len(_schema),
4756 max_size=len(_schema),
4759 class SeqWithoutDefault(self.base_klass):
4761 (n, Integer(impl=t))
4762 for (n, _), t in zip(_schema, tags)
4764 seq_without_default = SeqWithoutDefault()
4765 for name, value in _schema:
4766 seq_without_default[name] = Integer(value)
4767 seq_encoded = seq_without_default.encode()
4769 class SeqWithDefault(self.base_klass):
4771 (n, Integer(default=v, impl=t))
4772 for (n, v), t in zip(_schema, tags)
4774 seq_with_default = SeqWithDefault()
4775 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4776 for name, value in _schema:
4777 self.assertEqual(seq_decoded[name], seq_with_default[name])
4778 self.assertEqual(seq_decoded[name], value)
4780 @given(data_strategy())
4781 def test_missing_from_spec(self, d):
4782 names = list(d.draw(sets(text_letters(), min_size=2)))
4783 tags = [tag_encode(tag) for tag in d.draw(sets(
4784 integers(min_value=0),
4785 min_size=len(names),
4786 max_size=len(names),
4788 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4790 class SeqFull(self.base_klass):
4791 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4792 seq_full = SeqFull()
4793 for i, name in enumerate(names):
4794 seq_full[name] = Integer(i)
4795 seq_encoded = seq_full.encode()
4796 altered = names_tags[:-2] + names_tags[-1:]
4798 class SeqMissing(self.base_klass):
4799 schema = [(n, Integer(impl=t)) for n, t in altered]
4800 seq_missing = SeqMissing()
4801 with self.assertRaises(TagMismatch):
4802 seq_missing.decode(seq_encoded)
4805 class TestSequence(SeqMixing, CommonMixin, TestCase):
4806 base_klass = Sequence
4812 def test_remaining(self, value, junk):
4813 class Seq(Sequence):
4815 ("whatever", Integer()),
4817 int_encoded = Integer(value).encode()
4819 Sequence.tag_default,
4820 len_encode(len(int_encoded + junk)),
4823 with assertRaisesRegex(self, DecodeError, "remaining"):
4824 Seq().decode(junked)
4826 @given(sets(text_letters(), min_size=2))
4827 def test_obj_unknown(self, names):
4828 missing = names.pop()
4830 class Seq(Sequence):
4831 schema = [(n, Boolean()) for n in names]
4833 with self.assertRaises(ObjUnknown) as err:
4836 with self.assertRaises(ObjUnknown) as err:
4837 seq[missing] = Boolean()
4840 def test_x690_vector(self):
4841 class Seq(Sequence):
4843 ("name", IA5String()),
4846 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4847 self.assertEqual(seq["name"], "Smith")
4848 self.assertEqual(seq["ok"], True)
4851 class TestSet(SeqMixing, CommonMixin, TestCase):
4854 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4855 @given(data_strategy())
4856 def test_sorted(self, d):
4858 tag_encode(tag) for tag in
4859 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4863 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4865 for name, _ in Seq.schema:
4866 seq[name] = OctetString(b"")
4867 seq_encoded = seq.encode()
4868 seq_decoded, _ = seq.decode(seq_encoded)
4869 self.assertSequenceEqual(
4870 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4871 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4876 def seqof_values_strategy(draw, schema=None, do_expl=False):
4878 schema = draw(sampled_from((Boolean(), Integer())))
4879 bound_min, bound_max = sorted(draw(sets(
4880 integers(min_value=0, max_value=10),
4884 if isinstance(schema, Boolean):
4885 values_generator = booleans().map(Boolean)
4886 elif isinstance(schema, Integer):
4887 values_generator = integers().map(Integer)
4888 values_generator = lists(
4893 values = draw(one_of(none(), values_generator))
4897 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4899 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4900 default = draw(one_of(none(), values_generator))
4901 optional = draw(one_of(none(), booleans()))
4903 draw(integers(min_value=0)),
4904 draw(integers(min_value=0)),
4905 draw(integers(min_value=0)),
4910 (bound_min, bound_max),
4919 class SeqOfMixing(object):
4920 def test_invalid_value_type(self):
4921 with self.assertRaises(InvalidValueType) as err:
4922 self.base_klass(123)
4925 def test_invalid_values_type(self):
4926 class SeqOf(self.base_klass):
4928 with self.assertRaises(InvalidValueType) as err:
4929 SeqOf([Integer(123), Boolean(False), Integer(234)])
4932 def test_schema_required(self):
4933 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4934 self.base_klass.__mro__[1]()
4936 @given(booleans(), booleans(), binary(), binary())
4937 def test_comparison(self, value1, value2, tag1, tag2):
4938 class SeqOf(self.base_klass):
4940 obj1 = SeqOf([Boolean(value1)])
4941 obj2 = SeqOf([Boolean(value2)])
4942 self.assertEqual(obj1 == obj2, value1 == value2)
4943 self.assertEqual(obj1 != obj2, value1 != value2)
4944 self.assertEqual(obj1 == list(obj2), value1 == value2)
4945 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4946 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4947 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4948 self.assertEqual(obj1 == obj2, tag1 == tag2)
4949 self.assertEqual(obj1 != obj2, tag1 != tag2)
4951 @given(lists(booleans()))
4952 def test_iter(self, values):
4953 class SeqOf(self.base_klass):
4955 obj = SeqOf([Boolean(value) for value in values])
4956 self.assertEqual(len(obj), len(values))
4957 for i, value in enumerate(obj):
4958 self.assertEqual(value, values[i])
4960 @given(data_strategy())
4961 def test_ready(self, d):
4962 ready = [Integer(v) for v in d.draw(lists(
4969 range(d.draw(integers(min_value=1, max_value=5)))
4972 class SeqOf(self.base_klass):
4974 values = d.draw(permutations(ready + non_ready))
4976 for value in values:
4978 self.assertFalse(seqof.ready)
4981 with self.assertRaises(ObjNotReady) as err:
4984 for i, value in enumerate(values):
4985 self.assertEqual(seqof[i], value)
4986 if not seqof[i].ready:
4987 seqof[i] = Integer(i)
4988 self.assertTrue(seqof.ready)
4992 def test_spec_mismatch(self):
4993 class SeqOf(self.base_klass):
4996 seqof.append(Integer(123))
4997 with self.assertRaises(ValueError):
4998 seqof.append(Boolean(False))
4999 with self.assertRaises(ValueError):
5000 seqof[0] = Boolean(False)
5002 @given(data_strategy())
5003 def test_bounds_satisfied(self, d):
5004 class SeqOf(self.base_klass):
5006 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5007 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5008 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5009 SeqOf(value=value, bounds=(bound_min, bound_max))
5011 @given(data_strategy())
5012 def test_bounds_unsatisfied(self, d):
5013 class SeqOf(self.base_klass):
5015 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5016 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5017 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
5018 with self.assertRaises(BoundsError) as err:
5019 SeqOf(value=value, bounds=(bound_min, bound_max))
5021 value = [Boolean()] * d.draw(integers(
5022 min_value=bound_max + 1,
5023 max_value=bound_max + 10,
5025 with self.assertRaises(BoundsError) as err:
5026 SeqOf(value=value, bounds=(bound_min, bound_max))
5029 @given(integers(min_value=1, max_value=10))
5030 def test_out_of_bounds(self, bound_max):
5031 class SeqOf(self.base_klass):
5033 bounds = (0, bound_max)
5035 for _ in range(bound_max):
5036 seqof.append(Integer(123))
5037 with self.assertRaises(BoundsError):
5038 seqof.append(Integer(123))
5040 @given(data_strategy())
5041 def test_call(self, d):
5051 ) = d.draw(seqof_values_strategy())
5053 class SeqOf(self.base_klass):
5054 schema = schema_initial
5055 obj_initial = SeqOf(
5056 value=value_initial,
5057 bounds=bounds_initial,
5060 default=default_initial,
5061 optional=optional_initial or False,
5062 _decoded=_decoded_initial,
5073 ) = d.draw(seqof_values_strategy(
5074 schema=schema_initial,
5075 do_expl=impl_initial is None,
5077 if (default is None) and (obj_initial.default is not None):
5080 (bounds is None) and
5081 (value is not None) and
5082 (bounds_initial is not None) and
5083 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5087 (bounds is None) and
5088 (default is not None) and
5089 (bounds_initial is not None) and
5090 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5102 value_expected = default if value is None else value
5104 default_initial if value_expected is None
5107 value_expected = () if value_expected is None else value_expected
5108 self.assertEqual(obj, value_expected)
5109 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5110 self.assertEqual(obj.expl_tag, expl or expl_initial)
5113 default_initial if default is None else default,
5115 if obj.default is None:
5116 optional = optional_initial if optional is None else optional
5117 optional = False if optional is None else optional
5120 self.assertEqual(obj.optional, optional)
5122 (obj._bound_min, obj._bound_max),
5123 bounds or bounds_initial or (0, float("+inf")),
5126 @given(seqof_values_strategy())
5127 def test_copy(self, values):
5128 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5130 class SeqOf(self.base_klass):
5138 optional=optional or False,
5141 obj_copied = obj.copy()
5142 self.assert_copied_basic_fields(obj, obj_copied)
5143 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5144 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5145 self.assertEqual(obj._value, obj_copied._value)
5149 integers(min_value=1).map(tag_encode),
5151 def test_stripped(self, values, tag_impl):
5152 class SeqOf(self.base_klass):
5153 schema = OctetString()
5154 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5155 with self.assertRaises(NotEnoughData):
5156 obj.decode(obj.encode()[:-1])
5160 integers(min_value=1).map(tag_ctxc),
5162 def test_stripped_expl(self, values, tag_expl):
5163 class SeqOf(self.base_klass):
5164 schema = OctetString()
5165 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5166 with self.assertRaises(NotEnoughData):
5167 obj.decode(obj.encode()[:-1])
5170 integers(min_value=31),
5171 integers(min_value=0),
5174 def test_bad_tag(self, tag, offset, decode_path):
5175 with self.assertRaises(DecodeError) as err:
5176 self.base_klass().decode(
5177 tag_encode(tag)[:-1],
5179 decode_path=decode_path,
5182 self.assertEqual(err.exception.offset, offset)
5183 self.assertEqual(err.exception.decode_path, decode_path)
5186 integers(min_value=128),
5187 integers(min_value=0),
5190 def test_bad_len(self, l, offset, decode_path):
5191 with self.assertRaises(DecodeError) as err:
5192 self.base_klass().decode(
5193 self.base_klass.tag_default + len_encode(l)[:-1],
5195 decode_path=decode_path,
5198 self.assertEqual(err.exception.offset, offset)
5199 self.assertEqual(err.exception.decode_path, decode_path)
5201 @given(binary(min_size=1))
5202 def test_tag_mismatch(self, impl):
5203 assume(impl != self.base_klass.tag_default)
5204 with self.assertRaises(TagMismatch):
5205 self.base_klass(impl=impl).decode(self.base_klass().encode())
5207 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5209 seqof_values_strategy(schema=Integer()),
5210 lists(integers().map(Integer)),
5211 integers(min_value=1).map(tag_ctxc),
5212 integers(min_value=0),
5215 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5216 _, _, _, _, _, default, optional, _decoded = values
5218 class SeqOf(self.base_klass):
5228 self.assertFalse(obj.expled)
5229 obj_encoded = obj.encode()
5230 obj_expled = obj(value, expl=tag_expl)
5231 self.assertTrue(obj_expled.expled)
5234 obj_expled_encoded = obj_expled.encode()
5235 obj_decoded, tail = obj_expled.decode(
5236 obj_expled_encoded + tail_junk,
5241 self.assertEqual(tail, tail_junk)
5242 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5243 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5244 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5245 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5247 obj_decoded.expl_llen,
5248 len(len_encode(len(obj_encoded))),
5250 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5251 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5254 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5256 self.assertEqual(obj_decoded.expl_offset, offset)
5257 for obj_inner in obj_decoded:
5258 self.assertIn(obj_inner, obj_decoded)
5259 self.assertSequenceEqual(
5262 obj_inner.offset - offset:
5263 obj_inner.offset + obj_inner.tlvlen - offset
5267 t, _, lv = tag_strip(obj_encoded)
5268 _, _, v = len_decode(lv)
5269 obj_encoded_lenindef = t + LENINDEF + v + EOC
5270 obj_decoded_lenindef, tail_lenindef = obj.decode(
5271 obj_encoded_lenindef + tail_junk,
5272 ctx={"bered": True},
5274 self.assertTrue(obj_decoded_lenindef.lenindef)
5275 repr(obj_decoded_lenindef)
5276 pprint(obj_decoded_lenindef)
5277 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5278 with self.assertRaises(DecodeError):
5279 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5280 with self.assertRaises(DecodeError):
5281 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5284 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5285 class SeqOf(SequenceOf):
5289 def _test_symmetric_compare_objs(self, obj1, obj2):
5290 self.assertEqual(obj1, obj2)
5291 self.assertSequenceEqual(list(obj1), list(obj2))
5294 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5299 def _test_symmetric_compare_objs(self, obj1, obj2):
5300 self.assertSetEqual(
5301 set(int(v) for v in obj1),
5302 set(int(v) for v in obj2),
5305 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5306 @given(data_strategy())
5307 def test_sorted(self, d):
5308 values = [OctetString(v) for v in d.draw(lists(binary()))]
5311 schema = OctetString()
5313 seq_encoded = seq.encode()
5314 seq_decoded, _ = seq.decode(seq_encoded)
5315 self.assertSequenceEqual(
5316 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5317 b"".join(sorted([v.encode() for v in values])),
5321 class TestGoMarshalVectors(TestCase):
5323 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5324 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5325 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5326 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5327 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5329 class Seq(Sequence):
5331 ("erste", Integer()),
5332 ("zweite", Integer(optional=True))
5335 seq["erste"] = Integer(64)
5336 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5337 seq["erste"] = Integer(0x123456)
5338 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5339 seq["erste"] = Integer(64)
5340 seq["zweite"] = Integer(65)
5341 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5343 class NestedSeq(Sequence):
5347 seq["erste"] = Integer(127)
5348 seq["zweite"] = None
5349 nested = NestedSeq()
5350 nested["nest"] = seq
5351 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5353 self.assertSequenceEqual(
5354 OctetString(b"\x01\x02\x03").encode(),
5355 hexdec("0403010203"),
5358 class Seq(Sequence):
5360 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5363 seq["erste"] = Integer(64)
5364 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5366 class Seq(Sequence):
5368 ("erste", Integer(expl=tag_ctxc(5))),
5371 seq["erste"] = Integer(64)
5372 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5374 class Seq(Sequence):
5377 impl=tag_encode(0, klass=TagClassContext),
5382 seq["erste"] = Null()
5383 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5385 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5387 self.assertSequenceEqual(
5388 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5389 hexdec("170d3730303130313030303030305a"),
5391 self.assertSequenceEqual(
5392 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5393 hexdec("170d3039313131353232353631365a"),
5395 self.assertSequenceEqual(
5396 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5397 hexdec("180f32313030303430353132303130315a"),
5400 class Seq(Sequence):
5402 ("erste", GeneralizedTime()),
5405 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5406 self.assertSequenceEqual(
5408 hexdec("3011180f32303039313131353232353631365a"),
5411 self.assertSequenceEqual(
5412 BitString((1, b"\x80")).encode(),
5415 self.assertSequenceEqual(
5416 BitString((12, b"\x81\xF0")).encode(),
5417 hexdec("03030481f0"),
5420 self.assertSequenceEqual(
5421 ObjectIdentifier("1.2.3.4").encode(),
5422 hexdec("06032a0304"),
5424 self.assertSequenceEqual(
5425 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5426 hexdec("06092a864888932d010105"),
5428 self.assertSequenceEqual(
5429 ObjectIdentifier("2.100.3").encode(),
5430 hexdec("0603813403"),
5433 self.assertSequenceEqual(
5434 PrintableString("test").encode(),
5435 hexdec("130474657374"),
5437 self.assertSequenceEqual(
5438 PrintableString("x" * 127).encode(),
5439 hexdec("137F" + "78" * 127),
5441 self.assertSequenceEqual(
5442 PrintableString("x" * 128).encode(),
5443 hexdec("138180" + "78" * 128),
5445 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5447 class Seq(Sequence):
5449 ("erste", IA5String()),
5452 seq["erste"] = IA5String("test")
5453 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5455 class Seq(Sequence):
5457 ("erste", PrintableString()),
5460 seq["erste"] = PrintableString("test")
5461 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5462 seq["erste"] = PrintableString("test*")
5463 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5465 class Seq(Sequence):
5467 ("erste", Any(optional=True)),
5468 ("zweite", Integer()),
5471 seq["zweite"] = Integer(64)
5472 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5477 seq.append(Integer(10))
5478 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5480 class _SeqOf(SequenceOf):
5481 schema = PrintableString()
5483 class SeqOf(SequenceOf):
5486 _seqof.append(PrintableString("1"))
5488 seqof.append(_seqof)
5489 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5491 class Seq(Sequence):
5493 ("erste", Integer(default=1)),
5496 seq["erste"] = Integer(0)
5497 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5498 seq["erste"] = Integer(1)
5499 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5500 seq["erste"] = Integer(2)
5501 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5504 class TestPP(TestCase):
5505 @given(data_strategy())
5506 def test_oid_printing(self, d):
5508 str(ObjectIdentifier(k)): v * 2
5509 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5511 chosen = d.draw(sampled_from(sorted(oids)))
5512 chosen_id = oids[chosen]
5513 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5514 self.assertNotIn(chosen_id, pp_console_row(pp))
5515 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5518 class TestAutoAddSlots(TestCase):
5520 class Inher(Integer):
5523 with self.assertRaises(AttributeError):
5525 inher.unexistent = "whatever"
5528 class TestOIDDefines(TestCase):
5529 @given(data_strategy())
5530 def runTest(self, d):
5531 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5532 value_name_chosen = d.draw(sampled_from(value_names))
5534 ObjectIdentifier(oid)
5535 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5537 oid_chosen = d.draw(sampled_from(oids))
5538 values = d.draw(lists(
5540 min_size=len(value_names),
5541 max_size=len(value_names),
5544 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5545 oid: Integer() for oid in oids[:-1]
5548 for i, value_name in enumerate(value_names):
5549 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5551 class Seq(Sequence):
5554 for value_name, value in zip(value_names, values):
5555 seq[value_name] = Any(Integer(value).encode())
5556 seq["type"] = oid_chosen
5557 seq, _ = Seq().decode(seq.encode())
5558 for value_name in value_names:
5559 if value_name == value_name_chosen:
5561 self.assertIsNone(seq[value_name].defined)
5562 if value_name_chosen in oids[:-1]:
5563 self.assertIsNotNone(seq[value_name_chosen].defined)
5564 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5565 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5568 class TestDefinesByPath(TestCase):
5569 def test_generated(self):
5570 class Seq(Sequence):
5572 ("type", ObjectIdentifier()),
5573 ("value", OctetString(expl=tag_ctxc(123))),
5576 class SeqInner(Sequence):
5578 ("typeInner", ObjectIdentifier()),
5579 ("valueInner", Any()),
5582 class PairValue(SetOf):
5585 class Pair(Sequence):
5587 ("type", ObjectIdentifier()),
5588 ("value", PairValue()),
5591 class Pairs(SequenceOf):
5598 type_octet_stringed,
5600 ObjectIdentifier(oid)
5601 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5603 seq_integered = Seq()
5604 seq_integered["type"] = type_integered
5605 seq_integered["value"] = OctetString(Integer(123).encode())
5606 seq_integered_raw = seq_integered.encode()
5610 (type_octet_stringed, OctetString(b"whatever")),
5611 (type_integered, Integer(123)),
5612 (type_octet_stringed, OctetString(b"whenever")),
5613 (type_integered, Integer(234)),
5615 for t, v in pairs_input:
5618 pair["value"] = PairValue((Any(v),))
5620 seq_inner = SeqInner()
5621 seq_inner["typeInner"] = type_innered
5622 seq_inner["valueInner"] = Any(pairs)
5623 seq_sequenced = Seq()
5624 seq_sequenced["type"] = type_sequenced
5625 seq_sequenced["value"] = OctetString(seq_inner.encode())
5626 seq_sequenced_raw = seq_sequenced.encode()
5628 defines_by_path = []
5629 seq_integered, _ = Seq().decode(seq_integered_raw)
5630 self.assertIsNone(seq_integered["value"].defined)
5631 defines_by_path.append(
5632 (("type",), ((("value",), {
5633 type_integered: Integer(),
5634 type_sequenced: SeqInner(),
5637 seq_integered, _ = Seq().decode(
5639 ctx={"defines_by_path": defines_by_path},
5641 self.assertIsNotNone(seq_integered["value"].defined)
5642 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5643 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5644 self.assertTrue(seq_integered_raw[
5645 seq_integered["value"].defined[1].offset:
5646 ].startswith(Integer(123).encode()))
5648 seq_sequenced, _ = Seq().decode(
5650 ctx={"defines_by_path": defines_by_path},
5652 self.assertIsNotNone(seq_sequenced["value"].defined)
5653 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5654 seq_inner = seq_sequenced["value"].defined[1]
5655 self.assertIsNone(seq_inner["valueInner"].defined)
5657 defines_by_path.append((
5658 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5659 ((("valueInner",), {type_innered: Pairs()}),),
5661 seq_sequenced, _ = Seq().decode(
5663 ctx={"defines_by_path": defines_by_path},
5665 self.assertIsNotNone(seq_sequenced["value"].defined)
5666 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5667 seq_inner = seq_sequenced["value"].defined[1]
5668 self.assertIsNotNone(seq_inner["valueInner"].defined)
5669 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5670 pairs = seq_inner["valueInner"].defined[1]
5672 self.assertIsNone(pair["value"][0].defined)
5674 defines_by_path.append((
5677 DecodePathDefBy(type_sequenced),
5679 DecodePathDefBy(type_innered),
5684 type_integered: Integer(),
5685 type_octet_stringed: OctetString(),
5688 seq_sequenced, _ = Seq().decode(
5690 ctx={"defines_by_path": defines_by_path},
5692 self.assertIsNotNone(seq_sequenced["value"].defined)
5693 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5694 seq_inner = seq_sequenced["value"].defined[1]
5695 self.assertIsNotNone(seq_inner["valueInner"].defined)
5696 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5697 pairs_got = seq_inner["valueInner"].defined[1]
5698 for pair_input, pair_got in zip(pairs_input, pairs_got):
5699 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5700 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5702 @given(oid_strategy(), integers())
5703 def test_simple(self, oid, tgt):
5704 class Inner(Sequence):
5706 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5707 ObjectIdentifier(oid): Integer(),
5711 class Outer(Sequence):
5714 ("tgt", OctetString()),
5718 inner["oid"] = ObjectIdentifier(oid)
5720 outer["inner"] = inner
5721 outer["tgt"] = OctetString(Integer(tgt).encode())
5722 decoded, _ = Outer().decode(outer.encode())
5723 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5726 class TestAbsDecodePath(TestCase):
5728 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5729 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5731 def test_concat(self, decode_path, rel_path):
5732 self.assertSequenceEqual(
5733 abs_decode_path(decode_path, rel_path),
5734 decode_path + rel_path,
5738 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5739 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5741 def test_abs(self, decode_path, rel_path):
5742 self.assertSequenceEqual(
5743 abs_decode_path(decode_path, ("/",) + rel_path),
5748 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5749 integers(min_value=1, max_value=3),
5750 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5752 def test_dots(self, decode_path, number_of_dots, rel_path):
5753 self.assertSequenceEqual(
5754 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5755 decode_path[:-number_of_dots] + rel_path,
5759 class TestStrictDefaultExistence(TestCase):
5760 @given(data_strategy())
5761 def runTest(self, d):
5762 count = d.draw(integers(min_value=1, max_value=10))
5763 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5765 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5766 for i in range(count)
5769 class Seq(Sequence):
5772 for i in range(count):
5773 seq["int%d" % i] = Integer(123)
5775 chosen = "int%d" % chosen
5776 seq.specs[chosen] = seq.specs[chosen](default=123)
5778 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5779 seq.decode(raw, ctx={"strict_default_existence": True})
5782 class TestX690PrefixedType(TestCase):
5784 self.assertSequenceEqual(
5785 VisibleString("Jones").encode(),
5786 hexdec("1A054A6F6E6573"),
5788 self.assertSequenceEqual(
5791 impl=tag_encode(3, klass=TagClassApplication),
5793 hexdec("43054A6F6E6573"),
5795 self.assertSequenceEqual(
5799 impl=tag_encode(3, klass=TagClassApplication),
5803 hexdec("A20743054A6F6E6573"),
5805 self.assertSequenceEqual(
5809 impl=tag_encode(3, klass=TagClassApplication),
5811 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5813 hexdec("670743054A6F6E6573"),
5815 self.assertSequenceEqual(
5816 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5817 hexdec("82054A6F6E6573"),