# License along with this program. If not, see
# <http://www.gnu.org/licenses/>.
+from copy import copy
from copy import deepcopy
from datetime import datetime
+from importlib import import_module
from string import ascii_letters
from string import digits
from string import printable
from string import whitespace
+from time import time
from unittest import TestCase
from hypothesis import assume
from six import PY2
from six import text_type
from six import unichr as six_unichr
+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 pyderasn import _pp
from pyderasn import abs_decode_path
from pyderasn import Enumerated
from pyderasn import EOC
from pyderasn import EOC_LEN
+from pyderasn import ExceedingData
from pyderasn import GeneralizedTime
from pyderasn import GeneralString
from pyderasn import GraphicString
lambda decode_path: tuple(str(dp) for dp in decode_path)
)
ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
+copy_funcs = (
+ copy,
+ lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
+)
+self_module = import_module(__name__)
+
+
+def register_class(klass):
+ klassname = klass.__name__ + str(time()).replace(".", "")
+ klass.__name__ = klassname
+ klass.__qualname__ = klassname
+ setattr(self_module, klassname, klass)
+
+
+def assert_exceeding_data(self, call, junk):
+ if len(junk) > 0:
+ with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)):
+ call()
class TestHex(TestCase):
def test_copy(self, values):
for klass in (Boolean, BooleanInherited):
obj = klass(*values)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
@given(
booleans(),
offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
)
self.assertEqual(obj_decoded.expl_offset, offset)
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
@given(integers(min_value=2))
def test_invalid_len(self, l):
self.assertTrue(obj.ber_encoded)
self.assertFalse(obj.lenindef)
self.assertTrue(obj.bered)
- obj = obj.copy()
+ obj = copy(obj)
self.assertTrue(obj.ber_encoded)
self.assertFalse(obj.lenindef)
self.assertTrue(obj.bered)
self.assertFalse(obj.lenindef)
self.assertFalse(obj.ber_encoded)
self.assertTrue(obj.bered)
- obj = obj.copy()
+ obj = copy(obj)
self.assertTrue(obj.expl_lenindef)
self.assertFalse(obj.lenindef)
self.assertFalse(obj.ber_encoded)
def test_copy(self, values):
for klass in (Integer, IntegerInherited):
obj = klass(*values)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
- self.assertEqual(obj.specs, obj_copied.specs)
- self.assertEqual(obj._bound_min, obj_copied._bound_min)
- self.assertEqual(obj._bound_max, obj_copied._bound_max)
- self.assertEqual(obj._value, obj_copied._value)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
+ self.assertEqual(obj.specs, obj_copied.specs)
+ self.assertEqual(obj._bound_min, obj_copied._bound_min)
+ self.assertEqual(obj._bound_max, obj_copied._bound_max)
+ self.assertEqual(obj._value, obj_copied._value)
@given(
integers(),
offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
)
self.assertEqual(obj_decoded.expl_offset, offset)
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
def test_go_vectors_valid(self):
for data, expect in ((
class BS(klass):
schema = _schema
+ register_class(BS)
obj = BS(
value=value,
impl=impl,
optional=optional or False,
_decoded=_decoded,
)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
- self.assertEqual(obj.specs, obj_copied.specs)
- self.assertEqual(obj._value, obj_copied._value)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
+ self.assertEqual(obj.specs, obj_copied.specs)
+ self.assertEqual(obj._value, obj_copied._value)
@given(
binary(),
self.assertSetEqual(set(value), set(obj_decoded.named))
for name in value:
obj_decoded[name]
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
@given(integers(min_value=1, max_value=255))
def test_bad_zero_value(self, pad_size):
self.assertTrue(obj.ber_encoded)
self.assertEqual(obj.lenindef, lenindef_expected)
self.assertTrue(obj.bered)
- obj = obj.copy()
+ obj = copy(obj)
self.assertTrue(obj.ber_encoded)
self.assertEqual(obj.lenindef, lenindef_expected)
self.assertTrue(obj.bered)
self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.lenindef)
self.assertTrue(obj.bered)
- obj = obj.copy()
+ obj = copy(obj)
self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.lenindef)
self.assertTrue(obj.bered)
def test_copy(self, values):
for klass in (OctetString, OctetStringInherited):
obj = klass(*values)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
- self.assertEqual(obj._bound_min, obj_copied._bound_min)
- self.assertEqual(obj._bound_max, obj_copied._bound_max)
- self.assertEqual(obj._value, obj_copied._value)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
+ self.assertEqual(obj._bound_min, obj_copied._bound_min)
+ self.assertEqual(obj._bound_max, obj_copied._bound_max)
+ self.assertEqual(obj._value, obj_copied._value)
@given(
binary(),
offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
)
self.assertEqual(obj_decoded.expl_offset, offset)
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
@given(
integers(min_value=1, max_value=30),
self.assertTrue(obj.ber_encoded)
self.assertEqual(obj.lenindef, lenindef_expected)
self.assertTrue(obj.bered)
- obj = obj.copy()
+ obj = copy(obj)
self.assertTrue(obj.ber_encoded)
self.assertEqual(obj.lenindef, lenindef_expected)
self.assertTrue(obj.bered)
optional=optional or False,
_decoded=_decoded,
)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
@given(integers(min_value=1).map(tag_encode))
def test_stripped(self, tag_impl):
offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
)
self.assertEqual(obj_decoded.expl_offset, offset)
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
@given(integers(min_value=1))
def test_invalid_len(self, l):
optional=optional,
_decoded=_decoded,
)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
- self.assertEqual(obj._value, obj_copied._value)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
+ self.assertEqual(obj._value, obj_copied._value)
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(
offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
)
self.assertEqual(obj_decoded.expl_offset, offset)
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
@given(
oid_strategy().map(ObjectIdentifier),
obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.bered)
- obj = obj.copy()
+ obj = copy(obj)
self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.bered)
with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.bered)
- obj = obj.copy()
+ obj = copy(obj)
self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.bered)
with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
class E(Enumerated):
schema = schema_input
+ register_class(E)
obj = E(
value=value,
impl=impl,
optional=optional,
_decoded=_decoded,
)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
- self.assertEqual(obj.specs, obj_copied.specs)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
+ self.assertEqual(obj.specs, obj_copied.specs)
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(data_strategy())
offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
)
self.assertEqual(obj_decoded.expl_offset, offset)
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
@composite
def test_copy(self, d):
values = d.draw(string_values_strategy(self.text_alphabet()))
obj = self.base_klass(*values)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
- self.assertEqual(obj._bound_min, obj_copied._bound_min)
- self.assertEqual(obj._bound_max, obj_copied._bound_max)
- self.assertEqual(obj._value, obj_copied._value)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
+ self.assertEqual(obj._bound_min, obj_copied._bound_min)
+ self.assertEqual(obj._bound_max, obj_copied._bound_max)
+ self.assertEqual(obj._value, obj_copied._value)
@given(data_strategy())
def test_stripped(self, d):
offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
)
self.assertEqual(obj_decoded.expl_offset, offset)
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
class TestUTF8String(StringMixin, CommonMixin, TestCase):
self.assertEqual(err.exception.offset, offset)
self.assertEqual(err.exception.decode_path, decode_path)
+ def test_allowable_invalid_chars(self):
+ for c, kwargs in (
+ ("*", {"allow_asterisk": True}),
+ ("&", {"allow_ampersand": True}),
+ ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
+ ):
+ s = "hello invalid " + c
+ with assertRaisesRegex(self, DecodeError, "non-printable"):
+ self.base_klass(s)
+ self.base_klass(s, **kwargs)
+ klass = self.base_klass(**kwargs)
+ obj = klass(s)
+ obj = copy(obj)
+ obj(s)
+
class TestTeletexString(
UnicodeDecodeErrorMixin,
self.assertTrue(obj.ber_encoded)
self.assertFalse(obj.lenindef)
self.assertTrue(obj.bered)
- obj = obj.copy()
+ obj = copy(obj)
self.assertTrue(obj.ber_encoded)
self.assertFalse(obj.lenindef)
self.assertTrue(obj.bered)
self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.lenindef)
self.assertTrue(obj.bered)
- obj = obj.copy()
+ obj = copy(obj)
self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.lenindef)
self.assertTrue(obj.bered)
max_datetime=self.max_datetime,
))
obj = self.base_klass(*values)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
- self.assertEqual(obj._value, obj_copied._value)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
+ self.assertEqual(obj._value, obj_copied._value)
@given(data_strategy())
def test_stripped(self, d):
offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
)
self.assertEqual(obj_decoded.expl_offset, offset)
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
def test_copy(self, values):
for klass in (Any, AnyInherited):
obj = klass(*values)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
- self.assertEqual(obj._value, obj_copied._value)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
+ self.assertEqual(obj._value, obj_copied._value)
@given(binary().map(OctetString))
def test_stripped(self, value):
self.assertEqual(obj_decoded.tlen, 0)
self.assertEqual(obj_decoded.llen, 0)
self.assertEqual(obj_decoded.vlen, len(value))
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
@given(
integers(min_value=1).map(tag_ctxc),
self.assertTrue(obj.lenindef)
self.assertFalse(obj.ber_encoded)
self.assertTrue(obj.bered)
- obj = obj.copy()
+ obj = copy(obj)
self.assertTrue(obj.lenindef)
self.assertFalse(obj.ber_encoded)
self.assertTrue(obj.bered)
class Wahl(self.base_klass):
schema = _schema
+ register_class(Wahl)
obj = Wahl(
value=value,
expl=expl,
optional=optional or False,
_decoded=_decoded,
)
- obj_copied = obj.copy()
- self.assertIsNone(obj.tag)
- self.assertIsNone(obj_copied.tag)
- # hack for assert_copied_basic_fields
- obj.tag = "whatever"
- obj_copied.tag = "whatever"
- self.assert_copied_basic_fields(obj, obj_copied)
- self.assertEqual(obj._value, obj_copied._value)
- self.assertEqual(obj.specs, obj_copied.specs)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assertIsNone(obj.tag)
+ self.assertIsNone(obj_copied.tag)
+ # hack for assert_copied_basic_fields
+ obj.tag = "whatever"
+ obj_copied.tag = "whatever"
+ self.assert_copied_basic_fields(obj, obj_copied)
+ obj.tag = None
+ self.assertEqual(obj._value, obj_copied._value)
+ self.assertEqual(obj.specs, obj_copied.specs)
@given(booleans())
def test_stripped(self, value):
],
obj_encoded,
)
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
@given(integers())
def test_set_get(self, value):
def test_copy(self, d):
class SeqInherited(self.base_klass):
pass
+ register_class(SeqInherited)
for klass in (self.base_klass, SeqInherited):
values = d.draw(seq_values_strategy(seq_klass=klass))
obj = klass(*values)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
- self.assertEqual(obj.specs, obj_copied.specs)
- self.assertEqual(obj._value, obj_copied._value)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
+ self.assertEqual(obj.specs, obj_copied.specs)
+ self.assertEqual(obj._value, obj_copied._value)
@given(data_strategy())
def test_stripped(self, d):
self.assertDictEqual(ctx_copied, ctx_dummy)
self.assertTrue(seq_decoded_lenindef.lenindef)
self.assertTrue(seq_decoded_lenindef.bered)
- seq_decoded_lenindef = seq_decoded_lenindef.copy()
+ seq_decoded_lenindef = copy(seq_decoded_lenindef)
self.assertTrue(seq_decoded_lenindef.lenindef)
self.assertTrue(seq_decoded_lenindef.bered)
with self.assertRaises(DecodeError):
obj.encode(),
)
+ assert_exceeding_data(
+ self,
+ lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
+ tail_junk,
+ )
+
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(data_strategy())
def test_symmetric_with_seq(self, d):
seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
self.assertTrue(seq_decoded.ber_encoded)
self.assertTrue(seq_decoded.bered)
- seq_decoded = seq_decoded.copy()
+ seq_decoded = copy(seq_decoded)
self.assertTrue(seq_decoded.ber_encoded)
self.assertTrue(seq_decoded.bered)
for name, value in _schema:
self.assertFalse(decoded.ber_encoded)
self.assertFalse(decoded.lenindef)
self.assertTrue(decoded.bered)
- decoded = decoded.copy()
+ decoded = copy(decoded)
self.assertFalse(decoded.ber_encoded)
self.assertFalse(decoded.lenindef)
self.assertTrue(decoded.bered)
self.assertFalse(decoded.ber_encoded)
self.assertFalse(decoded.lenindef)
self.assertTrue(decoded.bered)
- decoded = decoded.copy()
+ decoded = copy(decoded)
self.assertFalse(decoded.ber_encoded)
self.assertFalse(decoded.lenindef)
self.assertTrue(decoded.bered)
seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
self.assertTrue(seq_decoded.ber_encoded)
self.assertTrue(seq_decoded.bered)
- seq_decoded = seq_decoded.copy()
+ seq_decoded = copy(seq_decoded)
self.assertTrue(seq_decoded.ber_encoded)
self.assertTrue(seq_decoded.bered)
self.assertSequenceEqual(
class SeqOf(self.base_klass):
schema = _schema
+ register_class(SeqOf)
obj = SeqOf(
value=value,
bounds=bounds,
optional=optional or False,
_decoded=_decoded,
)
- obj_copied = obj.copy()
- self.assert_copied_basic_fields(obj, obj_copied)
- self.assertEqual(obj._bound_min, obj_copied._bound_min)
- self.assertEqual(obj._bound_max, obj_copied._bound_max)
- self.assertEqual(obj._value, obj_copied._value)
+ for copy_func in copy_funcs:
+ obj_copied = copy_func(obj)
+ self.assert_copied_basic_fields(obj, obj_copied)
+ self.assertEqual(obj._bound_min, obj_copied._bound_min)
+ self.assertEqual(obj._bound_max, obj_copied._bound_max)
+ self.assertEqual(obj._value, obj_copied._value)
@given(
lists(binary()),
)
self.assertTrue(obj_decoded_lenindef.lenindef)
self.assertTrue(obj_decoded_lenindef.bered)
- obj_decoded_lenindef = obj_decoded_lenindef.copy()
+ obj_decoded_lenindef = copy(obj_decoded_lenindef)
self.assertTrue(obj_decoded_lenindef.lenindef)
self.assertTrue(obj_decoded_lenindef.bered)
repr(obj_decoded_lenindef)
list(obj_decoded_lenindef.pps())
pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
+ self.assertEqual(tail_lenindef, tail_junk)
self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
with self.assertRaises(DecodeError):
obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
with self.assertRaises(DecodeError):
obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
+ assert_exceeding_data(
+ self,
+ lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
+ tail_junk,
+ )
+
def test_bered(self):
class SeqOf(self.base_klass):
schema = Boolean()
self.assertFalse(decoded.ber_encoded)
self.assertFalse(decoded.lenindef)
self.assertTrue(decoded.bered)
- decoded = decoded.copy()
+ decoded = copy(decoded)
self.assertFalse(decoded.ber_encoded)
self.assertFalse(decoded.lenindef)
self.assertTrue(decoded.bered)
self.assertFalse(decoded.ber_encoded)
self.assertFalse(decoded.lenindef)
self.assertTrue(decoded.bered)
- decoded = decoded.copy()
+ decoded = copy(decoded)
self.assertFalse(decoded.ber_encoded)
self.assertFalse(decoded.lenindef)
self.assertTrue(decoded.bered)
seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
self.assertTrue(seq_decoded.ber_encoded)
self.assertTrue(seq_decoded.bered)
- seq_decoded = seq_decoded.copy()
+ seq_decoded = copy(seq_decoded)
self.assertTrue(seq_decoded.ber_encoded)
self.assertTrue(seq_decoded.bered)
self.assertSequenceEqual(
decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
self.assertTrue(decoded.ber_encoded)
self.assertTrue(decoded.bered)
- decoded = decoded.copy()
+ decoded = copy(decoded)
self.assertTrue(decoded.ber_encoded)
self.assertTrue(decoded.bered)
decoded, _ = seq.decode(raw, ctx={"bered": True})
self.assertTrue(decoded.ber_encoded)
self.assertTrue(decoded.bered)
- decoded = decoded.copy()
+ decoded = copy(decoded)
self.assertTrue(decoded.ber_encoded)
self.assertTrue(decoded.bered)
with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
Integer(expl=expl).decode(raw)
Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
+
+
+class TestPickleDifferentVersion(TestCase):
+ def runTest(self):
+ pickled = pickle_dumps(Integer(123), pickle_proto)
+ import pyderasn
+ version_orig = pyderasn.__version__
+ pyderasn.__version__ += "different"
+ with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
+ pickle_loads(pickled)
+ pyderasn.__version__ = version_orig
+ pickle_loads(pickled)