]> Cypherpunks.ru repositories - pyderasn.git/blobdiff - tests/test_pyderasn.py
DEFINED BY support
[pyderasn.git] / tests / test_pyderasn.py
index 2fa22ab34daa594c3799b2ad12580ae124e86bd6..23127261feb9175309eea0f8b6e41356f0e7cf56 100644 (file)
@@ -56,6 +56,7 @@ from pyderasn import BMPString
 from pyderasn import Boolean
 from pyderasn import BoundsError
 from pyderasn import Choice
+from pyderasn import decode_path_defby
 from pyderasn import DecodeError
 from pyderasn import Enumerated
 from pyderasn import GeneralizedTime
@@ -85,6 +86,7 @@ from pyderasn import SequenceOf
 from pyderasn import Set
 from pyderasn import SetOf
 from pyderasn import tag_ctxc
+from pyderasn import tag_ctxp
 from pyderasn import tag_decode
 from pyderasn import tag_encode
 from pyderasn import tag_strip
@@ -292,7 +294,6 @@ class CommonMixin(object):
     @given(binary())
     def test_impl_inherited(self, impl_tag):
         class Inherited(self.base_klass):
-            __slots__ = ()
             impl = impl_tag
         obj = Inherited()
         self.assertSequenceEqual(obj.impl, impl_tag)
@@ -301,7 +302,6 @@ class CommonMixin(object):
     @given(binary())
     def test_expl_inherited(self, expl_tag):
         class Inherited(self.base_klass):
-            __slots__ = ()
             expl = expl_tag
         obj = Inherited()
         self.assertSequenceEqual(obj.expl, expl_tag)
@@ -319,7 +319,7 @@ class CommonMixin(object):
 
 
 @composite
-def boolean_values_strat(draw, do_expl=False):
+def boolean_values_strategy(draw, do_expl=False):
     value = draw(one_of(none(), booleans()))
     impl = None
     expl = None
@@ -338,7 +338,7 @@ def boolean_values_strat(draw, do_expl=False):
 
 
 class BooleanInherited(Boolean):
-    __slots__ = ()
+    pass
 
 
 class TestBoolean(CommonMixin, TestCase):
@@ -374,10 +374,12 @@ class TestBoolean(CommonMixin, TestCase):
             obj1 = klass(value1)
             obj2 = klass(value2)
             self.assertEqual(obj1 == obj2, value1 == value2)
+            self.assertEqual(obj1 != obj2, value1 != value2)
             self.assertEqual(obj1 == bool(obj2), value1 == value2)
             obj1 = klass(value1, impl=tag1)
             obj2 = klass(value1, impl=tag2)
             self.assertEqual(obj1 == obj2, tag1 == tag2)
+            self.assertEqual(obj1 != obj2, tag1 != tag2)
 
     @given(data_strategy())
     def test_call(self, d):
@@ -389,7 +391,7 @@ class TestBoolean(CommonMixin, TestCase):
                 default_initial,
                 optional_initial,
                 _decoded_initial,
-            ) = d.draw(boolean_values_strat())
+            ) = d.draw(boolean_values_strategy())
             obj_initial = klass(
                 value_initial,
                 impl_initial,
@@ -405,7 +407,7 @@ class TestBoolean(CommonMixin, TestCase):
                 default,
                 optional,
                 _decoded,
-            ) = d.draw(boolean_values_strat(do_expl=impl_initial is None))
+            ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
             obj = obj_initial(value, impl, expl, default, optional)
             if obj.ready:
                 value_expected = default if value is None else value
@@ -427,7 +429,7 @@ class TestBoolean(CommonMixin, TestCase):
                 optional = True
             self.assertEqual(obj.optional, optional)
 
-    @given(boolean_values_strat())
+    @given(boolean_values_strategy())
     def test_copy(self, values):
         for klass in (Boolean, BooleanInherited):
             obj = klass(*values)
