bt2: Add `*ValueConst` classes and adapt tests
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Tue, 27 Aug 2019 16:14:45 +0000 (12:14 -0400)
committerFrancis Deslauriers <francis.deslauriers@efficios.com>
Tue, 10 Sep 2019 01:05:12 +0000 (21:05 -0400)
Split Python Value classes to mimic the type safety offered by the C
api. Const classes offer a read-only view of the data. Non-Const classes
subclass their respective Const classes.

Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Change-Id: I479db305a281063c7ee8aee2890c33c0b22e7153
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1983
Tested-by: jenkins <jenkins@lttng.org>
Reviewed-by: Simon Marchi <simon.marchi@efficios.com>
src/bindings/python/bt2/bt2/__init__.py
src/bindings/python/bt2/bt2/component.py
src/bindings/python/bt2/bt2/query_executor.py
src/bindings/python/bt2/bt2/value.py
tests/bindings/python/bt2/test_package.py
tests/bindings/python/bt2/test_query_executor.py
tests/bindings/python/bt2/test_value.py

index 137fc423507ea7030c4b3b47970de8ade99c7f8e..9ea77fb8f8e6121ed4f100a719dbebdeb977f9d0 100644 (file)
@@ -121,6 +121,14 @@ from bt2.value import RealValue
 from bt2.value import StringValue
 from bt2.value import ArrayValue
 from bt2.value import MapValue
+from bt2.value import _BoolValueConst
+from bt2.value import _IntegerValueConst
+from bt2.value import _UnsignedIntegerValueConst
+from bt2.value import _SignedIntegerValueConst
+from bt2.value import _RealValueConst
+from bt2.value import _StringValueConst
+from bt2.value import _ArrayValueConst
+from bt2.value import _MapValueConst
 from bt2.version import __version__
 
 
index a4f80c613d98fb6dfe5239e332c92e9ce23634d5..acc5b22c7b71e931a451cf6cc86629770ed8739b 100644 (file)
@@ -515,7 +515,7 @@ class _UserComponentType(type):
 
         # call user's __init__() method
         if params_ptr is not None:
-            params = bt2_value._create_from_ptr_and_get_ref(params_ptr)
+            params = bt2_value._create_from_const_ptr_and_get_ref(params_ptr)
         else:
             params = None
 
@@ -574,7 +574,7 @@ class _UserComponentType(type):
     def _bt_get_supported_mip_versions_from_native(cls, params_ptr, obj, log_level):
         # this can raise, but the native side checks the exception
         if params_ptr is not None:
-            params = bt2_value._create_from_ptr_and_get_ref(params_ptr)
+            params = bt2_value._create_from_const_ptr_and_get_ref(params_ptr)
         else:
             params = None
 
@@ -595,7 +595,7 @@ class _UserComponentType(type):
     def _bt_query_from_native(cls, priv_query_exec_ptr, object, params_ptr, method_obj):
         # this can raise, but the native side checks the exception
         if params_ptr is not None:
-            params = bt2_value._create_from_ptr_and_get_ref(params_ptr)
+            params = bt2_value._create_from_const_ptr_and_get_ref(params_ptr)
         else:
             params = None
 
index 8e51f82522d1149efc5540a32ed5953ed9598ec4..e23fc96f8f484731c0d76b5dfc12e7873e9898fc 100644 (file)
@@ -120,7 +120,7 @@ class QueryExecutor(object._SharedObject, _QueryExecutorCommon):
         status, result_ptr = native_bt.query_executor_query(self._ptr)
         utils._handle_func_status(status, 'cannot query component class')
         assert result_ptr is not None
-        return bt2_value._create_from_ptr(result_ptr)
+        return bt2_value._create_from_const_ptr(result_ptr)
 
 
 class _PrivateQueryExecutor(_QueryExecutorCommon):
index 3001502abb472600a8038d1d056c19197a8c374b..4c3afacbedc26dd855288ba188459137d43650c8 100644 (file)
@@ -29,7 +29,7 @@ import abc
 import bt2
 
 
-def _create_from_ptr(ptr):
+def _create_from_ptr_template(ptr, object_map):
     if ptr is None:
         return
 
@@ -41,15 +41,31 @@ def _create_from_ptr(ptr):
         return
 
     typeid = native_bt.value_get_type(ptr)
