# coding: utf-8
# PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures
-# Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
+# Copyright (C) 2017-2021 Sergey Matveev <stargrave@stargrave.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
from datetime import datetime
from datetime import timedelta
from importlib import import_module
+from io import BytesIO
from operator import attrgetter
from os import environ
from os import urandom
from time import mktime
from time import time
from unittest import TestCase
+from unittest.mock import patch
+from dateutil.tz import UTC
from hypothesis import assume
from hypothesis import given
from hypothesis import settings
from hypothesis.strategies import sets
from hypothesis.strategies import text
from hypothesis.strategies import tuples
-from six import assertRaisesRegex
-from six import binary_type
-from six import byte2int
-from six import indexbytes
-from six import int2byte
-from six import iterbytes
-from six import PY2
-from six import text_type
-from six import unichr as six_unichr
-from six.moves import xrange as six_xrange
-from six.moves.cPickle import dumps as pickle_dumps
-from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto
-from six.moves.cPickle import loads as pickle_loads
+from pickle import dumps as pickle_dumps
+from pickle import HIGHEST_PROTOCOL as pickle_proto
+from pickle import loads as pickle_loads
from pyderasn import _pp
from pyderasn import abs_decode_path
from pyderasn import Choice
from pyderasn import DecodeError
from pyderasn import DecodePathDefBy
+from pyderasn import encode2pass
from pyderasn import encode_cer
from pyderasn import Enumerated
from pyderasn import EOC
from pyderasn import UTF8String
from pyderasn import VideotexString
from pyderasn import VisibleString
+import pyderasn
max_examples = environ.get("MAX_EXAMPLES")
def assert_exceeding_data(self, call, junk):
if len(junk) <= 0:
return
- with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)) as err:
+ with self.assertRaisesRegex(ExceedingData, "%d trailing bytes" % len(junk)) as err:
call()
repr(err)
self.assertEqual(tag_decode(raw), (klass, form, num))
self.assertEqual(len(raw), 1)
self.assertEqual(
- byte2int(tag_encode(klass=klass, form=form, num=0)),
- byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
+ tag_encode(klass=klass, form=form, num=0)[0],
+ raw[0] & (1 << 7 | 1 << 6 | 1 << 5),
)
stripped, tlen, tail = tag_strip(memoryview(raw + junk))
self.assertSequenceEqual(stripped.tobytes(), raw)
self.assertEqual(tag_decode(raw), (klass, form, num))
self.assertGreater(len(raw), 1)
self.assertEqual(
- byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
- byte2int(raw[:1]),
+ tag_encode(klass=klass, form=form, num=0)[0] | 31,
+ raw[0],
)
- self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
- self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
+ self.assertEqual(raw[-1] & 0x80, 0)
+ self.assertTrue(all(b & 0x80 > 0 for b in raw[1:-1]))
stripped, tlen, tail = tag_strip(memoryview(raw + junk))
self.assertSequenceEqual(stripped.tobytes(), raw)
self.assertEqual(tlen, len(raw))
raw = bytearray(tag_encode(num=num))
for i in range(1, len(raw)):
raw[i] |= 0x80
- with assertRaisesRegex(self, DecodeError, "unfinished tag"):
+ with self.assertRaisesRegex(DecodeError, "unfinished tag"):
tag_strip(bytes(raw))
def test_go_vectors_valid(self):
integers(min_value=0, max_value=2),
)
def test_long_instead_of_short(self, l, dummy_num):
- octets = (b"\x00" * dummy_num) + int2byte(l)
- octets = int2byte((dummy_num + 1) | 0x80) + octets
+ octets = (b"\x00" * dummy_num) + bytes([l])
+ octets = bytes([(dummy_num + 1) | 0x80]) + octets
with self.assertRaises(DecodeError):
len_decode(octets)
+ @given(tag_classes, tag_forms, integers(min_value=31))
+ def test_leading_zero_byte(self, klass, form, num):
+ raw = tag_encode(klass=klass, form=form, num=num)
+ raw = b"".join((raw[:1], b"\x80", raw[1:]))
+ with self.assertRaisesRegex(DecodeError, "leading zero byte"):
+ tag_strip(raw)
+
+ @given(tag_classes, tag_forms, integers(max_value=30, min_value=0))
+ def test_unexpected_long_form(self, klass, form, num):
+ raw = bytes([klass | form | 31, num])
+ with self.assertRaisesRegex(DecodeError, "unexpected long form"):
+ tag_strip(raw)
+
class TestLenCoder(TestCase):
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
raw = len_encode(l) + junk
decoded, llen, tail = len_decode(memoryview(raw))
self.assertEqual(decoded, l)
- self.assertEqual((llen - 1) | 0x80, byte2int(raw))
+ self.assertEqual((llen - 1) | 0x80, raw[0])
self.assertEqual(llen, len(raw) - len(junk))
- self.assertNotEqual(indexbytes(raw, 1), 0)
+ self.assertNotEqual(raw[1], 0)
self.assertSequenceEqual(tail.tobytes(), junk)
def test_empty(self):
@composite
def text_letters(draw):
result = draw(text(alphabet=ascii_letters, min_size=1))
- if PY2:
- result = result.encode("ascii")
return result
pprint(obj, big_blobs=True, with_decode_path=True)
with self.assertRaises(ObjNotReady) as err:
obj.encode()
+ with self.assertRaises(ObjNotReady) as err:
+ encode2pass(obj)
repr(err.exception)
obj = Boolean(value)
self.assertTrue(obj.ready)
obj = Boolean(value, impl=tag_impl)
with self.assertRaises(NotEnoughData):
obj.decode(obj.encode()[:-1])
+ with self.assertRaises(NotEnoughData):
+ obj.decode(encode2pass(obj)[:-1])
@given(
booleans(),
obj = Boolean(value, expl=tag_expl)
with self.assertRaises(NotEnoughData):
obj.decode(obj.encode()[:-1])
+ with self.assertRaises(NotEnoughData):
+ obj.decode(encode2pass(obj)[:-1])
@given(
integers(min_value=31),
pprint(obj, big_blobs=True, with_decode_path=True)
self.assertFalse(obj.expled)
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
self.assertSequenceEqual(encode_cer(obj), obj_encoded)
obj_expled = obj(value, expl=tag_expl)
self.assertTrue(obj_expled.expled)
@given(integers(min_value=0 + 1, max_value=255 - 1))
def test_ber_value(self, value):
- with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
+ with self.assertRaisesRegex(DecodeError, "unacceptable Boolean value"):
Boolean().decode(b"".join((
Boolean.tag_default,
len_encode(1),
- int2byte(value),
+ bytes([value]),
)))
- encoded = b"".join((
- Boolean.tag_default,
- len_encode(1),
- int2byte(value),
- ))
+ encoded = b"".join((Boolean.tag_default, len_encode(1), bytes([value])))
obj, _ = Boolean().decode(encoded, ctx={"bered": True})
list(Boolean().decode_evgen(encoded, ctx={"bered": True}))
self.assertTrue(bool(obj))
encoded = expl + LENINDEF + Boolean(False).encode()
with self.assertRaises(LenIndefForm):
Boolean(expl=expl).decode(encoded + junk)
- with assertRaisesRegex(self, DecodeError, "no EOC"):
+ with self.assertRaisesRegex(DecodeError, "no EOC"):
Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
obj, tail = Boolean(expl=expl).decode(
encoded + EOC + junk,
pprint(obj, big_blobs=True, with_decode_path=True)
with self.assertRaises(ObjNotReady) as err:
obj.encode()
+ with self.assertRaises(ObjNotReady) as err:
+ encode2pass(obj)
repr(err.exception)
obj = Integer(value)
self.assertTrue(obj.ready)
with self.assertRaises(BoundsError) as err:
Integer(value=values[0], bounds=(values[1], values[2]))
repr(err.exception)
- with assertRaisesRegex(self, DecodeError, "bounds") as err:
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
Integer(bounds=(values[1], values[2])).decode(
Integer(values[0]).encode()
)
repr(err.exception)
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
+ Integer(bounds=(values[1], values[2])).decode(
+ encode2pass(Integer(values[0]))
+ )
with self.assertRaises(BoundsError) as err:
Integer(value=values[2], bounds=(values[0], values[1]))
repr(err.exception)
- with assertRaisesRegex(self, DecodeError, "bounds") as err:
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
Integer(bounds=(values[0], values[1])).decode(
Integer(values[2]).encode()
)
repr(err.exception)
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
+ Integer(bounds=(values[0], values[1])).decode(
+ encode2pass(Integer(values[2]))
+ )
@given(data_strategy())
def test_call(self, d):
pprint(obj, big_blobs=True, with_decode_path=True)
self.assertFalse(obj.expled)
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
self.assertSequenceEqual(encode_cer(obj), obj_encoded)
obj_expled = obj(value, expl=tag_expl)
self.assertTrue(obj_expled.expled)
with self.assertRaises(ObjNotReady) as err:
obj.encode()
repr(err.exception)
+ with self.assertRaises(ObjNotReady) as err:
+ encode2pass(obj)
obj = BitString(value)
self.assertTrue(obj.ready)
repr(obj)
pprint(obj, big_blobs=True, with_decode_path=True)
self.assertFalse(obj.expled)
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
self.assertSequenceEqual(encode_cer(obj), obj_encoded)
obj_expled = obj(value, expl=tag_expl)
self.assertTrue(obj_expled.expled)
BitString().decode(b"".join((
BitString.tag_default,
len_encode(1),
- int2byte(pad_size),
+ bytes([pad_size]),
)))
def test_go_vectors_invalid(self):
payload_expected = b""
bit_len_expected = 0
for chunk_input in chunk_inputs:
- if isinstance(chunk_input, binary_type):
+ if isinstance(chunk_input, bytes):
chunks.append(BitString(chunk_input).encode())
payload_expected += chunk_input
bit_len_expected += len(chunk_input) * 8
b"".join(chunks) +
chunk_last.encode()
)
- with assertRaisesRegex(self, DecodeError, "unallowed BER"):
+ with self.assertRaisesRegex(DecodeError, "unallowed BER"):
BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
for lenindef_expected, encoded in (
(True, encoded_indefinite),
decode_path_strat,
)
def test_ber_definite_too_short(self, offset, decode_path):
- with assertRaisesRegex(self, DecodeError, "longer than data") as err:
+ with self.assertRaisesRegex(DecodeError, "longer than data") as err:
BitString().decode(
tag_encode(3, form=TagFormConstructed) + len_encode(1),
offset=offset,
decode_path_strat,
)
def test_ber_definite_no_data(self, offset, decode_path):
- with assertRaisesRegex(self, DecodeError, "zero length") as err:
+ with self.assertRaisesRegex(DecodeError, "zero length") as err:
BitString().decode(
tag_encode(3, form=TagFormConstructed) + len_encode(0),
offset=offset,
def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
bs = BitString(b"data").encode()
bs_longer = BitString(b"data-longer").encode()
- with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
+ with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
BitString().decode(
(
tag_encode(3, form=TagFormConstructed) +
decode_path_strat,
)
def test_ber_indefinite_no_chunks(self, offset, decode_path):
- with assertRaisesRegex(self, DecodeError, "no chunks") as err:
+ with self.assertRaisesRegex(DecodeError, "no chunks") as err:
BitString().decode(
tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
offset=offset,
chunks.append(bs_short)
offset = d.draw(integers(min_value=0))
decode_path = d.draw(decode_path_strat)
- with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
+ with self.assertRaisesRegex(DecodeError, "multiple of 8 bits") as err:
BitString().decode(
(
tag_encode(3, form=TagFormConstructed) +
def test_invalid_value_type(self):
with self.assertRaises(InvalidValueType) as err:
- OctetString(text_type(123))
+ OctetString(str(123))
repr(err.exception)
@given(booleans())
with self.assertRaises(ObjNotReady) as err:
obj.encode()
repr(err.exception)
+ with self.assertRaises(ObjNotReady) as err:
+ encode2pass(obj)
obj = OctetString(value)
self.assertTrue(obj.ready)
repr(obj)
with self.assertRaises(BoundsError) as err:
OctetString(value=value, bounds=(bound_min, bound_max))
repr(err.exception)
- with assertRaisesRegex(self, DecodeError, "bounds") as err:
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
OctetString(bounds=(bound_min, bound_max)).decode(
OctetString(value).encode()
)
repr(err.exception)
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
+ OctetString(bounds=(bound_min, bound_max)).decode(
+ encode2pass(OctetString(value))
+ )
value = d.draw(binary(min_size=bound_max + 1))
with self.assertRaises(BoundsError) as err:
OctetString(value=value, bounds=(bound_min, bound_max))
repr(err.exception)
- with assertRaisesRegex(self, DecodeError, "bounds") as err:
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
OctetString(bounds=(bound_min, bound_max)).decode(
OctetString(value).encode()
)
repr(err.exception)
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
+ OctetString(bounds=(bound_min, bound_max)).decode(
+ encode2pass(OctetString(value))
+ )
@given(data_strategy())
def test_call(self, d):
pprint(obj, big_blobs=True, with_decode_path=True)
self.assertFalse(obj.expled)
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
self.assertSequenceEqual(encode_cer(obj), obj_encoded)
obj_expled = obj(value, expl=tag_expl)
self.assertTrue(obj_expled.expled)
chunks_len_expected = []
payload_expected = b""
for chunk_input in chunk_inputs:
- if isinstance(chunk_input, binary_type):
+ if isinstance(chunk_input, bytes):
chunks.append(OctetString(chunk_input).encode())
payload_expected += chunk_input
chunks_len_expected.append(len(chunk_input))
len_encode(len(b"".join(chunks))) +
b"".join(chunks)
)
- with assertRaisesRegex(self, DecodeError, "unallowed BER"):
+ with self.assertRaisesRegex(DecodeError, "unallowed BER"):
OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
for lenindef_expected, encoded in (
(True, encoded_indefinite),
decode_path_strat,
)
def test_ber_definite_too_short(self, offset, decode_path):
- with assertRaisesRegex(self, DecodeError, "longer than data") as err:
+ with self.assertRaisesRegex(DecodeError, "longer than data") as err:
OctetString().decode(
tag_encode(4, form=TagFormConstructed) + len_encode(1),
offset=offset,
def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
bs = OctetString(b"data").encode()
bs_longer = OctetString(b"data-longer").encode()
- with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
+ with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
OctetString().decode(
(
tag_encode(4, form=TagFormConstructed) +
pprint(obj, big_blobs=True, with_decode_path=True)
self.assertFalse(obj.expled)
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
self.assertSequenceEqual(encode_cer(obj), obj_encoded)
obj_expled = obj(expl=tag_expl)
self.assertTrue(obj_expled.expled)
repr(obj)
list(obj.pps())
-
@given(integers(min_value=1))
def test_invalid_len(self, l):
with self.assertRaises(InvalidLength):
with self.assertRaises(ObjNotReady) as err:
obj.encode()
repr(err.exception)
+ with self.assertRaises(ObjNotReady) as err:
+ encode2pass(obj)
obj = ObjectIdentifier(value)
self.assertTrue(obj.ready)
self.assertFalse(obj.ber_encoded)
len_encode(len(data)),
data,
))
- with assertRaisesRegex(self, DecodeError, "unfinished OID"):
+ with self.assertRaisesRegex(DecodeError, "unfinished OID"):
obj.decode(data)
@given(integers(min_value=0))
pprint(obj, big_blobs=True, with_decode_path=True)
self.assertFalse(obj.expled)
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
self.assertSequenceEqual(encode_cer(obj), obj_encoded)
obj_expled = obj(value, expl=tag_expl)
self.assertTrue(obj_expled.expled)
data,
)))
+ def test_go_non_minimal_encoding(self):
+ with self.assertRaises(DecodeError):
+ ObjectIdentifier().decode(hexdec("060a2a80864886f70d01010b"))
+
def test_x690_vector(self):
self.assertEqual(
ObjectIdentifier().decode(hexdec("0603883703"))[0],
obj = copy(obj)
self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.bered)
- with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
+ with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
ObjectIdentifier().decode(tampered)
@given(data_strategy())
obj = copy(obj)
self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.bered)
- with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
+ with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
ObjectIdentifier().decode(tampered)
base_klass = EWhatever
def test_schema_required(self):
- with assertRaisesRegex(self, ValueError, "schema must be specified"):
+ with self.assertRaisesRegex(ValueError, "schema must be specified"):
Enumerated()
def test_invalid_value_type(self):
pprint(obj, big_blobs=True, with_decode_path=True)
self.assertFalse(obj.expled)
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
obj_expled = obj(value, expl=tag_expl)
self.assertTrue(obj_expled.expled)
repr(obj_expled)
repr(err.exception)
def text_alphabet(self):
- if self.base_klass.encoding in ("ascii", "iso-8859-1"):
- return printable + whitespace
- return None
+ return "".join(chr(c) for c in range(256))
@given(booleans())
def test_optional(self, optional):
repr(obj)
list(obj.pps())
pprint(obj, big_blobs=True, with_decode_path=True)
- text_type(obj)
+ str(obj)
with self.assertRaises(ObjNotReady) as err:
obj.encode()
repr(err.exception)
+ with self.assertRaises(ObjNotReady) as err:
+ encode2pass(obj)
value = d.draw(text(alphabet=self.text_alphabet()))
obj = self.base_klass(value)
self.assertTrue(obj.ready)
repr(obj)
list(obj.pps())
pprint(obj, big_blobs=True, with_decode_path=True)
- text_type(obj)
+ str(obj)
@given(data_strategy())
def test_comparison(self, d):
self.assertEqual(obj1 == obj2, value1 == value2)
self.assertEqual(obj1 != obj2, value1 != value2)
self.assertEqual(obj1 == bytes(obj2), value1 == value2)
- self.assertEqual(obj1 == text_type(obj2), value1 == value2)
+ self.assertEqual(obj1 == str(obj2), value1 == value2)
obj1 = self.base_klass(value1, impl=tag1)
obj2 = self.base_klass(value1, impl=tag2)
self.assertEqual(obj1 == obj2, tag1 == tag2)
with self.assertRaises(BoundsError) as err:
self.base_klass(value=value, bounds=(bound_min, bound_max))
repr(err.exception)
- with assertRaisesRegex(self, DecodeError, "bounds") as err:
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
self.base_klass(bounds=(bound_min, bound_max)).decode(
self.base_klass(value).encode()
)
repr(err.exception)
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
+ self.base_klass(bounds=(bound_min, bound_max)).decode(
+ encode2pass(self.base_klass(value))
+ )
value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
with self.assertRaises(BoundsError) as err:
self.base_klass(value=value, bounds=(bound_min, bound_max))
repr(err.exception)
- with assertRaisesRegex(self, DecodeError, "bounds") as err:
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
self.base_klass(bounds=(bound_min, bound_max)).decode(
self.base_klass(value).encode()
)
repr(err.exception)
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
+ self.base_klass(bounds=(bound_min, bound_max)).decode(
+ encode2pass(self.base_klass(value))
+ )
@given(data_strategy())
def test_call(self, d):
pprint(obj, big_blobs=True, with_decode_path=True)
self.assertFalse(obj.expled)
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
obj_expled = obj(value, expl=tag_expl)
self.assertTrue(obj_expled.expled)
repr(obj_expled)
self.assertNotEqual(obj_decoded, obj)
self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
self.assertEqual(bytes(obj_decoded), bytes(obj))
- self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
- self.assertEqual(text_type(obj_decoded), text_type(obj))
+ self.assertEqual(str(obj_decoded), str(obj_expled))
+ self.assertEqual(str(obj_decoded), str(obj))
self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
cyrillic_letters = text(
- alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
+ alphabet="".join(chr(i) for i in list(range(0x0410, 0x044f + 1))),
min_size=1,
max_size=5,
)
@given(text(alphabet=ascii_letters, min_size=1, max_size=5))
def test_non_numeric(self, non_numeric_text):
- with assertRaisesRegex(self, DecodeError, "non-numeric"):
+ with self.assertRaisesRegex(DecodeError, "alphabet value"):
self.base_klass(non_numeric_text)
@given(
@given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
def test_non_printable(self, non_printable_text):
- with assertRaisesRegex(self, DecodeError, "non-printable"):
+ with self.assertRaisesRegex(DecodeError, "alphabet value"):
self.base_klass(non_printable_text)
@given(
for prop in kwargs.keys():
self.assertFalse(getattr(obj, prop))
s += c
- with assertRaisesRegex(self, DecodeError, "non-printable"):
+ with self.assertRaisesRegex(DecodeError, "alphabet value"):
self.base_klass(s)
self.base_klass(s, **kwargs)
klass = self.base_klass(**kwargs)
):
base_klass = IA5String
+ def text_alphabet(self):
+ return "".join(chr(c) for c in range(128))
+
+ @given(integers(min_value=128, max_value=255))
+ def test_alphabet_bad(self, code):
+ with self.assertRaises(DecodeError):
+ self.base_klass().decod(
+ self.base_klass.tag_default +
+ len_encode(1) +
+ bytes(bytearray([code])),
+ )
+
class TestGraphicString(
UnicodeDecodeErrorMixin,
):
base_klass = VisibleString
+ def text_alphabet(self):
+ return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
+
def test_x690_vector(self):
obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
self.assertSequenceEqual(tail, b"")
self.assertTrue(obj.lenindef)
self.assertTrue(obj.bered)
+ @given(one_of((
+ integers(min_value=0, max_value=ord(" ") - 1),
+ integers(min_value=ord("~") + 1, max_value=255),
+ )))
+ def test_alphabet_bad(self, code):
+ with self.assertRaises(DecodeError):
+ self.base_klass().decod(
+ self.base_klass.tag_default +
+ len_encode(1) +
+ bytes(bytearray([code])),
+ )
+
+ @given(
+ sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
+ integers(min_value=0),
+ decode_path_strat,
+ )
+ def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
+ value, bound_min = list(sorted(ints))
+
+ class String(self.base_klass):
+ bounds = (bound_min, bound_min)
+ with self.assertRaises(DecodeError) as err:
+ String().decode(
+ self.base_klass(b"1" * value).encode(),
+ offset=offset,
+ decode_path=decode_path,
+ )
+ repr(err.exception)
+ self.assertEqual(err.exception.offset, offset)
+ self.assertEqual(err.exception.decode_path, decode_path)
+
class TestGeneralString(
UnicodeDecodeErrorMixin,
with self.assertRaises(ObjNotReady) as err:
obj.encode()
repr(err.exception)
+ with self.assertRaises(ObjNotReady) as err:
+ encode2pass(obj)
value = d.draw(datetimes(
min_value=self.min_datetime,
max_value=self.max_datetime,
pprint(obj, big_blobs=True, with_decode_path=True)
self.assertFalse(obj.expled)
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
self.additional_symmetric_check(value, obj_encoded)
obj_expled = obj(value, expl=tag_expl)
self.assertTrue(obj_expled.expled)
self.assertFalse(obj_encoded.endswith(b"0Z"))
def test_repr_not_ready(self):
- unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
+ str(GeneralizedTime())
repr(GeneralizedTime())
def test_x690_vector_valid(self):
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(data_strategy())
def test_valid_ber(self, d):
- min_year = 1901 if PY2 else 2
- year = d.draw(integers(min_value=min_year, max_value=9999))
+ year = d.draw(integers(min_value=2, max_value=9999))
month = d.draw(integers(min_value=1, max_value=12))
day = d.draw(integers(min_value=1, max_value=28))
hours = d.draw(integers(min_value=0, max_value=23))
mktime(obj.todatetime().timetuple()),
mktime(dt.timetuple()),
)
- elif not PY2:
- self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
+ else:
+ try:
+ obj.todatetime().timestamp()
+ except:
+ pass
+ else:
+ self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
self.assertEqual(obj.ber_encoded, not dered)
self.assertEqual(obj.bered, not dered)
self.assertEqual(obj.ber_raw, None if dered else data)
def test_ns_fractions(self):
GeneralizedTime(b"20010101000000.000001Z")
- with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
+ with self.assertRaisesRegex(DecodeError, "only microsecond fractions"):
GeneralizedTime(b"20010101000000.0000001Z")
def test_non_pure_integers(self):
with self.assertRaises(DecodeError):
GeneralizedTime(data)
+ def test_aware(self):
+ with self.assertRaisesRegex(ValueError, "only naive"):
+ GeneralizedTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
+
class TestUTCTime(TimeMixin, CommonMixin, TestCase):
base_klass = UTCTime
pass
def test_repr_not_ready(self):
- unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
+ str(GeneralizedTime())
repr(UTCTime())
def test_x690_vector_valid(self):
junk
)
+ def test_aware(self):
+ with self.assertRaisesRegex(ValueError, "only naive"):
+ UTCTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
+
+ def test_raises_if_no_dateutil(self):
+ with patch("pyderasn.tzUTC", new="missing"):
+ with self.assertRaisesRegex(NotImplementedError, "dateutil"):
+ UTCTime(datetime.now()).totzdatetime()
+
+ def test_tzinfo_gives_datetime_with_tzutc_tzinfo(self):
+ self.assertEqual(UTCTime(datetime.now()).totzdatetime().tzinfo, UTC)
+
@composite
def tlv_value_strategy(draw):
with self.assertRaises(ObjNotReady) as err:
obj.encode()
repr(err.exception)
+ with self.assertRaises(ObjNotReady) as err:
+ encode2pass(obj)
obj = Any(value)
self.assertTrue(obj.ready)
repr(obj)
tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
self.assertEqual(obj.tag_order, (tag_class, tag_num))
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
obj_expled = obj(value, expl=tag_expl)
self.assertTrue(obj_expled.expled)
tag_class, _, tag_num = tag_decode(tag_expl)
base_klass = Wahl
def test_schema_required(self):
- with assertRaisesRegex(self, ValueError, "schema must be specified"):
+ with self.assertRaisesRegex(ValueError, "schema must be specified"):
Choice()
def test_impl_forbidden(self):
- with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
+ with self.assertRaisesRegex(ValueError, "no implicit tag allowed"):
Choice(impl=b"whatever")
def test_invalid_value_type(self):
with self.assertRaises(ObjNotReady) as err:
obj.encode()
repr(err.exception)
+ with self.assertRaises(ObjNotReady) as err:
+ encode2pass(obj)
obj["whatever"] = Boolean()
self.assertFalse(obj.ready)
repr(obj)
self.assertFalse(obj.expled)
self.assertEqual(obj.tag_order, obj.value.tag_order)
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
obj_expled = obj(value, expl=tag_expl)
self.assertTrue(obj_expled.expled)
tag_class, _, tag_num = tag_decode(tag_expl)
return seq_outer, expect_outers
-class SeqMixing(object):
+class SeqMixin(object):
def test_invalid_value_type(self):
with self.assertRaises(InvalidValueType) as err:
self.base_klass(123)
with self.assertRaises(ObjNotReady) as err:
seq.encode()
repr(err.exception)
+ with self.assertRaises(ObjNotReady) as err:
+ encode2pass(seq)
for name, value in non_ready.items():
seq[name] = Boolean(value)
self.assertTrue(seq.ready)
pprint(seq, big_blobs=True, with_decode_path=True)
self.assertTrue(seq.ready)
seq_encoded = seq.encode()
+ self.assertEqual(encode2pass(seq), seq_encoded)
seq_encoded_cer = encode_cer(seq)
self.assertNotEqual(seq_encoded_cer, seq_encoded)
self.assertSequenceEqual(
seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
self.assertTrue(seq.ready)
seq_encoded = seq.encode()
+ self.assertEqual(encode2pass(seq), seq_encoded)
seq_decoded, tail = seq.decode(seq_encoded)
self.assertEqual(tail, b"")
self.assertTrue(seq.ready)
max_size=len(_schema),
))]
+ class Wahl(Choice):
+ schema = (("int", Integer()),)
+
class SeqWithoutDefault(self.base_klass):
schema = [
- (n, Integer(impl=t))
+ (n, Wahl(expl=t))
for (n, _), t in zip(_schema, tags)
]
seq_without_default = SeqWithoutDefault()
for name, value in _schema:
- seq_without_default[name] = Integer(value)
+ seq_without_default[name] = Wahl(("int", Integer(value)))
seq_encoded = seq_without_default.encode()
+ seq_without_default.decode(seq_encoded)
+ self.assertEqual(
+ len(list(seq_without_default.decode_evgen(seq_encoded))),
+ len(_schema) * 2 + 1,
+ )
class SeqWithDefault(self.base_klass):
schema = [
- (n, Integer(default=v, impl=t))
+ (n, Wahl(default=Wahl(("int", Integer(v))), expl=t))
for (n, v), t in zip(_schema, tags)
]
seq_with_default = SeqWithDefault()
- with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
+ with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
seq_with_default.decode(seq_encoded)
+ with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
+ list(seq_with_default.decode_evgen(seq_encoded))
for ctx in ({"bered": True}, {"allow_default_values": True}):
seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
self.assertTrue(seq_decoded.ber_encoded)
self.assertTrue(seq_decoded.bered)
for name, value in _schema:
self.assertEqual(seq_decoded[name], seq_with_default[name])
- self.assertEqual(seq_decoded[name], value)
+ self.assertEqual(seq_decoded[name].value, value)
+ self.assertEqual(
+ len(list(seq_with_default.decode_evgen(seq_encoded, ctx=ctx))),
+ len(_schema) + 1,
+ )
+
+ seq_without_default = SeqWithoutDefault()
+ for name, value in _schema:
+ seq_without_default[name] = Wahl(("int", Integer(value + 1)))
+ seq_encoded = seq_without_default.encode()
+ seq_with_default.decode(seq_encoded)
+ self.assertEqual(
+ len(list(seq_with_default.decode_evgen(seq_encoded))),
+ len(_schema) + 1,
+ )
@given(data_strategy())
def test_missing_from_spec(self, d):
seq_missing = SeqMissing()
with self.assertRaises(TagMismatch):
seq_missing.decode(seq_encoded)
+ with self.assertRaises(TagMismatch):
+ list(seq_missing.decode_evgen(seq_encoded))
def test_bered(self):
class Seq(self.base_klass):
encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
with self.assertRaises(DecodeError):
Seq().decode(encoded)
+ with self.assertRaises(DecodeError):
+ list(Seq().decode_evgen(encoded))
+ list(Seq().decode_evgen(encoded, ctx={"bered": True}))
decoded, _ = Seq().decode(encoded, ctx={"bered": True})
self.assertFalse(decoded.ber_encoded)
self.assertFalse(decoded.lenindef)
self.assertTrue(decoded.bered)
-class TestSequence(SeqMixing, CommonMixin, TestCase):
+class TestSequence(SeqMixin, CommonMixin, TestCase):
base_klass = Sequence
@given(
len_encode(len(int_encoded + junk)),
int_encoded + junk,
))
- with assertRaisesRegex(self, DecodeError, "remaining"):
+ with self.assertRaisesRegex(DecodeError, "remaining"):
Seq().decode(junked)
@given(sets(text_letters(), min_size=2))
self.assertEqual(seq["ok"], True)
-class TestSet(SeqMixing, CommonMixin, TestCase):
+class TestSet(SeqMixin, CommonMixin, TestCase):
base_klass = Set
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
len_encode(len(encoded)),
encoded,
))
- with assertRaisesRegex(self, DecodeError, "unordered SET"):
+ with self.assertRaisesRegex(DecodeError, "unordered SET"):
seq.decode(seq_encoded)
for ctx in ({"bered": True}, {"allow_unordered_set": True}):
seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
)
-class SeqOfMixing(object):
+class SeqOfMixin(object):
def test_invalid_value_type(self):
with self.assertRaises(InvalidValueType) as err:
self.base_klass(123)
repr(err.exception)
def test_schema_required(self):
- with assertRaisesRegex(self, ValueError, "schema must be specified"):
+ with self.assertRaisesRegex(ValueError, "schema must be specified"):
self.base_klass.__mro__[1]()
@given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
with self.assertRaises(ObjNotReady) as err:
seqof.encode()
repr(err.exception)
+ with self.assertRaises(ObjNotReady) as err:
+ encode2pass(seqof)
for i, value in enumerate(values):
self.assertEqual(seqof[i], value)
if not seqof[i].ready:
with self.assertRaises(BoundsError) as err:
SeqOf(value=value, bounds=(bound_min, bound_max))
repr(err.exception)
- with assertRaisesRegex(self, DecodeError, "bounds") as err:
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
SeqOf(bounds=(bound_min, bound_max)).decode(
SeqOf(value).encode()
)
repr(err.exception)
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
+ SeqOf(bounds=(bound_min, bound_max)).decode(
+ encode2pass(SeqOf(value))
+ )
value = [Boolean(True)] * d.draw(integers(
min_value=bound_max + 1,
max_value=bound_max + 10,
with self.assertRaises(BoundsError) as err:
SeqOf(value=value, bounds=(bound_min, bound_max))
repr(err.exception)
- with assertRaisesRegex(self, DecodeError, "bounds") as err:
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
SeqOf(bounds=(bound_min, bound_max)).decode(
SeqOf(value).encode()
)
repr(err.exception)
+ with self.assertRaisesRegex(DecodeError, "bounds") as err:
+ SeqOf(bounds=(bound_min, bound_max)).decode(
+ encode2pass(SeqOf(value))
+ )
@given(integers(min_value=1, max_value=10))
def test_out_of_bounds(self, bound_max):
pprint(obj, big_blobs=True, with_decode_path=True)
self.assertFalse(obj.expled)
obj_encoded = obj.encode()
+ self.assertEqual(encode2pass(obj), obj_encoded)
obj_encoded_cer = encode_cer(obj)
self.assertNotEqual(obj_encoded_cer, obj_encoded)
self.assertSequenceEqual(
self.assertTrue(decoded.bered)
-class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
+class TestSequenceOf(SeqOfMixin, CommonMixin, TestCase):
class SeqOf(SequenceOf):
schema = "whatever"
base_klass = SeqOf
register_class(SeqOf)
seqof = SeqOf()
pickle_dumps(seqof)
- seqof = seqof(iter(six_xrange(10)))
- with assertRaisesRegex(self, ValueError, "iterator"):
+ seqof = seqof(iter(range(10)))
+ with self.assertRaisesRegex(ValueError, "iterator"):
pickle_dumps(seqof)
def test_iterator_bounds(self):
schema = Integer()
bounds = (10, 20)
seqof = None
+
def gen(n):
- for i in six_xrange(n):
+ for i in range(n):
yield Integer(i)
for n in (9, 21):
seqof = SeqOf(gen(n))
class SeqOf(SequenceOf):
schema = Integer()
bounds = (1, float("+inf"))
+
def gen():
- for i in six_xrange(10):
+ for i in range(10):
yield Integer(i)
seqof = SeqOf(gen())
self.assertTrue(seqof.ready)
register_class(SeqOf)
pickle_dumps(seqof)
+ def test_iterator_2pass(self):
+ class SeqOf(SequenceOf):
+ schema = Integer()
+ bounds = (1, float("+inf"))
+
+ def gen():
+ for i in range(10):
+ yield Integer(i)
+ seqof = SeqOf(gen())
+ self.assertTrue(seqof.ready)
+ _, state = seqof.encode1st()
+ self.assertFalse(seqof.ready)
+ seqof = seqof(gen())
+ self.assertTrue(seqof.ready)
+ buf = BytesIO()
+ seqof.encode2nd(buf.write, iter(state))
+ self.assertSequenceEqual(
+ [int(i) for i in seqof.decod(buf.getvalue())],
+ list(gen()),
+ )
+
def test_non_ready_bound_min(self):
class SeqOf(SequenceOf):
schema = Integer()
self.assertFalse(seqof.ready)
-class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
+class TestSetOf(SeqOfMixin, CommonMixin, TestCase):
class SeqOf(SetOf):
schema = "whatever"
base_klass = SeqOf
class Seq(SetOf):
schema = OctetString()
seq = Seq()
- with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
+ with self.assertRaisesRegex(DecodeError, "unordered SET OF"):
seq.decode(seq_encoded)
for ctx in ({"bered": True}, {"allow_unordered_set": True}):
seq["erste"] = PrintableString("test")
self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
# Asterisk is actually not allowable
- PrintableString._allowable_chars |= set(b"*")
+ pyderasn.PRINTABLE_ALLOWABLE_CHARS |= set(b"*")
seq["erste"] = PrintableString("test*")
self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
- PrintableString._allowable_chars -= set(b"*")
+ pyderasn.PRINTABLE_ALLOWABLE_CHARS -= set(b"*")
class Seq(Sequence):
schema = (
def test_remaining_data(self):
oid = ObjectIdentifier("1.2.3")
+
class Seq(Sequence):
schema = (
("oid", ObjectIdentifier(defines=((("tgt",), {
("oid", oid),
("tgt", OctetString(Integer(123).encode() + b"junk")),
))
- with assertRaisesRegex(self, DecodeError, "remaining data"):
+ with self.assertRaisesRegex(DecodeError, "remaining data"):
Seq().decode(seq.encode())
def test_remaining_data_seqof(self):
oid = ObjectIdentifier("1.2.3")
+
class SeqOf(SetOf):
schema = OctetString()
("oid", oid),
("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
))
- with assertRaisesRegex(self, DecodeError, "remaining data"):
+ with self.assertRaisesRegex(DecodeError, "remaining data"):
Seq().decode(seq.encode())
raw = seq.encode()
chosen_choice = "int%d" % chosen
seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
- with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
+ with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
seq.decode(raw)
decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
self.assertTrue(decoded.ber_encoded)
expl = tag_ctxc(123)
raw = Integer(123).encode() + Integer(234).encode()
raw = b"".join((expl, len_encode(len(raw)), raw))
- with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
+ with self.assertRaisesRegex(DecodeError, "explicit tag out-of-bound"):
Integer(expl=expl).decode(raw)
Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
import pyderasn
version_orig = pyderasn.__version__
pyderasn.__version__ += "different"
- with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
+ with self.assertRaisesRegex(ValueError, "different PyDERASN version"):
pickle_loads(pickled)
pyderasn.__version__ = version_orig
pickle_loads(pickled)