@@ -522,7 +524,7 @@ class TestBoolean(CommonMixin, TestCase):
 
     @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
     @given(
-        boolean_values_strat(),
+        boolean_values_strategy(),
         booleans(),
         integers(min_value=1).map(tag_ctxc),
         integers(min_value=0),
@@ -588,7 +590,7 @@ class TestBoolean(CommonMixin, TestCase):
 
 
 @composite
-def integer_values_strat(draw, do_expl=False):
+def integer_values_strategy(draw, do_expl=False):
     bound_min, value, default, bound_max = sorted(draw(sets(
         integers(),
         min_size=4,
@@ -626,7 +628,7 @@ def integer_values_strat(draw, do_expl=False):
 
 
 class IntegerInherited(Integer):
-    __slots__ = ()
+    pass
 
 
 class TestInteger(CommonMixin, TestCase):
@@ -642,7 +644,6 @@ class TestInteger(CommonMixin, TestCase):
         missing = names_input.pop()
 
         class Int(Integer):
-            __slots__ = ()
             schema = [(n, 123) for n in names_input]
         with self.assertRaises(ObjUnknown) as err:
             Int(missing)
@@ -651,7 +652,6 @@ class TestInteger(CommonMixin, TestCase):
     @given(sets(text_letters(), min_size=2))
     def test_known_name(self, names_input):
         class Int(Integer):
-            __slots__ = ()
             schema = [(n, 123) for n in names_input]
         Int(names_input.pop())
 
@@ -681,10 +681,12 @@ class TestInteger(CommonMixin, TestCase):
             obj1 = klass(value1)
             obj2 = klass(value2)
             self.assertEqual(obj1 == obj2, value1 == value2)
+            self.assertEqual(obj1 != obj2, value1 != value2)
             self.assertEqual(obj1 == int(obj2), value1 == value2)
             obj1 = klass(value1, impl=tag1)
             obj2 = klass(value1, impl=tag2)
             self.assertEqual(obj1 == obj2, tag1 == tag2)
+            self.assertEqual(obj1 != obj2, tag1 != tag2)
 
     @given(lists(integers()))
     def test_sorted_works(self, values):
@@ -705,7 +707,6 @@ class TestInteger(CommonMixin, TestCase):
         names_input = dict(zip(names_input, values_input))
 
         class Int(Integer):
-            __slots__ = ()
             schema = names_input
         _int = Int(chosen_name)
         self.assertEqual(_int.named, chosen_name)
@@ -739,7 +740,7 @@ class TestInteger(CommonMixin, TestCase):
                 optional_initial,
                 _specs_initial,
                 _decoded_initial,
-            ) = d.draw(integer_values_strat())
+            ) = d.draw(integer_values_strategy())
             obj_initial = klass(
                 value_initial,
                 bounds_initial,
@@ -759,7 +760,7 @@ class TestInteger(CommonMixin, TestCase):
                 optional,
                 _,
                 _decoded,
-            ) = d.draw(integer_values_strat(do_expl=impl_initial is None))
+            ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
             if (default is None) and (obj_initial.default is not None):
                 bounds = None
             if (
@@ -805,7 +806,7 @@ class TestInteger(CommonMixin, TestCase):
                 {} if _specs_initial is None else dict(_specs_initial),
             )
 
-    @given(integer_values_strat())
+    @given(integer_values_strategy())
     def test_copy(self, values):
         for klass in (Integer, IntegerInherited):
             obj = klass(*values)
@@ -898,7 +899,7 @@ class TestInteger(CommonMixin, TestCase):
 
     @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
     @given(
-        integer_values_strat(),
+        integer_values_strategy(),
         integers(),
         integers(min_value=1).map(tag_ctxc),
         integers(min_value=0),
@@ -983,7 +984,7 @@ class TestInteger(CommonMixin, TestCase):
 
 
 @composite
-def bit_string_values_strat(draw, schema=None, value_required=False, do_expl=False):
+def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
     if schema is None:
         schema = ()
         if draw(booleans()):
@@ -1029,7 +1030,7 @@ def bit_string_values_strat(draw, schema=None, value_required=False, do_expl=Fal
 
 
 class BitStringInherited(BitString):
-    __slots__ = ()
+    pass
 
 
 class TestBitString(CommonMixin, TestCase):
@@ -1063,7 +1064,6 @@ class TestBitString(CommonMixin, TestCase):
         self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
 
         class BS(BitString):
-            __slots__ = ()
             schema = (("whatever", 0),)
         obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
         self.assertEqual(obj.bit_len, leading_zeros + 1)
@@ -1089,7 +1089,7 @@ class TestBitString(CommonMixin, TestCase):
             BitString(b"whatever")["whenever"]
         repr(err.exception)
 
-    def test_get_invalid_typ(self):
+    def test_get_invalid_type(self):
         with self.assertRaises(InvalidValueType) as err:
             BitString(b"whatever")[(1, 2, 3)]
         repr(err.exception)
@@ -1100,7 +1100,6 @@ class TestBitString(CommonMixin, TestCase):
         missing = _schema.pop()
 
         class BS(BitString):
-            __slots__ = ()
             schema = [(n, i) for i, n in enumerate(_schema)]
         with self.assertRaises(ObjUnknown) as err:
             BS((missing,))
@@ -1136,10 +1135,12 @@ class TestBitString(CommonMixin, TestCase):
             obj1 = klass(value1)
             obj2 = klass(value2)
             self.assertEqual(obj1 == obj2, value1 == value2)
+            self.assertEqual(obj1 != obj2, value1 != value2)
             self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
             obj1 = klass(value1, impl=tag1)
             obj2 = klass(value1, impl=tag2)
             self.assertEqual(obj1 == obj2, tag1 == tag2)
+            self.assertEqual(obj1 != obj2, tag1 != tag2)
 
     @given(data_strategy())
     def test_call(self, d):
@@ -1152,10 +1153,9 @@ class TestBitString(CommonMixin, TestCase):
                 default_initial,
                 optional_initial,
                 _decoded_initial,
-            ) = d.draw(bit_string_values_strat())
+            ) = d.draw(bit_string_values_strategy())
 
             class BS(klass):
-                __slots__ = ()
                 schema = schema_initial
             obj_initial = BS(
                 value=value_initial,
@@ -1173,7 +1173,7 @@ class TestBitString(CommonMixin, TestCase):
                 default,
                 optional,
                 _decoded,
-            ) = d.draw(bit_string_values_strat(
+            ) = d.draw(bit_string_values_strategy(
                 schema=schema_initial,
                 do_expl=impl_initial is None,
             ))
@@ -1194,13 +1194,12 @@ class TestBitString(CommonMixin, TestCase):
             self.assertEqual(obj.optional, optional)
             self.assertEqual(obj.specs, obj_initial.specs)
 
-    @given(bit_string_values_strat())
+    @given(bit_string_values_strategy())
     def test_copy(self, values):
         for klass in (BitString, BitStringInherited):
             _schema, value, impl, expl, default, optional, _decoded = values
 
             class BS(klass):
-                __slots__ = ()
                 schema = _schema
             obj = BS(
                 value=value,
@@ -1278,12 +1277,11 @@ class TestBitString(CommonMixin, TestCase):
             default,
             optional,
             _decoded,
-        ) = d.draw(bit_string_values_strat(value_required=True))
+        ) = d.draw(bit_string_values_strategy(value_required=True))
         tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
         offset = d.draw(integers(min_value=0))
         for klass in (BitString, BitStringInherited):
             class BS(klass):
-                __slots__ = ()
                 schema = _schema
             obj = BS(
                 value=value,
@@ -1375,7 +1373,7 @@ class TestBitString(CommonMixin, TestCase):
 
 
 @composite
-def octet_string_values_strat(draw, do_expl=False):
+def octet_string_values_strategy(draw, do_expl=False):
     bound_min, bound_max = sorted(draw(sets(
         integers(min_value=0, max_value=1 << 7),
         min_size=2,
@@ -1408,7 +1406,7 @@ def octet_string_values_strat(draw, do_expl=False):
 
 
 class OctetStringInherited(OctetString):
-    __slots__ = ()
+    pass
 
 
 class TestOctetString(CommonMixin, TestCase):
@@ -1444,10 +1442,19 @@ class TestOctetString(CommonMixin, TestCase):
             obj1 = klass(value1)
             obj2 = klass(value2)
             self.assertEqual(obj1 == obj2, value1 == value2)
+            self.assertEqual(obj1 != obj2, value1 != value2)
             self.assertEqual(obj1 == bytes(obj2), value1 == value2)
             obj1 = klass(value1, impl=tag1)
             obj2 = klass(value1, impl=tag2)
             self.assertEqual(obj1 == obj2, tag1 == tag2)
+            self.assertEqual(obj1 != obj2, tag1 != tag2)
+
+    @given(lists(binary()))
+    def test_sorted_works(self, values):
+        self.assertSequenceEqual(
+            [bytes(v) for v in sorted(OctetString(v) for v in values)],
+            sorted(values),
+        )
 
     @given(data_strategy())
     def test_bounds_satisfied(self, d):
@@ -1480,7 +1487,7 @@ class TestOctetString(CommonMixin, TestCase):
                 default_initial,
                 optional_initial,
                 _decoded_initial,
-            ) = d.draw(octet_string_values_strat())
+            ) = d.draw(octet_string_values_strategy())
             obj_initial = klass(
                 value_initial,
                 bounds_initial,
@@ -1498,7 +1505,7 @@ class TestOctetString(CommonMixin, TestCase):
                 default,
                 optional,
                 _decoded,
-            ) = d.draw(octet_string_values_strat(do_expl=impl_initial is None))
+            ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
             if (default is None) and (obj_initial.default is not None):
                 bounds = None
             if (
@@ -1540,7 +1547,7 @@ class TestOctetString(CommonMixin, TestCase):
                 bounds or bounds_initial or (0, float("+inf")),
             )
 
-    @given(octet_string_values_strat())
+    @given(octet_string_values_strategy())
     def test_copy(self, values):
         for klass in (OctetString, OctetStringInherited):
             obj = klass(*values)
@@ -1625,7 +1632,7 @@ class TestOctetString(CommonMixin, TestCase):
 
     @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
     @given(
-        octet_string_values_strat(),
+        octet_string_values_strategy(),
         binary(),
         integers(min_value=1).map(tag_ctxc),
         integers(min_value=0),
@@ -1673,7 +1680,7 @@ class TestOctetString(CommonMixin, TestCase):
 
 
 @composite
-def null_values_strat(draw, do_expl=False):
+def null_values_strategy(draw, do_expl=False):
     impl = None
     expl = None
     if do_expl:
@@ -1690,7 +1697,7 @@ def null_values_strat(draw, do_expl=False):
 
 
 class NullInherited(Null):
-    __slots__ = ()
+    pass
 
 
 class TestNull(CommonMixin, TestCase):
@@ -1708,6 +1715,7 @@ class TestNull(CommonMixin, TestCase):
             obj1 = klass(impl=tag1)
             obj2 = klass(impl=tag2)
             self.assertEqual(obj1 == obj2, tag1 == tag2)
+            self.assertEqual(obj1 != obj2, tag1 != tag2)
             self.assertNotEqual(obj1, tag2)
 
     @given(data_strategy())
@@ -1718,7 +1726,7 @@ class TestNull(CommonMixin, TestCase):
                 expl_initial,
                 optional_initial,
                 _decoded_initial,
-            ) = d.draw(null_values_strat())
+            ) = d.draw(null_values_strategy())
             obj_initial = klass(
                 impl=impl_initial,
                 expl=expl_initial,
@@ -1730,7 +1738,7 @@ class TestNull(CommonMixin, TestCase):
                 expl,
                 optional,
                 _decoded,
-            ) = d.draw(null_values_strat(do_expl=impl_initial is None))
+            ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
             obj = obj_initial(impl=impl, expl=expl, optional=optional)
             self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
             self.assertEqual(obj.expl_tag, expl or expl_initial)
@@ -1738,7 +1746,7 @@ class TestNull(CommonMixin, TestCase):
             optional = False if optional is None else optional
             self.assertEqual(obj.optional, optional)
 
-    @given(null_values_strat())
+    @given(null_values_strategy())
     def test_copy(self, values):
         for klass in (Null, NullInherited):
             impl, expl, optional, _decoded = values
@@ -1804,7 +1812,7 @@ class TestNull(CommonMixin, TestCase):
             Null(impl=impl).decode(Null().encode())
 
     @given(
-        null_values_strat(),
+        null_values_strategy(),
         integers(min_value=1).map(tag_ctxc),
         integers(min_value=0),
     )
@@ -1864,7 +1872,7 @@ def oid_strategy(draw):
 
 
 @composite
-def oid_values_strat(draw, do_expl=False):
+def oid_values_strategy(draw, do_expl=False):
     value = draw(one_of(none(), oid_strategy()))
     impl = None
     expl = None
@@ -1883,7 +1891,7 @@ def oid_values_strat(draw, do_expl=False):
 
 
 class ObjectIdentifierInherited(ObjectIdentifier):
-    __slots__ = ()
+    pass
 
 
 class TestObjectIdentifier(CommonMixin, TestCase):
@@ -1920,11 +1928,13 @@ class TestObjectIdentifier(CommonMixin, TestCase):
             obj1 = klass(value1)
             obj2 = klass(value2)
             self.assertEqual(obj1 == obj2, value1 == value2)
+            self.assertEqual(obj1 != obj2, value1 != value2)
             self.assertEqual(obj1 == tuple(obj2), value1 == value2)
             self.assertEqual(str(obj1) == str(obj2), value1 == value2)
             obj1 = klass(value1, impl=tag1)
             obj2 = klass(value1, impl=tag2)
             self.assertEqual(obj1 == obj2, tag1 == tag2)
+            self.assertEqual(obj1 != obj2, tag1 != tag2)
 
     @given(lists(oid_strategy()))
     def test_sorted_works(self, values):
@@ -1943,14 +1953,14 @@ class TestObjectIdentifier(CommonMixin, TestCase):
                 default_initial,
                 optional_initial,
                 _decoded_initial,
-            ) = d.draw(oid_values_strat())
+            ) = d.draw(oid_values_strategy())
             obj_initial = klass(
-                value_initial,
-                impl_initial,
-                expl_initial,
-                default_initial,
-                optional_initial or False,
-                _decoded_initial,
+                value=value_initial,
+                impl=impl_initial,
+                expl=expl_initial,
+                default=default_initial,
+                optional=optional_initial or False,
+                _decoded=_decoded_initial,
             )
             (
                 value,
@@ -1959,8 +1969,14 @@ class TestObjectIdentifier(CommonMixin, TestCase):
                 default,
                 optional,
                 _decoded,
-            ) = d.draw(oid_values_strat(do_expl=impl_initial is None))
-            obj = obj_initial(value, impl, expl, default, optional)
+            ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
+            obj = obj_initial(
+                value=value,
+                impl=impl,
+                expl=expl,
+                default=default,
+                optional=optional,
+            )
             if obj.ready:
                 value_expected = default if value is None else value
                 value_expected = (
@@ -1981,10 +1997,25 @@ class TestObjectIdentifier(CommonMixin, TestCase):
                 optional = True
             self.assertEqual(obj.optional, optional)
 
-    @given(oid_values_strat())
+    @given(oid_values_strategy())
     def test_copy(self, values):
         for klass in (ObjectIdentifier, ObjectIdentifierInherited):
-            obj = klass(*values)
+            (
+                value,
+                impl,
+                expl,
+                default,
+                optional,
+                _decoded,
+            ) = values
+            obj = klass(
+                value=value,
+                impl=impl,
+                expl=expl,
+                default=default,
+                optional=optional,
+                _decoded=_decoded,
+            )
             obj_copied = obj.copy()
             self.assert_copied_basic_fields(obj, obj_copied)
             self.assertEqual(obj._value, obj_copied._value)
@@ -2100,7 +2131,7 @@ class TestObjectIdentifier(CommonMixin, TestCase):
 
     @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
     @given(
-        oid_values_strat(),
+        oid_values_strategy(),
         oid_strategy(),
         integers(min_value=1).map(tag_ctxc),
         integers(min_value=0),
@@ -2184,7 +2215,7 @@ class TestObjectIdentifier(CommonMixin, TestCase):
 
 
 @composite
-def enumerated_values_strat(draw, schema=None, do_expl=False):
+def enumerated_values_strategy(draw, schema=None, do_expl=False):
     if schema is None:
         schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
         values = list(draw(sets(
@@ -2212,7 +2243,6 @@ def enumerated_values_strat(draw, schema=None, do_expl=False):
 
 class TestEnumerated(CommonMixin, TestCase):
     class EWhatever(Enumerated):
-        __slots__ = ()
         schema = (("whatever", 0),)
 
     base_klass = EWhatever
@@ -2231,7 +2261,6 @@ class TestEnumerated(CommonMixin, TestCase):
         missing = schema_input.pop()
 
         class E(Enumerated):
-            __slots__ = ()
             schema = [(n, 123) for n in schema_input]
         with self.assertRaises(ObjUnknown) as err:
             E(missing)
@@ -2247,7 +2276,6 @@ class TestEnumerated(CommonMixin, TestCase):
         _input = list(zip(schema_input, values_input))
 
         class E(Enumerated):
-            __slots__ = ()
             schema = _input
         with self.assertRaises(DecodeError) as err:
             E(missing_value)
@@ -2274,22 +2302,23 @@ class TestEnumerated(CommonMixin, TestCase):
     @given(integers(), integers(), binary(), binary())
     def test_comparison(self, value1, value2, tag1, tag2):
         class E(Enumerated):
-            __slots__ = ()
             schema = (
                 ("whatever0", value1),
                 ("whatever1", value2),
             )
 
         class EInherited(E):
-            __slots__ = ()
+            pass
         for klass in (E, EInherited):
             obj1 = klass(value1)
             obj2 = klass(value2)
             self.assertEqual(obj1 == obj2, value1 == value2)
+            self.assertEqual(obj1 != obj2, value1 != value2)
             self.assertEqual(obj1 == int(obj2), value1 == value2)
             obj1 = klass(value1, impl=tag1)
             obj2 = klass(value1, impl=tag2)
             self.assertEqual(obj1 == obj2, tag1 == tag2)
+            self.assertEqual(obj1 != obj2, tag1 != tag2)
 
     @given(data_strategy())
     def test_call(self, d):
@@ -2301,10 +2330,9 @@ class TestEnumerated(CommonMixin, TestCase):
             default_initial,
             optional_initial,
             _decoded_initial,
-        ) = d.draw(enumerated_values_strat())
+        ) = d.draw(enumerated_values_strategy())
 
         class E(Enumerated):
-            __slots__ = ()
             schema = schema_initial
         obj_initial = E(
             value=value_initial,
@@ -2322,7 +2350,7 @@ class TestEnumerated(CommonMixin, TestCase):
             default,
             optional,
             _decoded,
-        ) = d.draw(enumerated_values_strat(
+        ) = d.draw(enumerated_values_strategy(
             schema=schema_initial,
             do_expl=impl_initial is None,
         ))
@@ -2357,12 +2385,11 @@ class TestEnumerated(CommonMixin, TestCase):
         self.assertEqual(obj.optional, optional)
         self.assertEqual(obj.specs, dict(schema_initial))
 
-    @given(enumerated_values_strat())
+    @given(enumerated_values_strategy())
     def test_copy(self, values):
         schema_input, value, impl, expl, default, optional, _decoded = values
 
         class E(Enumerated):
-            __slots__ = ()
             schema = schema_input
         obj = E(
             value=value,
@@ -2380,14 +2407,13 @@ class TestEnumerated(CommonMixin, TestCase):
     @given(data_strategy())
     def test_symmetric(self, d):
         schema_input, _, _, _, default, optional, _decoded = d.draw(
-            enumerated_values_strat(),
+            enumerated_values_strategy(),
         )
         tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
         offset = d.draw(integers(min_value=0))
         value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
 
         class E(Enumerated):
-            __slots__ = ()
             schema = schema_input
         obj = E(
             value=value,
@@ -2429,7 +2455,7 @@ class TestEnumerated(CommonMixin, TestCase):
 
 
 @composite
-def string_values_strat(draw, alphabet, do_expl=False):
+def string_values_strategy(draw, alphabet, do_expl=False):
     bound_min, bound_max = sorted(draw(sets(
         integers(min_value=0, max_value=1 << 7),
         min_size=2,
@@ -2503,11 +2529,13 @@ class StringMixin(object):
         obj1 = self.base_klass(value1)
         obj2 = self.base_klass(value2)
         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)
         obj1 = self.base_klass(value1, impl=tag1)
         obj2 = self.base_klass(value1, impl=tag2)
         self.assertEqual(obj1 == obj2, tag1 == tag2)
+        self.assertEqual(obj1 != obj2, tag1 != tag2)
 
     @given(data_strategy())
     def test_bounds_satisfied(self, d):
@@ -2543,7 +2571,7 @@ class StringMixin(object):
             default_initial,
             optional_initial,
             _decoded_initial,
-        ) = d.draw(string_values_strat(self.text_alphabet()))
+        ) = d.draw(string_values_strategy(self.text_alphabet()))
         obj_initial = self.base_klass(
             value_initial,
             bounds_initial,
@@ -2561,7 +2589,7 @@ class StringMixin(object):
             default,
             optional,
             _decoded,
-        ) = d.draw(string_values_strat(
+        ) = d.draw(string_values_strategy(
             self.text_alphabet(),
             do_expl=impl_initial is None,
         ))
@@ -2608,7 +2636,7 @@ class StringMixin(object):
 
     @given(data_strategy())
     def test_copy(self, d):
-        values = d.draw(string_values_strat(self.text_alphabet()))
+        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)
@@ -2691,7 +2719,7 @@ class StringMixin(object):
 
     @given(data_strategy())
     def test_symmetric(self, d):
-        values = d.draw(string_values_strat(self.text_alphabet()))
+        values = d.draw(string_values_strategy(self.text_alphabet()))
         value = d.draw(text(alphabet=self.text_alphabet()))
         tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
         offset = d.draw(integers(min_value=0))
@@ -2782,7 +2810,7 @@ class TestBMPString(StringMixin, CommonMixin, TestCase):
 
 
 @composite
-def generalized_time_values_strat(
+def generalized_time_values_strategy(
         draw,
         min_datetime,
         max_datetime,
@@ -2863,11 +2891,13 @@ class TimeMixin(object):
         obj1 = self.base_klass(value1)
         obj2 = self.base_klass(value2)
         self.assertEqual(obj1 == obj2, value1 == value2)
+        self.assertEqual(obj1 != obj2, value1 != value2)
         self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
         self.assertEqual(obj1 == bytes(obj2), value1 == value2)
         obj1 = self.base_klass(value1, impl=tag1)
         obj2 = self.base_klass(value1, impl=tag2)
         self.assertEqual(obj1 == obj2, tag1 == tag2)
+        self.assertEqual(obj1 != obj2, tag1 != tag2)
 
     @given(data_strategy())
     def test_call(self, d):
@@ -2878,7 +2908,7 @@ class TimeMixin(object):
             default_initial,
             optional_initial,
             _decoded_initial,
-        ) = d.draw(generalized_time_values_strat(
+        ) = d.draw(generalized_time_values_strategy(
             min_datetime=self.min_datetime,
             max_datetime=self.max_datetime,
             omit_ms=self.omit_ms,
@@ -2898,7 +2928,7 @@ class TimeMixin(object):
             default,
             optional,
             _decoded,
-        ) = d.draw(generalized_time_values_strat(
+        ) = d.draw(generalized_time_values_strategy(
             min_datetime=self.min_datetime,
             max_datetime=self.max_datetime,
             omit_ms=self.omit_ms,
@@ -2933,7 +2963,7 @@ class TimeMixin(object):
 
     @given(data_strategy())
     def test_copy(self, d):
-        values = d.draw(generalized_time_values_strat(
+        values = d.draw(generalized_time_values_strategy(
             min_datetime=self.min_datetime,
             max_datetime=self.max_datetime,
         ))
@@ -2967,7 +2997,7 @@ class TimeMixin(object):
     @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
     @given(data_strategy())
     def test_symmetric(self, d):
-        values = d.draw(generalized_time_values_strat(
+        values = d.draw(generalized_time_values_strategy(
             min_datetime=self.min_datetime,
             max_datetime=self.max_datetime,
         ))
@@ -3122,7 +3152,7 @@ class TestUTCTime(TimeMixin, CommonMixin, TestCase):
 
 
 @composite
-def any_values_strat(draw, do_expl=False):
+def any_values_strategy(draw, do_expl=False):
     value = draw(one_of(none(), binary()))
     expl = None
     if do_expl:
@@ -3137,7 +3167,7 @@ def any_values_strat(draw, do_expl=False):
 
 
 class AnyInherited(Any):
-    __slots__ = ()
+    pass
 
 
 class TestAny(CommonMixin, TestCase):
@@ -3190,6 +3220,7 @@ class TestAny(CommonMixin, TestCase):
             obj1 = klass(value1)
             obj2 = klass(value2)
             self.assertEqual(obj1 == obj2, value1 == value2)
+            self.assertEqual(obj1 != obj2, value1 != value2)
             self.assertEqual(obj1 == bytes(obj2), value1 == value2)
 
     @given(data_strategy())
@@ -3200,7 +3231,7 @@ class TestAny(CommonMixin, TestCase):
                 expl_initial,
                 optional_initial,
                 _decoded_initial,
-            ) = d.draw(any_values_strat())
+            ) = d.draw(any_values_strategy())
             obj_initial = klass(
                 value_initial,
                 expl_initial,
@@ -3212,7 +3243,7 @@ class TestAny(CommonMixin, TestCase):
                 expl,
                 optional,
                 _decoded,
-            ) = d.draw(any_values_strat(do_expl=True))
+            ) = d.draw(any_values_strategy(do_expl=True))
             obj = obj_initial(value, expl, optional)
             if obj.ready:
                 value_expected = None if value is None else value
@@ -3231,7 +3262,7 @@ class TestAny(CommonMixin, TestCase):
         # override it, as Any does not have implicit tag
         pass
 
-    @given(any_values_strat())
+    @given(any_values_strategy())
     def test_copy(self, values):
         for klass in (Any, AnyInherited):
             obj = klass(*values)
@@ -3290,7 +3321,7 @@ class TestAny(CommonMixin, TestCase):
 
     @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
     @given(
-        any_values_strat(),
+        any_values_strategy(),
         integers().map(lambda x: Integer(x).encode()),
         integers(min_value=1).map(tag_ctxc),
         integers(min_value=0),
@@ -3335,7 +3366,7 @@ class TestAny(CommonMixin, TestCase):
 
 
 @composite
-def choice_values_strat(draw, value_required=False, schema=None, do_expl=False):
+def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
     if schema is None:
         names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
         tags = [tag_encode(tag) for tag in draw(sets(
@@ -3367,7 +3398,7 @@ def choice_values_strat(draw, value_required=False, schema=None, do_expl=False):
 
 
 class ChoiceInherited(Choice):
-    __slots__ = ()
+    pass
 
 
 class TestChoice(CommonMixin, TestCase):
@@ -3424,11 +3455,12 @@ class TestChoice(CommonMixin, TestCase):
     @given(booleans(), booleans())
     def test_comparison(self, value1, value2):
         class WahlInherited(self.base_klass):
-            __slots__ = ()
+            pass
         for klass in (self.base_klass, WahlInherited):
             obj1 = klass(("whatever", Boolean(value1)))
             obj2 = klass(("whatever", Boolean(value2)))
             self.assertEqual(obj1 == obj2, value1 == value2)
+            self.assertEqual(obj1 != obj2, value1 != value2)
             self.assertEqual(obj1 == obj2._value, value1 == value2)
             self.assertFalse(obj1 == obj2._value[1])
 
@@ -3442,10 +3474,9 @@ class TestChoice(CommonMixin, TestCase):
                 default_initial,
                 optional_initial,
                 _decoded_initial,
-            ) = d.draw(choice_values_strat())
+            ) = d.draw(choice_values_strategy())
 
             class Wahl(klass):
-                __slots__ = ()
                 schema = schema_initial
             obj_initial = Wahl(
                 value=value_initial,
@@ -3461,7 +3492,7 @@ class TestChoice(CommonMixin, TestCase):
                 default,
                 optional,
                 _decoded,
-            ) = d.draw(choice_values_strat(schema=schema_initial, do_expl=True))
+            ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
             obj = obj_initial(value, expl, default, optional)
             if obj.ready:
                 value_expected = default if value is None else value
@@ -3492,12 +3523,11 @@ class TestChoice(CommonMixin, TestCase):
         # override it, as Any does not have implicit tag
         pass
 
-    @given(choice_values_strat())
+    @given(choice_values_strategy())
     def test_copy(self, values):
         _schema, value, expl, default, optional, _decoded = values
 
         class Wahl(self.base_klass):
-            __slots__ = ()
             schema = _schema
         obj = Wahl(
             value=value,
@@ -3535,13 +3565,12 @@ class TestChoice(CommonMixin, TestCase):
     @given(data_strategy())
     def test_symmetric(self, d):
         _schema, value, _, default, optional, _decoded = d.draw(
-            choice_values_strat(value_required=True)
+            choice_values_strategy(value_required=True)
         )
         tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
         offset = d.draw(integers(min_value=0))
 
         class Wahl(self.base_klass):
-            __slots__ = ()
             schema = _schema
         obj = Wahl(
             value=value,
@@ -3623,7 +3652,7 @@ class TestChoice(CommonMixin, TestCase):
 
 
 @composite
-def seq_values_strat(draw, seq_klass, do_expl=False):
+def seq_values_strategy(draw, seq_klass, do_expl=False):
     value = None
     if draw(booleans()):
         value = seq_klass()
@@ -3673,7 +3702,7 @@ def seq_values_strat(draw, seq_klass, do_expl=False):
 
 
 @composite
-def sequence_strat(draw, seq_klass):
+def sequence_strategy(draw, seq_klass):
     inputs = draw(lists(
         one_of(
             tuples(just(Boolean), booleans(), one_of(none(), booleans())),
@@ -3714,7 +3743,7 @@ def sequence_strat(draw, seq_klass):
     for i, (klass, value, default) in enumerate(inputs):
         schema.append((names[i], klass(default=default, **inits[i])))
     seq_name = draw(text_letters())
-    Seq = type(seq_name, (seq_klass,), {"__slots__": (), "schema": tuple(schema)})
+    Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
     seq = Seq()
     expects = []
     for i, (klass, value, default) in enumerate(inputs):
@@ -3742,7 +3771,7 @@ def sequence_strat(draw, seq_klass):
 
 
 @composite
-def sequences_strat(draw, seq_klass):
+def sequences_strategy(draw, seq_klass):
     tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
     inits = [
         ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
@@ -3765,7 +3794,7 @@ def sequences_strat(draw, seq_klass):
         max_size=len(tags),
     )))
     seq_expectses = draw(lists(
-        sequence_strat(seq_klass=seq_klass),
+        sequence_strategy(seq_klass=seq_klass),
         min_size=len(tags),
         max_size=len(tags),
     ))
@@ -3777,7 +3806,7 @@ def sequences_strat(draw, seq_klass):
             seq(default=(seq if i in defaulted else None), **inits[i]),
         ))
     seq_name = draw(text_letters())
-    Seq = type(seq_name, (seq_klass,), {"__slots__": (), "schema": tuple(schema)})
+    Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
     seq_outer = Seq()
     expect_outers = []
     for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
@@ -3801,7 +3830,6 @@ class SeqMixing(object):
 
     def test_invalid_value_type_set(self):
         class Seq(self.base_klass):
-            __slots__ = ()
             schema = (("whatever", Boolean()),)
         seq = Seq()
         with self.assertRaises(InvalidValueType) as err:
@@ -3836,7 +3864,6 @@ class SeqMixing(object):
             schema_input.append((name, Boolean()))
 
         class Seq(self.base_klass):
-            __slots__ = ()
             schema = tuple(schema_input)
         seq = Seq()
         for name in ready.keys():
@@ -3862,7 +3889,7 @@ class SeqMixing(object):
     @given(data_strategy())
     def test_call(self, d):
         class SeqInherited(self.base_klass):
-            __slots__ = ()
+            pass
         for klass in (self.base_klass, SeqInherited):
             (
                 value_initial,
@@ -3872,7 +3899,7 @@ class SeqMixing(object):
                 default_initial,
                 optional_initial,
                 _decoded_initial,
-            ) = d.draw(seq_values_strat(seq_klass=klass))
+            ) = d.draw(seq_values_strategy(seq_klass=klass))
             obj_initial = klass(
                 value_initial,
                 schema_initial,
@@ -3890,7 +3917,7 @@ class SeqMixing(object):
                 default,
                 optional,
                 _decoded,
-            ) = d.draw(seq_values_strat(
+            ) = d.draw(seq_values_strategy(
                 seq_klass=klass,
                 do_expl=impl_initial is None,
             ))
@@ -3918,9 +3945,9 @@ class SeqMixing(object):
     @given(data_strategy())
     def test_copy(self, d):
         class SeqInherited(self.base_klass):
-            __slots__ = ()
+            pass
         for klass in (self.base_klass, SeqInherited):
-            values = d.draw(seq_values_strat(seq_klass=klass))
+            values = d.draw(seq_values_strategy(seq_klass=klass))
             obj = klass(*values)
             obj_copied = obj.copy()
             self.assert_copied_basic_fields(obj, obj_copied)
@@ -3933,7 +3960,6 @@ class SeqMixing(object):
         tag_impl = tag_encode(d.draw(integers(min_value=1)))
 
         class Seq(self.base_klass):
-            __slots__ = ()
             impl = tag_impl
             schema = (("whatever", Integer()),)
         seq = Seq()
@@ -3947,7 +3973,6 @@ class SeqMixing(object):
         tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
 
         class Seq(self.base_klass):
-            __slots__ = ()
             expl = tag_expl
             schema = (("whatever", Integer()),)
         seq = Seq()
@@ -3966,7 +3991,6 @@ class SeqMixing(object):
             assume(False)
 
         class Seq(self.base_klass):
-            __slots__ = ()
             schema = (
                 ("whatever", Integer()),
                 ("junk", Any()),
@@ -4031,7 +4055,7 @@ class SeqMixing(object):
     @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
     @given(data_strategy())
     def test_symmetric(self, d):
-        seq, expects = d.draw(sequence_strat(seq_klass=self.base_klass))
+        seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
         self.assertTrue(seq.ready)
         self.assertFalse(seq.decoded)
         self._assert_expects(seq, expects)
@@ -4061,7 +4085,7 @@ class SeqMixing(object):
     @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
     @given(data_strategy())
     def test_symmetric_with_seq(self, d):
-        seq, expect_outers = d.draw(sequences_strat(seq_klass=self.base_klass))
+        seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
         self.assertTrue(seq.ready)
         seq_encoded = seq.encode()
         seq_decoded, tail = seq.decode(seq_encoded)
@@ -4093,7 +4117,6 @@ class SeqMixing(object):
         )).items())
 
         class Seq(self.base_klass):
-            __slots__ = ()
             schema = [
                 (n, Integer(default=d))
                 for n, (_, d) in _schema
@@ -4123,7 +4146,6 @@ class SeqMixing(object):
         ))]
 
         class SeqWithoutDefault(self.base_klass):
-            __slots__ = ()
             schema = [
                 (n, Integer(impl=t))
                 for (n, _), t in zip(_schema, tags)
@@ -4134,7 +4156,6 @@ class SeqMixing(object):
         seq_encoded = seq_without_default.encode()
 
         class SeqWithDefault(self.base_klass):
-            __slots__ = ()
             schema = [
                 (n, Integer(default=v, impl=t))
                 for (n, v), t in zip(_schema, tags)
@@ -4156,7 +4177,6 @@ class SeqMixing(object):
         names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
 
         class SeqFull(self.base_klass):
-            __slots__ = ()
             schema = [(n, Integer(impl=t)) for n, t in names_tags]
         seq_full = SeqFull()
         for i, name in enumerate(names):
@@ -4165,7 +4185,6 @@ class SeqMixing(object):
         altered = names_tags[:-2] + names_tags[-1:]
 
         class SeqMissing(self.base_klass):
-            __slots__ = ()
             schema = [(n, Integer(impl=t)) for n, t in altered]
         seq_missing = SeqMissing()
         with self.assertRaises(TagMismatch):
@@ -4181,7 +4200,6 @@ class TestSequence(SeqMixing, CommonMixin, TestCase):
     )
     def test_remaining(self, value, junk):
         class Seq(Sequence):
-            __slots__ = ()
             schema = (
                 ("whatever", Integer()),
             )
@@ -4199,7 +4217,6 @@ class TestSequence(SeqMixing, CommonMixin, TestCase):
         missing = names.pop()
 
         class Seq(Sequence):
-            __slots__ = ()
             schema = [(n, Boolean()) for n in names]
         seq = Seq()
         with self.assertRaises(ObjUnknown) as err:
@@ -4222,7 +4239,6 @@ class TestSet(SeqMixing, CommonMixin, TestCase):
         ]
 
         class Seq(Set):
-            __slots__ = ()
             schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
         seq = Seq()
         for name, _ in Seq.schema:
@@ -4236,7 +4252,7 @@ class TestSet(SeqMixing, CommonMixin, TestCase):
 
 
 @composite
-def seqof_values_strat(draw, schema=None, do_expl=False):
+def seqof_values_strategy(draw, schema=None, do_expl=False):
     if schema is None:
         schema = draw(sampled_from((Boolean(), Integer())))
     bound_min, bound_max = sorted(draw(sets(
@@ -4287,7 +4303,6 @@ class SeqOfMixing(object):
 
     def test_invalid_values_type(self):
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = Integer()
         with self.assertRaises(InvalidValueType) as err:
             SeqOf([Integer(123), Boolean(False), Integer(234)])
@@ -4300,21 +4315,21 @@ class SeqOfMixing(object):
     @given(booleans(), booleans(), binary(), binary())
     def test_comparison(self, value1, value2, tag1, tag2):
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = Boolean()
         obj1 = SeqOf([Boolean(value1)])
         obj2 = SeqOf([Boolean(value2)])
         self.assertEqual(obj1 == obj2, value1 == value2)
+        self.assertEqual(obj1 != obj2, value1 != value2)
         self.assertEqual(obj1 == list(obj2), value1 == value2)
         self.assertEqual(obj1 == tuple(obj2), value1 == value2)
         obj1 = SeqOf([Boolean(value1)], impl=tag1)
         obj2 = SeqOf([Boolean(value1)], impl=tag2)
         self.assertEqual(obj1 == obj2, tag1 == tag2)
+        self.assertEqual(obj1 != obj2, tag1 != tag2)
 
     @given(lists(booleans()))
     def test_iter(self, values):
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = Boolean()
         obj = SeqOf([Boolean(value) for value in values])
         self.assertEqual(len(obj), len(values))
@@ -4334,7 +4349,6 @@ class SeqOfMixing(object):
         ]
 
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = Integer()
         values = d.draw(permutations(ready + non_ready))
         seqof = SeqOf()
@@ -4356,7 +4370,6 @@ class SeqOfMixing(object):
 
     def test_spec_mismatch(self):
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = Integer()
         seqof = SeqOf()
         seqof.append(Integer(123))
@@ -4368,7 +4381,6 @@ class SeqOfMixing(object):
     @given(data_strategy())
     def test_bounds_satisfied(self, d):
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = Boolean()
         bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
         bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
@@ -4378,7 +4390,6 @@ class SeqOfMixing(object):
     @given(data_strategy())
     def test_bounds_unsatisfied(self, d):
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = Boolean()
         bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
         bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
@@ -4397,7 +4408,6 @@ class SeqOfMixing(object):
     @given(integers(min_value=1, max_value=10))
     def test_out_of_bounds(self, bound_max):
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = Integer()
             bounds = (0, bound_max)
         seqof = SeqOf()
@@ -4417,10 +4427,9 @@ class SeqOfMixing(object):
             default_initial,
             optional_initial,
             _decoded_initial,
-        ) = d.draw(seqof_values_strat())
+        ) = d.draw(seqof_values_strategy())
 
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = schema_initial
         obj_initial = SeqOf(
             value=value_initial,
@@ -4440,7 +4449,7 @@ class SeqOfMixing(object):
             default,
             optional,
             _decoded,
-        ) = d.draw(seqof_values_strat(
+        ) = d.draw(seqof_values_strategy(
             schema=schema_initial,
             do_expl=impl_initial is None,
         ))
@@ -4493,12 +4502,11 @@ class SeqOfMixing(object):
             bounds or bounds_initial or (0, float("+inf")),
         )
 
-    @given(seqof_values_strat())
+    @given(seqof_values_strategy())
     def test_copy(self, values):
         _schema, value, bounds, impl, expl, default, optional, _decoded = values
 
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = _schema
         obj = SeqOf(
             value=value,
@@ -4521,7 +4529,6 @@ class SeqOfMixing(object):
     )
     def test_stripped(self, values, tag_impl):
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = OctetString()
         obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
         with self.assertRaises(NotEnoughData):
@@ -4533,7 +4540,6 @@ class SeqOfMixing(object):
     )
     def test_stripped_expl(self, values, tag_expl):
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = OctetString()
         obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
         with self.assertRaises(NotEnoughData):
@@ -4581,7 +4587,7 @@ class SeqOfMixing(object):
 
     @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
     @given(
-        seqof_values_strat(schema=Integer()),
+        seqof_values_strategy(schema=Integer()),
         lists(integers().map(Integer)),
         integers(min_value=1).map(tag_ctxc),
         integers(min_value=0),
@@ -4590,7 +4596,6 @@ class SeqOfMixing(object):
         _, _, _, _, _, default, optional, _decoded = values
 
         class SeqOf(self.base_klass):
-            __slots__ = ()
             schema = Integer()
         obj = SeqOf(
             value=value,
@@ -4639,7 +4644,6 @@ class SeqOfMixing(object):
 
 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
     class SeqOf(SequenceOf):
-        __slots__ = ()
         schema = "whatever"
     base_klass = SeqOf
 
@@ -4650,7 +4654,6 @@ class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
 
 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
     class SeqOf(SetOf):
-        __slots__ = ()
         schema = "whatever"
     base_klass = SeqOf
 
@@ -4666,7 +4669,6 @@ class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
         values = [OctetString(v) for v in d.draw(lists(binary()))]
 
         class Seq(SetOf):
-            __slots__ = ()
             schema = OctetString()
         seq = Seq(values)
         seq_encoded = seq.encode()
@@ -4686,7 +4688,6 @@ class TestGoMarshalVectors(TestCase):
         self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
 
         class Seq(Sequence):
-            __slots__ = ()
             schema = (
                 ("erste", Integer()),
                 ("zweite", Integer(optional=True))
@@ -4701,7 +4702,6 @@ class TestGoMarshalVectors(TestCase):
         self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
 
         class NestedSeq(Sequence):
-            __slots__ = ()
             schema = (
                 ("nest", Seq()),
             )
@@ -4717,7 +4717,6 @@ class TestGoMarshalVectors(TestCase):
         )
 
         class Seq(Sequence):
-            __slots__ = ()
             schema = (
                 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
             )
@@ -4726,7 +4725,6 @@ class TestGoMarshalVectors(TestCase):
         self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
 
         class Seq(Sequence):
-            __slots__ = ()
             schema = (
                 ("erste", Integer(expl=tag_ctxc(5))),
             )
@@ -4735,7 +4733,6 @@ class TestGoMarshalVectors(TestCase):
         self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
 
         class Seq(Sequence):
-            __slots__ = ()
             schema = (
                 ("erste", Null(
                     impl=tag_encode(0, klass=TagClassContext),
@@ -4762,7 +4759,6 @@ class TestGoMarshalVectors(TestCase):
         )
 
         class Seq(Sequence):
-            __slots__ = ()
             schema = (
                 ("erste", GeneralizedTime()),
             )
@@ -4810,7 +4806,6 @@ class TestGoMarshalVectors(TestCase):
         self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
 
         class Seq(Sequence):
-            __slots__ = ()
             schema = (
                 ("erste", IA5String()),
             )
@@ -4819,7 +4814,6 @@ class TestGoMarshalVectors(TestCase):
         self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
 
         class Seq(Sequence):
-            __slots__ = ()
             schema = (
                 ("erste", PrintableString()),
             )
@@ -4830,7 +4824,6 @@ class TestGoMarshalVectors(TestCase):
         self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
 
         class Seq(Sequence):
-            __slots__ = ()
             schema = (
                 ("erste", Any(optional=True)),
                 ("zweite", Integer()),
@@ -4840,18 +4833,15 @@ class TestGoMarshalVectors(TestCase):
         self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
 
         class Seq(SetOf):
-            __slots__ = ()
             schema = Integer()
         seq = Seq()
         seq.append(Integer(10))
         self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
 
         class _SeqOf(SequenceOf):
-            __slots__ = ()
             schema = PrintableString()
 
         class SeqOf(SequenceOf):
-            __slots__ = ()
             schema = _SeqOf()
         _seqof = _SeqOf()
         _seqof.append(PrintableString("1"))
@@ -4860,7 +4850,6 @@ class TestGoMarshalVectors(TestCase):
         self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
 
         class Seq(Sequence):
-            __slots__ = ()
             schema = (
                 ("erste", Integer(default=1)),
             )
@@ -4885,3 +4874,173 @@ class TestPP(TestCase):
         pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
         self.assertNotIn(chosen_id, pp_console_row(pp))
         self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
+
+
+class TestAutoAddSlots(TestCase):
+    def runTest(self):
+        class Inher(Integer):
+            pass
+
+        with self.assertRaises(AttributeError):
+            inher = Inher()
+            inher.unexistent = "whatever"
+
+
+class TestOIDDefines(TestCase):
+    @given(data_strategy())
+    def runTest(self, d):
+        value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
+        value_name_chosen = d.draw(sampled_from(value_names))
+        oids = [
+            ObjectIdentifier(oid)
+            for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
+        ]
+        oid_chosen = d.draw(sampled_from(oids))
+        values = d.draw(lists(
+            integers(),
+            min_size=len(value_names),
+            max_size=len(value_names),
+        ))
+        _schema = [
+            ("type", ObjectIdentifier(defines=(value_name_chosen, {
+                oid: Integer() for oid in oids[:-1]
+            }))),
+        ]
+        for i, value_name in enumerate(value_names):
+            _schema.append((value_name, Any(expl=tag_ctxp(i))))
+
+        class Seq(Sequence):
+            schema = _schema
+        seq = Seq()
+        for value_name, value in zip(value_names, values):
+            seq[value_name] = Any(Integer(value).encode())
+        seq["type"] = oid_chosen
+        seq, _ = Seq().decode(seq.encode())
+        for value_name in value_names:
+            if value_name == value_name_chosen:
+                continue
+            self.assertIsNone(seq[value_name].defined)
+        if value_name_chosen in oids[:-1]:
+            self.assertIsNotNone(seq[value_name_chosen].defined)
+            self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
+            self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
+
+
+class TestDefinesByPath(TestCase):
+    def runTest(self):
+        class Seq(Sequence):
+            schema = (
+                ("type", ObjectIdentifier()),
+                ("value", OctetString(expl=tag_ctxc(123))),
+            )
+
+        class SeqInner(Sequence):
+            schema = (
+                ("typeInner", ObjectIdentifier()),
+                ("valueInner", Any()),
+            )
+
+        class PairValue(SetOf):
+            schema = Any()
+
+        class Pair(Sequence):
+            schema = (
+                ("type", ObjectIdentifier()),
+                ("value", PairValue()),
+            )
+
+        class Pairs(SequenceOf):
+            schema = Pair()
+
+        (
+            type_integered,
+            type_sequenced,
+            type_innered,
+            type_octet_stringed,
+        ) = [
+            ObjectIdentifier(oid)
+            for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
+        ]
+        seq_integered = Seq()
+        seq_integered["type"] = type_integered
+        seq_integered["value"] = OctetString(Integer(123).encode())
+        seq_integered_raw = seq_integered.encode()
+
+        pairs = Pairs()
+        pairs_input = (
+            (type_octet_stringed, OctetString(b"whatever")),
+            (type_integered, Integer(123)),
+            (type_octet_stringed, OctetString(b"whenever")),
+            (type_integered, Integer(234)),
+        )
+        for t, v in pairs_input:
+            pair = Pair()
+            pair["type"] = t
+            pair["value"] = PairValue((Any(v),))
+            pairs.append(pair)
+        seq_inner = SeqInner()
+        seq_inner["typeInner"] = type_innered
+        seq_inner["valueInner"] = Any(pairs)
+        seq_sequenced = Seq()
+        seq_sequenced["type"] = type_sequenced
+        seq_sequenced["value"] = OctetString(seq_inner.encode())
+        seq_sequenced_raw = seq_sequenced.encode()
+
+        defines_by_path = []
+        seq_integered, _ = Seq().decode(seq_integered_raw)
+        self.assertIsNone(seq_integered["value"].defined)
+        defines_by_path.append(
+            (("type",), ("value", {
+                type_integered: Integer(),
+                type_sequenced: SeqInner(),
+            }))
+        )
+        seq_integered, _ = Seq().decode(seq_integered_raw, defines_by_path=defines_by_path)
+        self.assertIsNotNone(seq_integered["value"].defined)
+        self.assertEqual(seq_integered["value"].defined[0], type_integered)
+        self.assertEqual(seq_integered["value"].defined[1], Integer(123))
+
+        seq_sequenced, _ = Seq().decode(seq_sequenced_raw, defines_by_path=defines_by_path)
+        self.assertIsNotNone(seq_sequenced["value"].defined)
+        self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
+        seq_inner = seq_sequenced["value"].defined[1]
+        self.assertIsNone(seq_inner["valueInner"].defined)
+
+        defines_by_path.append((
+            ("value", decode_path_defby(type_sequenced), "typeInner"),
+            ("valueInner", {type_innered: Pairs()}),
+        ))
+        seq_sequenced, _ = Seq().decode(seq_sequenced_raw, defines_by_path=defines_by_path)
+        self.assertIsNotNone(seq_sequenced["value"].defined)
+        self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
+        seq_inner = seq_sequenced["value"].defined[1]
+        self.assertIsNotNone(seq_inner["valueInner"].defined)
+        self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
+        pairs = seq_inner["valueInner"].defined[1]
+        for pair in pairs:
+            self.assertIsNone(pair["value"][0].defined)
+
+        defines_by_path.append((
+            (
+                "value",
+                decode_path_defby(type_sequenced),
+                "valueInner",
+                decode_path_defby(type_innered),
+                any,
+                "type",
+            ),
+            ("value", {
+                type_integered: Integer(),
+                type_octet_stringed: OctetString(),
+            }),
+        ))
+        seq_sequenced, _ = Seq().decode(seq_sequenced_raw, defines_by_path=defines_by_path)
+        self.assertIsNotNone(seq_sequenced["value"].defined)
+        self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
+        seq_inner = seq_sequenced["value"].defined[1]
+        self.assertIsNotNone(seq_inner["valueInner"].defined)
+        self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
+        pairs_got = seq_inner["valueInner"].defined[1]
+        for pair_input, pair_got in zip(pairs_input, pairs_got):
+            self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
+            self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])