-    return _TYPE_TO_OBJ[typeid]._create_from_ptr(ptr)
+    return object_map[typeid]._create_from_ptr(ptr)
 
 
-def _create_from_ptr_and_get_ref(ptr):
+def _create_from_ptr(ptr):
+    return _create_from_ptr_template(ptr, _TYPE_TO_OBJ)
+
+
+def _create_from_const_ptr(ptr):
+    return _create_from_ptr_template(ptr, _TYPE_TO_CONST_OBJ)
+
+
+def _create_from_ptr_and_get_ref_template(ptr, object_map):
     if ptr is None or ptr == native_bt.value_null:
         return
 
     typeid = native_bt.value_get_type(ptr)
-    return _TYPE_TO_OBJ[typeid]._create_from_ptr_and_get_ref(ptr)
+    return object_map[typeid]._create_from_ptr_and_get_ref(ptr)
+
+
+def _create_from_ptr_and_get_ref(ptr):
+    return _create_from_ptr_and_get_ref_template(ptr, _TYPE_TO_OBJ)
+
+
+def _create_from_const_ptr_and_get_ref(ptr):
+    return _create_from_ptr_and_get_ref_template(ptr, _TYPE_TO_CONST_OBJ)
 
 
 def create_value(value):
@@ -83,9 +99,13 @@ def create_value(value):
     )
 
 
-class _Value(object._SharedObject, metaclass=abc.ABCMeta):
+class _ValueConst(object._SharedObject, metaclass=abc.ABCMeta):
     _get_ref = staticmethod(native_bt.value_get_ref)
     _put_ref = staticmethod(native_bt.value_put_ref)
+    _create_value_from_ptr = staticmethod(_create_from_const_ptr)
+    _create_value_from_ptr_and_get_ref = staticmethod(
+        _create_from_const_ptr_and_get_ref
+    )
 
     def __ne__(self, other):
         return not (self == other)
@@ -97,11 +117,16 @@ class _Value(object._SharedObject, metaclass=abc.ABCMeta):
             )
 
 
+class _Value(_ValueConst):
+    _create_value_from_ptr = staticmethod(_create_from_ptr)
+    _create_value_from_ptr_and_get_ref = staticmethod(_create_from_ptr_and_get_ref)
+
+
 @functools.total_ordering
-class _NumericValue(_Value):
+class _NumericValueConst(_ValueConst):
     @staticmethod
     def _extract_value(other):
-        if isinstance(other, BoolValue) or isinstance(other, bool):
+        if isinstance(other, _BoolValueConst) or isinstance(other, bool):
             return bool(other)
 
         if isinstance(other, numbers.Integral):
@@ -196,7 +221,11 @@ class _NumericValue(_Value):
         return self._extract_value(base) ** self._value
 
 
-class _IntegralValue(_NumericValue, numbers.Integral):
+class _NumericValue(_NumericValueConst, _Value):
+    pass
+
+
+class _IntegralValueConst(_NumericValueConst, numbers.Integral):
     def __lshift__(self, other):
         return self._value << self._extract_value(other)
 
@@ -231,11 +260,26 @@ class _IntegralValue(_NumericValue, numbers.Integral):
         return ~self._value
 
 
-class _RealValue(_NumericValue, numbers.Real):
+class _IntegralValue(_IntegralValueConst, _NumericValue):
     pass
 
 
-class BoolValue(_IntegralValue):
+class _BoolValueConst(_IntegralValueConst):
+    _NAME = 'Const boolean'
+
+    def __bool__(self):
+        return self._value
+
+    def __repr__(self):
+        return repr(self._value)
+
+    @property
+    def _value(self):
+        value = native_bt.value_bool_get(self._ptr)
+        return value != 0
+
+
+class BoolValue(_BoolValueConst, _IntegralValue):
     _NAME = 'Boolean'
 
     def __init__(self, value=None):
@@ -247,37 +291,33 @@ class BoolValue(_IntegralValue):
         self._check_create_status(ptr)
         super().__init__(ptr)
 
-    def __bool__(self):
-        return self._value
-
-    def __repr__(self):
-        return repr(self._value)
-
-    def _value_to_bool(self, value):
-        if isinstance(value, BoolValue):
+    @classmethod
+    def _value_to_bool(cls, value):
+        if isinstance(value, _BoolValueConst):
             value = value._value
 
         if not isinstance(value, bool):
             raise TypeError(
-                "'{}' object is not a 'bool' or 'BoolValue' object".format(
+                "'{}' object is not a 'bool', 'BoolValue', or '_BoolValueConst' object".format(
                     value.__class__
                 )
             )
 
         return value
 
-    @property
-    def _value(self):
-        value = native_bt.value_bool_get(self._ptr)
-        return value != 0
-
     def _set_value(self, value):
         native_bt.value_bool_set(self._ptr, self._value_to_bool(value))
 
     value = property(fset=_set_value)
 
 
-class _IntegerValue(_IntegralValue):
+class _IntegerValueConst(_IntegralValueConst):
+    @property
+    def _value(self):
+        return self._get_value(self._ptr)
+
+
+class _IntegerValue(_IntegerValueConst, _IntegralValue):
     def __init__(self, value=None):
         if value is None:
             ptr = self._create_default_value()
@@ -287,41 +327,56 @@ class _IntegerValue(_IntegralValue):
         self._check_create_status(ptr)
         super().__init__(ptr)
 
-    def _value_to_int(self, value):
+    @classmethod
+    def _value_to_int(cls, value):
         if not isinstance(value, numbers.Integral):
             raise TypeError('expecting an integral number object')
 
         value = int(value)
-        self._check_int_range(value)
+        cls._check_int_range(value)
         return value
 
-    @property
-    def _value(self):
-        return self._get_value(self._ptr)
-
     def _prop_set_value(self, value):
         self._set_value(self._ptr, self._value_to_int(value))
 
     value = property(fset=_prop_set_value)
 
 
-class UnsignedIntegerValue(_IntegerValue):
+class _UnsignedIntegerValueConst(_IntegerValueConst):
+    _NAME = 'Const unsigned integer'
+    _get_value = staticmethod(native_bt.value_integer_unsigned_get)
+
+
+class UnsignedIntegerValue(_UnsignedIntegerValueConst, _IntegerValue):
+    _NAME = 'Unsigned integer'
     _check_int_range = staticmethod(utils._check_uint64)
     _create_default_value = staticmethod(native_bt.value_integer_unsigned_create)
     _create_value = staticmethod(native_bt.value_integer_unsigned_create_init)
     _set_value = staticmethod(native_bt.value_integer_unsigned_set)
-    _get_value = staticmethod(native_bt.value_integer_unsigned_get)
 
 
-class SignedIntegerValue(_IntegerValue):
+class _SignedIntegerValueConst(_IntegerValueConst):
+    _NAME = 'Const signed integer'
+    _get_value = staticmethod(native_bt.value_integer_signed_get)
+
+
+class SignedIntegerValue(_SignedIntegerValueConst, _IntegerValue):
+    _NAME = 'Signed integer'
     _check_int_range = staticmethod(utils._check_int64)
     _create_default_value = staticmethod(native_bt.value_integer_signed_create)
     _create_value = staticmethod(native_bt.value_integer_signed_create_init)
     _set_value = staticmethod(native_bt.value_integer_signed_set)
-    _get_value = staticmethod(native_bt.value_integer_signed_get)
 
 
-class RealValue(_RealValue):
+class _RealValueConst(_NumericValueConst, numbers.Real):
+    _NAME = 'Const real number'
+
+    @property
+    def _value(self):
+        return native_bt.value_real_get(self._ptr)
+
+
+class RealValue(_RealValueConst, _NumericValue):
     _NAME = 'Real number'
 
     def __init__(self, value=None):
@@ -334,16 +389,13 @@ class RealValue(_RealValue):
         self._check_create_status(ptr)
         super().__init__(ptr)
 
-    def _value_to_float(self, value):
+    @classmethod
+    def _value_to_float(cls, value):
         if not isinstance(value, numbers.Real):
             raise TypeError("expecting a real number object")
 
         return float(value)
 
-    @property
-    def _value(self):
-        return native_bt.value_real_get(self._ptr)
-
     def _set_value(self, value):
         native_bt.value_real_set(self._ptr, self._value_to_float(value))
 
@@ -351,20 +403,12 @@ class RealValue(_RealValue):
 
 
 @functools.total_ordering
-class StringValue(collections.abc.Sequence, _Value):
-    _NAME = 'String'
+class _StringValueConst(collections.abc.Sequence, _Value):
+    _NAME = 'Const string'
 
-    def __init__(self, value=None):
-        if value is None:
-            ptr = native_bt.value_string_create()
-        else:
-            ptr = native_bt.value_string_create_init(self._value_to_str(value))
-
-        self._check_create_status(ptr)
-        super().__init__(ptr)
-
-    def _value_to_str(self, value):
-        if isinstance(value, self.__class__):
+    @classmethod
+    def _value_to_str(cls, value):
+        if isinstance(value, _StringValueConst):
             value = value._value
 
         utils._check_str(value)
@@ -374,12 +418,6 @@ class StringValue(collections.abc.Sequence, _Value):
     def _value(self):
         return native_bt.value_string_get(self._ptr)
 
-    def _set_value(self, value):
-        status = native_bt.value_string_set(self._ptr, self._value_to_str(value))
-        utils._handle_func_status(status)
-
-    value = property(fset=_set_value)
-
     def __eq__(self, other):
         try:
             return self._value == self._value_to_str(other)
@@ -407,6 +445,25 @@ class StringValue(collections.abc.Sequence, _Value):
     def __contains__(self, item):
         return self._value_to_str(item) in self._value
 
+
+class StringValue(_StringValueConst, _Value):
+    _NAME = 'String'
+
+    def __init__(self, value=None):
+        if value is None:
+            ptr = native_bt.value_string_create()
+        else:
+            ptr = native_bt.value_string_create_init(self._value_to_str(value))
+
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+    def _set_value(self, value):
+        status = native_bt.value_string_set(self._ptr, self._value_to_str(value))
+        utils._handle_func_status(status)
+
+    value = property(fset=_set_value)
+
     def __iadd__(self, value):
         curvalue = self._value
         curvalue += self._value_to_str(value)
@@ -414,27 +471,22 @@ class StringValue(collections.abc.Sequence, _Value):
         return self
 
 
-class _Container:
+class _ContainerConst:
     def __bool__(self):
         return len(self) != 0
 
+
+class _Container(_ContainerConst):
     def __delitem__(self, index):
         raise NotImplementedError
 
 
-class ArrayValue(_Container, collections.abc.MutableSequence, _Value):
-    _NAME = 'Array'
-
-    def __init__(self, value=None):
-        ptr = native_bt.value_array_create()
-        self._check_create_status(ptr)
-        super().__init__(ptr)
-
-        # Python will raise a TypeError if there's anything wrong with
-        # the iterable protocol.
-        if value is not None:
-            for elem in value:
-                self.append(elem)
+class _ArrayValueConst(_ContainerConst, collections.abc.Sequence, _ValueConst):
+    _NAME = 'Const array'
+    _borrow_element_by_index = staticmethod(
+        native_bt.value_array_borrow_element_by_index_const
+    )
+    _is_const = True
 
     def __eq__(self, other):
         if not isinstance(other, collections.abc.Sequence):
@@ -471,9 +523,30 @@ class ArrayValue(_Container, collections.abc.MutableSequence, _Value):
 
     def __getitem__(self, index):
         self._check_index(index)
-        ptr = native_bt.value_array_borrow_element_by_index(self._ptr, index)
+        ptr = self._borrow_element_by_index(self._ptr, index)
         assert ptr
-        return _create_from_ptr_and_get_ref(ptr)
+        return self._create_value_from_ptr_and_get_ref(ptr)
+
+    def __repr__(self):
+        return '[{}]'.format(', '.join([repr(v) for v in self]))
+
+
+class ArrayValue(_ArrayValueConst, _Container, collections.abc.MutableSequence, _Value):
+    _NAME = 'Array'
+    _borrow_element_by_index = staticmethod(
+        native_bt.value_array_borrow_element_by_index
+    )
+
+    def __init__(self, value=None):
+        ptr = native_bt.value_array_create()
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+        # Python will raise a TypeError if there's anything wrong with
+        # the iterable protocol.
+        if value is not None:
+            for elem in value:
+                self.append(elem)
 
     def __setitem__(self, index, value):
         self._check_index(index)
@@ -506,9 +579,6 @@ class ArrayValue(_Container, collections.abc.MutableSequence, _Value):
 
         return self
 
-    def __repr__(self):
-        return '[{}]'.format(', '.join([repr(v) for v in self]))
-
     def insert(self, value):
         raise NotImplementedError
 
@@ -533,19 +603,9 @@ class _MapValueKeyIterator(collections.abc.Iterator):
         return str(key)
 
 
-class MapValue(_Container, collections.abc.MutableMapping, _Value):
-    _NAME = 'Map'
-
-    def __init__(self, value=None):
-        ptr = native_bt.value_map_create()
-        self._check_create_status(ptr)
-        super().__init__(ptr)
-
-        # Python will raise a TypeError if there's anything wrong with
-        # the iterable/mapping protocol.
-        if value is not None:
-            for key, elem in value.items():
-                self[key] = elem
+class _MapValueConst(_ContainerConst, collections.abc.Mapping, _ValueConst):
+    _NAME = 'Const map'
+    _borrow_entry_value_ptr = staticmethod(native_bt.value_map_borrow_entry_value_const)
 
     def __ne__(self, other):
         return _Value.__ne__(self, other)
@@ -585,13 +645,33 @@ class MapValue(_Container, collections.abc.MutableMapping, _Value):
 
     def __getitem__(self, key):
         self._check_key(key)
-        ptr = native_bt.value_map_borrow_entry_value(self._ptr, key)
+        ptr = self._borrow_entry_value_ptr(self._ptr, key)
         assert ptr
-        return _create_from_ptr_and_get_ref(ptr)
+        return self._create_value_from_ptr_and_get_ref(ptr)
 
     def __iter__(self):
         return _MapValueKeyIterator(self)
 
+    def __repr__(self):
+        items = ['{}: {}'.format(repr(k), repr(v)) for k, v in self.items()]
+        return '{{{}}}'.format(', '.join(items))
+
+
+class MapValue(_MapValueConst, _Container, collections.abc.MutableMapping, _Value):
+    _NAME = 'Map'
+    _borrow_entry_value_ptr = staticmethod(native_bt.value_map_borrow_entry_value)
+
+    def __init__(self, value=None):
+        ptr = native_bt.value_map_create()
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+        # Python will raise a TypeError if there's anything wrong with
+        # the iterable/mapping protocol.
+        if value is not None:
+            for key, elem in value.items():
+                self[key] = elem
+
     def __setitem__(self, key, value):
         self._check_key_type(key)
         value = create_value(value)
@@ -604,10 +684,6 @@ class MapValue(_Container, collections.abc.MutableMapping, _Value):
         status = native_bt.value_map_insert_entry(self._ptr, key, ptr)
         utils._handle_func_status(status)
 
-    def __repr__(self):
-        items = ['{}: {}'.format(repr(k), repr(v)) for k, v in self.items()]
-        return '{{{}}}'.format(', '.join(items))
-
 
 _TYPE_TO_OBJ = {
     native_bt.VALUE_TYPE_BOOL: BoolValue,
@@ -618,3 +694,13 @@ _TYPE_TO_OBJ = {
     native_bt.VALUE_TYPE_ARRAY: ArrayValue,
     native_bt.VALUE_TYPE_MAP: MapValue,
 }
+
+_TYPE_TO_CONST_OBJ = {
+    native_bt.VALUE_TYPE_BOOL: _BoolValueConst,
+    native_bt.VALUE_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerValueConst,
+    native_bt.VALUE_TYPE_SIGNED_INTEGER: _SignedIntegerValueConst,
+    native_bt.VALUE_TYPE_REAL: _RealValueConst,
+    native_bt.VALUE_TYPE_STRING: _StringValueConst,
+    native_bt.VALUE_TYPE_ARRAY: _ArrayValueConst,
+    native_bt.VALUE_TYPE_MAP: _MapValueConst,
+}
index 71e792a4fe33ca1405e1e6d2273054c45e1e8b83..21ffe08446098a6e1fb3675c3eff5c6d4615166e 100644 (file)
@@ -318,5 +318,29 @@ class PackageTestCase(unittest.TestCase):
     def test_has_MapValue(self):
         self._assert_in_bt2('MapValue')
 
+    def test_has_BoolValueConst(self):
+        self._assert_in_bt2('_BoolValueConst')
+
+    def test_has__IntegerValueConst(self):
+        self._assert_in_bt2('_IntegerValueConst')
+
+    def test_has_UnsignedIntegerValueConst(self):
+        self._assert_in_bt2('_UnsignedIntegerValueConst')
+
+    def test_has_SignedIntegerValueConst(self):
+        self._assert_in_bt2('_SignedIntegerValueConst')
+
+    def test_has_RealValueConst(self):
+        self._assert_in_bt2('_RealValueConst')
+
+    def test_has_StringValueConst(self):
+        self._assert_in_bt2('_StringValueConst')
+
+    def test_has_ArrayValueConst(self):
+        self._assert_in_bt2('_ArrayValueConst')
+
+    def test_has_MapValueConst(self):
+        self._assert_in_bt2('_MapValueConst')
+
     def test_has___version__(self):
         self._assert_in_bt2('__version__')
index 1ed63f1a4749c9bbf682404cb867ae7722addf8a..26e554615924d179a4ff96e4265a56470955acc1 100644 (file)
@@ -41,6 +41,8 @@ class QueryExecutorTestCase(unittest.TestCase):
         }
 
         res = bt2.QueryExecutor(MySink, 'obj', params).query()
+        self.assertIs(type(res), bt2._MapValueConst)
+        self.assertIs(type(res['bt2']), bt2._StringValueConst)
         self.assertEqual(query_params, params)
         self.assertEqual(res, {'null': None, 'bt2': 'BT2'})
         del query_params
index fea749fc5b9234975d7f1abb7bb738ff85ccc747..b8ecfe55e685b72dd474a6e86967f60c9bf3a5ad 100644 (file)
@@ -1086,6 +1086,20 @@ class CreateValueFuncTestCase(unittest.TestCase):
             bt2.create_value(a)
 
 
+def _create_const_value(value):
+    class MySink(bt2._UserSinkComponent):
+        def _user_consume(self):
+            pass
+
+        @classmethod
+        def _user_query(cls, priv_query_exec, obj, params, method_obj):
+            nonlocal value
+            return {'my_value': value}
+
+    res = bt2.QueryExecutor(MySink, 'obj', None).query()
+    return res['my_value']
+
+
 class BoolValueTestCase(_TestNumericValue, unittest.TestCase):
     def setUp(self):
         self._f = bt2.BoolValue(False)
@@ -1446,6 +1460,7 @@ class StringValueTestCase(_TestCopySimple, unittest.TestCase):
     def setUp(self):
         self._def_value = 'Hello, World!'
         self._def = bt2.StringValue(self._def_value)
+        self._def_const = _create_const_value(self._def_value)
         self._def_new_value = 'Yes!'
 
     def tearDown(self):
@@ -1496,7 +1511,10 @@ class StringValueTestCase(_TestCopySimple, unittest.TestCase):
     def test_eq(self):
         self.assertEqual(self._def, self._def_value)
 
-    def test_eq(self):
+    def test_const_eq(self):
+        self.assertEqual(self._def_const, self._def_value)
+
+    def test_eq_raw(self):
         self.assertNotEqual(self._def, 23)
 
     def test_lt_vstring(self):
@@ -1556,12 +1574,22 @@ class StringValueTestCase(_TestCopySimple, unittest.TestCase):
     def test_getitem(self):
         self.assertEqual(self._def[5], self._def_value[5])
 
-    def test_append_str(self):
+    def test_const_getitem(self):
+        self.assertEqual(self._def_const[5], self._def_value[5])
+
+    def test_iadd_str(self):
         to_append = 'meow meow meow'
         self._def += to_append
         self._def_value += to_append
         self.assertEqual(self._def, self._def_value)
 
+    def test_const_iadd_str(self):
+        to_append = 'meow meow meow'
+        with self.assertRaises(TypeError):
+            self._def_const += to_append
+
+        self.assertEqual(self._def_const, self._def_value)
+
     def test_append_vstr(self):
         to_append = 'meow meow meow'
         self._def += bt2.create_value(to_append)
@@ -1573,6 +1601,7 @@ class ArrayValueTestCase(_TestCopySimple, unittest.TestCase):
     def setUp(self):
         self._def_value = [None, False, True, -23, 0, 42, -42.4, 23.17, 'yes']
         self._def = bt2.ArrayValue(copy.deepcopy(self._def_value))
+        self._def_const = _create_const_value(copy.deepcopy(self._def_value))
 
     def tearDown(self):
         del self._def
@@ -1619,9 +1648,16 @@ class ArrayValueTestCase(_TestCopySimple, unittest.TestCase):
     def test_eq_int(self):
         self.assertNotEqual(self._def, 23)
 
+    def test_const_eq(self):
+        a1 = _create_const_value([1, 2, 3])
+        a2 = [1, 2, 3]
+        self.assertEqual(a1, a2)
+
     def test_eq_diff_len(self):
         a1 = bt2.create_value([1, 2, 3])
         a2 = bt2.create_value([1, 2])
+        self.assertIs(type(a1), bt2.ArrayValue)
+        self.assertIs(type(a2), bt2.ArrayValue)
         self.assertNotEqual(a1, a2)
 
     def test_eq_diff_content_same_len(self):
@@ -1655,6 +1691,10 @@ class ArrayValueTestCase(_TestCopySimple, unittest.TestCase):
         self._def[2] = None
         self.assertIsNone(self._def[2])
 
+    def test_setitem_none(self):
+        self._def[2] = None
+        self.assertIsNone(self._def[2])
+
     def test_setitem_index_wrong_type(self):
         with self._assert_type_error():
             self._def['yes'] = 23
@@ -1667,6 +1707,10 @@ class ArrayValueTestCase(_TestCopySimple, unittest.TestCase):
         with self.assertRaises(IndexError):
             self._def[len(self._def)] = 23
 
+    def test_const_setitem(self):
+        with self.assertRaises(TypeError):
+            self._def_const[2] = 19
+
     def test_append_none(self):
         self._def.append(None)
         self.assertIsNone(self._def[len(self._def) - 1])
@@ -1676,6 +1720,10 @@ class ArrayValueTestCase(_TestCopySimple, unittest.TestCase):
         self._def.append(raw)
         self.assertEqual(self._def[len(self._def) - 1], raw)
 
+    def test_const_append(self):
+        with self.assertRaises(AttributeError):
+            self._def_const.append(12194)
+
     def test_append_vint(self):
         raw = 145
         self._def.append(bt2.create_value(raw))
@@ -1695,6 +1743,10 @@ class ArrayValueTestCase(_TestCopySimple, unittest.TestCase):
         self.assertEqual(self._def[len(self._def) - 2], raw[1])
         self.assertEqual(self._def[len(self._def) - 1], raw[2])
 
+    def test_const_iadd(self):
+        with self.assertRaises(TypeError):
+            self._def_const += 12194
+
     def test_iadd_unknown(self):
         class A:
             pass
@@ -1713,6 +1765,31 @@ class ArrayValueTestCase(_TestCopySimple, unittest.TestCase):
         for velem, elem in zip(self._def, self._def_value):
             self.assertEqual(velem, elem)
 
+    def test_const_iter(self):
+        for velem, elem in zip(self._def_const, self._def_value):
+            self.assertEqual(velem, elem)
+
+    def test_const_get_item(self):
+        item1 = self._def_const[0]
+        item2 = self._def_const[2]
+        item3 = self._def_const[5]
+        item4 = self._def_const[7]
+        item5 = self._def_const[8]
+
+        self.assertEqual(item1, None)
+
+        self.assertIs(type(item2), bt2._BoolValueConst)
+        self.assertEqual(item2, True)
+
+        self.assertIs(type(item3), bt2._SignedIntegerValueConst)
+        self.assertEqual(item3, 42)
+
+        self.assertIs(type(item4), bt2._RealValueConst)
+        self.assertEqual(item4, 23.17)
+
+        self.assertIs(type(item5), bt2._StringValueConst)
+        self.assertEqual(item5, 'yes')
+
 
 class MapValueTestCase(_TestCopySimple, unittest.TestCase):
     def setUp(self):
@@ -1728,6 +1805,7 @@ class MapValueTestCase(_TestCopySimple, unittest.TestCase):
             'str': 'yes',
         }
         self._def = bt2.MapValue(copy.deepcopy(self._def_value))
+        self._def_const = _create_const_value(self._def_value)
 
     def tearDown(self):
         del self._def
@@ -1763,6 +1841,11 @@ class MapValueTestCase(_TestCopySimple, unittest.TestCase):
     def test_len(self):
         self.assertEqual(len(self._def), len(self._def_value))
 
+    def test_const_eq(self):
+        a1 = _create_const_value({'a': 1, 'b': 2, 'c': 3})
+        a2 = {'a': 1, 'b': 2, 'c': 3}
+        self.assertEqual(a1, a2)
+
     def test_eq_int(self):
         self.assertNotEqual(self._def, 23)
 
@@ -1771,16 +1854,31 @@ class MapValueTestCase(_TestCopySimple, unittest.TestCase):
         a2 = bt2.create_value({'a': 1, 'b': 2})
         self.assertNotEqual(a1, a2)
 
+    def test_const_eq_diff_len(self):
+        a1 = _create_const_value({'a': 1, 'b': 2, 'c': 3})
+        a2 = _create_const_value({'a': 1, 'b': 2})
+        self.assertNotEqual(a1, a2)
+
     def test_eq_diff_content_same_len(self):
         a1 = bt2.create_value({'a': 1, 'b': 2, 'c': 3})
         a2 = bt2.create_value({'a': 4, 'b': 2, 'c': 3})
         self.assertNotEqual(a1, a2)
 
+    def test_const_eq_diff_content_same_len(self):
+        a1 = _create_const_value({'a': 1, 'b': 2, 'c': 3})
+        a2 = _create_const_value({'a': 4, 'b': 2, 'c': 3})
+        self.assertNotEqual(a1, a2)
+
     def test_eq_same_content_diff_keys(self):
         a1 = bt2.create_value({'a': 1, 'b': 2, 'c': 3})
         a2 = bt2.create_value({'a': 1, 'k': 2, 'c': 3})
         self.assertNotEqual(a1, a2)
 
+    def test_const_eq_same_content_diff_keys(self):
+        a1 = _create_const_value({'a': 1, 'b': 2, 'c': 3})
+        a2 = _create_const_value({'a': 1, 'k': 2, 'c': 3})
+        self.assertNotEqual(a1, a2)
+
     def test_eq_same_content_same_len(self):
         raw = {'3': 3, 'True': True, 'array': [1, 2.5, None, {'a': 17.6, 'b': None}]}
         a1 = bt2.MapValue(raw)
@@ -1788,11 +1886,22 @@ class MapValueTestCase(_TestCopySimple, unittest.TestCase):
         self.assertEqual(a1, a2)
         self.assertEqual(a1, raw)
 
+    def test_const_eq_same_content_same_len(self):
+        raw = {'3': 3, 'True': True, 'array': [1, 2.5, None, {'a': 17.6, 'b': None}]}
+        a1 = _create_const_value(raw)
+        a2 = _create_const_value(copy.deepcopy(raw))
+        self.assertEqual(a1, a2)
+        self.assertEqual(a1, raw)
+
     def test_setitem_int(self):
         raw = 19
         self._def['pos-int'] = raw
         self.assertEqual(self._def['pos-int'], raw)
 
+    def test_const_setitem_int(self):
+        with self.assertRaises(TypeError):
+            self._def_const['pos-int'] = 19
+
     def test_setitem_vint(self):
         raw = 19
         self._def['pos-int'] = bt2.create_value(raw)
@@ -1817,6 +1926,37 @@ class MapValueTestCase(_TestCopySimple, unittest.TestCase):
             val = self._def_value[vkey]
             self.assertEqual(vval, val)
 
+    def test_const_iter(self):
+        for vkey, vval in self._def_const.items():
+            val = self._def_value[vkey]
+            self.assertEqual(vval, val)
+
+    def test_get_item(self):
+        i = self._def['pos-float']
+        self.assertIs(type(i), bt2.RealValue)
+        self.assertEqual(i, 23.17)
+
+    def test_const_get_item(self):
+        item1 = self._def_const['none']
+        item2 = self._def_const['true']
+        item3 = self._def_const['pos-int']
+        item4 = self._def_const['pos-float']
+        item5 = self._def_const['str']
+
+        self.assertEqual(item1, None)
+
+        self.assertIs(type(item2), bt2._BoolValueConst)
+        self.assertEqual(item2, True)
+
+        self.assertIs(type(item3), bt2._SignedIntegerValueConst)
+        self.assertEqual(item3, 42)
+
+        self.assertIs(type(item4), bt2._RealValueConst)
+        self.assertEqual(item4, 23.17)
+
+        self.assertIs(type(item5), bt2._StringValueConst)
+        self.assertEqual(item5, 'yes')
+
     def test_getitem_wrong_key(self):
         with self.assertRaises(KeyError):
             self._def['kilojoule']
This page took 0.036771 seconds and 4 git commands to generate.