diff options
author | TizenOpenSource <tizenopensrc@samsung.com> | 2023-12-08 13:16:12 +0900 |
---|---|---|
committer | TizenOpenSource <tizenopensrc@samsung.com> | 2023-12-08 13:16:12 +0900 |
commit | 454aa52f950f2348756dfffc9c26fb74d4aa3bef (patch) | |
tree | 4e8be3f8c8218dbafe65e22dfc73e9351c1d5bbb /tests/test_gobject.py | |
parent | f3eae5a895fc60cb99c0c366bdd011018ce3bc7b (diff) | |
download | pygobject2-454aa52f950f2348756dfffc9c26fb74d4aa3bef.tar.gz pygobject2-454aa52f950f2348756dfffc9c26fb74d4aa3bef.tar.bz2 pygobject2-454aa52f950f2348756dfffc9c26fb74d4aa3bef.zip |
Imported Upstream version 3.46.0upstream/3.46.0
Diffstat (limited to 'tests/test_gobject.py')
-rw-r--r-- | tests/test_gobject.py | 305 |
1 files changed, 252 insertions, 53 deletions
diff --git a/tests/test_gobject.py b/tests/test_gobject.py index 57d3822..fbc3bb7 100644 --- a/tests/test_gobject.py +++ b/tests/test_gobject.py @@ -4,24 +4,101 @@ import sys import gc import unittest import warnings +import weakref +import platform -from gi.repository import GObject, GLib +import pytest + +from gi.repository import GObject, GLib, Gio from gi import PyGIDeprecationWarning from gi.module import get_introspection_module -from gi._gobject import _gobject +from gi import _gi import testhelper +from .helper import capture_glib_deprecation_warnings + + +@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="crashes") +def test_gobject_weak_ref(): + + called = [] + + def callback(*args): + called.extend(args) + + # object gets finalized + obj = GObject.Object() + obj.weak_ref(callback, 1) + del obj + gc.collect() + gc.collect() + assert called == [1] + del called[:] + + # wrapper gets finalized first + obj = GObject.Object() + pyref = weakref.ref(obj, lambda x: callback(-2)) + value = GObject.Value(GObject.Object, obj) + ref = obj.weak_ref(callback, 2) + del obj + gc.collect() + assert called == [-2] + del pyref + value.unset() + gc.collect() + assert called == [-2, 2] + del called[:] + + # weakref gets unregistered first + obj = GObject.Object() + ref = obj.weak_ref(callback, 3) + ref.unref() + del obj + gc.collect() + assert not called + + # weakref gets GCed + obj = GObject.Object() + obj.weak_ref(callback, 4) + gc.collect() + del obj + assert called == [4] class TestGObjectAPI(unittest.TestCase): + + def test_run_dispose(self): + class TestObject(GObject.GObject): + int_prop = GObject.Property(default=0, type=int) + + obj = TestObject() + called = [] + + def on_notify(*args): + called.append(args) + + obj.connect('notify::int-prop', on_notify) + obj.notify("int-prop") + obj.notify("int-prop") + # after this everything should be disconnected + obj.run_dispose() + obj.notify("int-prop") + obj.notify("int-prop") + assert len(called) == 2 + + def test_call_method_uninitialized_instance(self): + obj = GObject.Object.__new__(GObject.Object) + with self.assertRaisesRegex(RuntimeError, '.*is not initialized'): + obj.notify("foo") + def test_gobject_inheritance(self): # GObject.Object is a class hierarchy as follows: # overrides.Object -> introspection.Object -> static.GObject GIObjectModule = get_introspection_module('GObject') self.assertTrue(issubclass(GObject.Object, GIObjectModule.Object)) - self.assertTrue(issubclass(GIObjectModule.Object, _gobject.GObject)) + self.assertTrue(issubclass(GIObjectModule.Object, _gi.GObject)) - self.assertEqual(_gobject.GObject.__gtype__, GObject.TYPE_OBJECT) + self.assertEqual(_gi.GObject.__gtype__, GObject.TYPE_OBJECT) self.assertEqual(GIObjectModule.Object.__gtype__, GObject.TYPE_OBJECT) self.assertEqual(GObject.Object.__gtype__, GObject.TYPE_OBJECT) @@ -58,17 +135,20 @@ class TestGObjectAPI(unittest.TestCase): self.assertLess(GObject.PRIORITY_HIGH, GObject.PRIORITY_DEFAULT) def test_min_max_int(self): - self.assertEqual(GObject.G_MAXINT16, 2 ** 15 - 1) - self.assertEqual(GObject.G_MININT16, -2 ** 15) - self.assertEqual(GObject.G_MAXUINT16, 2 ** 16 - 1) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', PyGIDeprecationWarning) - self.assertEqual(GObject.G_MAXINT32, 2 ** 31 - 1) - self.assertEqual(GObject.G_MININT32, -2 ** 31) - self.assertEqual(GObject.G_MAXUINT32, 2 ** 32 - 1) + self.assertEqual(GObject.G_MAXINT16, 2 ** 15 - 1) + self.assertEqual(GObject.G_MININT16, -2 ** 15) + self.assertEqual(GObject.G_MAXUINT16, 2 ** 16 - 1) - self.assertEqual(GObject.G_MAXINT64, 2 ** 63 - 1) - self.assertEqual(GObject.G_MININT64, -2 ** 63) - self.assertEqual(GObject.G_MAXUINT64, 2 ** 64 - 1) + self.assertEqual(GObject.G_MAXINT32, 2 ** 31 - 1) + self.assertEqual(GObject.G_MININT32, -2 ** 31) + self.assertEqual(GObject.G_MAXUINT32, 2 ** 32 - 1) + + self.assertEqual(GObject.G_MAXINT64, 2 ** 63 - 1) + self.assertEqual(GObject.G_MININT64, -2 ** 63) + self.assertEqual(GObject.G_MAXUINT64, 2 ** 64 - 1) class TestReferenceCounting(unittest.TestCase): @@ -233,19 +313,23 @@ class TestPythonReferenceCounting(unittest.TestCase): def test_new_instance_has_two_refs(self): obj = GObject.GObject() - self.assertEqual(sys.getrefcount(obj), 2) + if hasattr(sys, "getrefcount"): + self.assertEqual(sys.getrefcount(obj), 2) def test_new_instance_has_two_refs_using_gobject_new(self): obj = GObject.new(GObject.GObject) - self.assertEqual(sys.getrefcount(obj), 2) + if hasattr(sys, "getrefcount"): + self.assertEqual(sys.getrefcount(obj), 2) def test_new_subclass_instance_has_two_refs(self): obj = A() - self.assertEqual(sys.getrefcount(obj), 2) + if hasattr(sys, "getrefcount"): + self.assertEqual(sys.getrefcount(obj), 2) def test_new_subclass_instance_has_two_refs_using_gobject_new(self): obj = GObject.new(A) - self.assertEqual(sys.getrefcount(obj), 2) + if hasattr(sys, "getrefcount"): + self.assertEqual(sys.getrefcount(obj), 2) class TestContextManagers(unittest.TestCase): @@ -270,14 +354,16 @@ class TestContextManagers(unittest.TestCase): self.assertEqual(self.tracking, [1, 2]) self.assertEqual(self.obj.__grefcount__, 1) - pyref_count = sys.getrefcount(self.obj) + if hasattr(sys, "getrefcount"): + pyref_count = sys.getrefcount(self.obj) # Using the context manager the tracking list should not be affected. # The GObject reference count should stay the same and the python # object ref-count should go up. with self.obj.freeze_notify(): self.assertEqual(self.obj.__grefcount__, 1) - self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1) + if hasattr(sys, "getrefcount"): + self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1) self.obj.props.prop = 3 self.assertEqual(self.obj.props.prop, 3) self.assertEqual(self.tracking, [1, 2]) @@ -289,7 +375,8 @@ class TestContextManagers(unittest.TestCase): self.assertEqual(self.obj.props.prop, 3) self.assertEqual(self.tracking, [1, 2, 3]) self.assertEqual(self.obj.__grefcount__, 1) - self.assertEqual(sys.getrefcount(self.obj), pyref_count) + if hasattr(sys, "getrefcount"): + self.assertEqual(sys.getrefcount(self.obj), pyref_count) def test_handler_block_context(self): # Verify prop tracking list @@ -300,14 +387,16 @@ class TestContextManagers(unittest.TestCase): self.assertEqual(self.tracking, [1, 2]) self.assertEqual(self.obj.__grefcount__, 1) - pyref_count = sys.getrefcount(self.obj) + if hasattr(sys, "getrefcount"): + pyref_count = sys.getrefcount(self.obj) # Using the context manager the tracking list should not be affected. # The GObject reference count should stay the same and the python # object ref-count should go up. with self.obj.handler_block(self.handler): self.assertEqual(self.obj.__grefcount__, 1) - self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1) + if hasattr(sys, "getrefcount"): + self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1) self.obj.props.prop = 3 self.assertEqual(self.obj.props.prop, 3) self.assertEqual(self.tracking, [1, 2]) @@ -319,7 +408,8 @@ class TestContextManagers(unittest.TestCase): self.assertEqual(self.obj.props.prop, 3) self.assertEqual(self.tracking, [1, 2]) self.assertEqual(self.obj.__grefcount__, 1) - self.assertEqual(sys.getrefcount(self.obj), pyref_count) + if hasattr(sys, "getrefcount"): + self.assertEqual(sys.getrefcount(self.obj), pyref_count) def test_freeze_notify_context_nested(self): self.assertEqual(self.tracking, []) @@ -415,6 +505,8 @@ class TestContextManagers(unittest.TestCase): self.assertEqual(self.tracking, [2]) +@unittest.skipUnless(hasattr(GObject.Binding, 'unbind'), + 'Requires newer GLib which has g_binding_unbind') class TestPropertyBindings(unittest.TestCase): class TestObject(GObject.GObject): int_prop = GObject.Property(default=0, type=int) @@ -438,6 +530,14 @@ class TestPropertyBindings(unittest.TestCase): self.assertEqual(self.source.int_prop, 1) self.assertEqual(self.target.int_prop, 2) + def test_call_binding(self): + binding = self.source.bind_property('int_prop', self.target, 'int_prop', + GObject.BindingFlags.DEFAULT) + with capture_glib_deprecation_warnings() as warn: + result = binding() + assert len(warn) + assert result is binding + def test_bidirectional_binding(self): binding = self.source.bind_property('int_prop', self.target, 'int_prop', GObject.BindingFlags.BIDIRECTIONAL) @@ -500,17 +600,19 @@ class TestPropertyBindings(unittest.TestCase): self.assertEqual(user_data, test_data) return value // 2 - test_data_ref_count = sys.getrefcount(test_data) - transform_to_ref_count = sys.getrefcount(transform_to) - transform_from_ref_count = sys.getrefcount(transform_from) + if hasattr(sys, "getrefcount"): + test_data_ref_count = sys.getrefcount(test_data) + transform_to_ref_count = sys.getrefcount(transform_to) + transform_from_ref_count = sys.getrefcount(transform_from) # bidirectional bindings binding = self.source.bind_property('int_prop', self.target, 'int_prop', GObject.BindingFlags.BIDIRECTIONAL, transform_to, transform_from, test_data) binding = binding # PyFlakes - binding_ref_count = sys.getrefcount(binding()) - binding_gref_count = binding().__grefcount__ + if hasattr(sys, "getrefcount"): + binding_ref_count = sys.getrefcount(binding) + binding_gref_count = binding.__grefcount__ self.source.int_prop = 1 self.assertEqual(self.source.int_prop, 1) @@ -520,19 +622,18 @@ class TestPropertyBindings(unittest.TestCase): self.assertEqual(self.source.int_prop, 2) self.assertEqual(self.target.int_prop, 4) - self.assertEqual(sys.getrefcount(binding()), binding_ref_count) - self.assertEqual(binding().__grefcount__, binding_gref_count) + if hasattr(sys, "getrefcount"): + self.assertEqual(sys.getrefcount(binding), binding_ref_count) + self.assertEqual(binding.__grefcount__, binding_gref_count) # test_data ref count increases by 2, once for each callback. - self.assertEqual(sys.getrefcount(test_data), test_data_ref_count + 2) - self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count + 1) - self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count + 1) + if hasattr(sys, "getrefcount"): + self.assertEqual(sys.getrefcount(test_data), test_data_ref_count + 2) + self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count + 1) + self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count + 1) # Unbind should clear out the binding and its transforms binding.unbind() - self.assertEqual(binding(), None) - del binding - gc.collect() # Setting source or target should not change the other. self.target.int_prop = 3 @@ -540,9 +641,10 @@ class TestPropertyBindings(unittest.TestCase): self.assertEqual(self.target.int_prop, 3) self.assertEqual(self.source.int_prop, 5) - self.assertEqual(sys.getrefcount(test_data), test_data_ref_count) - self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count) - self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count) + if hasattr(sys, "getrefcount"): + self.assertEqual(sys.getrefcount(test_data), test_data_ref_count) + self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count) + self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count) def test_explicit_unbind_clears_connection(self): self.assertEqual(self.source.int_prop, 0) @@ -554,15 +656,24 @@ class TestPropertyBindings(unittest.TestCase): self.assertEqual(self.source.int_prop, 1) self.assertEqual(self.target.int_prop, 1) + # unbind should clear out the bindings self reference binding.unbind() - self.assertEqual(binding(), None) + self.assertEqual(binding.__grefcount__, 1) self.source.int_prop = 10 self.assertEqual(self.source.int_prop, 10) self.assertEqual(self.target.int_prop, 1) - # An already unbound BindingWeakRef will raise if unbind is attempted a second time. - self.assertRaises(ValueError, binding.unbind) + glib_version = (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION) + + # calling unbind() on an already unbound binding + if glib_version >= (2, 57, 3): + # Fixed in newer glib: + # https://gitlab.gnome.org/GNOME/glib/merge_requests/244 + for i in range(10): + binding.unbind() + else: + self.assertRaises(ValueError, binding.unbind) def test_reference_counts(self): self.assertEqual(self.source.__grefcount__, 1) @@ -572,7 +683,7 @@ class TestPropertyBindings(unittest.TestCase): # the act of binding and the ref incurred by using __call__ to generate # a wrapper from the weak binding ref within python. binding = self.source.bind_property('int_prop', self.target, 'int_prop') - self.assertEqual(binding().__grefcount__, 2) + self.assertEqual(binding.__grefcount__, 2) # Creating a binding does not inc refs on source and target (they are weak # on the binding object itself) @@ -581,18 +692,25 @@ class TestPropertyBindings(unittest.TestCase): # Use GObject.get_property because the "props" accessor leaks. # Note property names are canonicalized. - self.assertEqual(binding().get_property('source'), self.source) - self.assertEqual(binding().get_property('source_property'), 'int-prop') - self.assertEqual(binding().get_property('target'), self.target) - self.assertEqual(binding().get_property('target_property'), 'int-prop') - self.assertEqual(binding().get_property('flags'), GObject.BindingFlags.DEFAULT) - - # Delete reference to source or target and the binding should listen. + self.assertEqual(binding.get_property('source'), self.source) + self.assertEqual(binding.get_property('source_property'), 'int-prop') + self.assertEqual(binding.get_property('target'), self.target) + self.assertEqual(binding.get_property('target_property'), 'int-prop') + self.assertEqual(binding.get_property('flags'), GObject.BindingFlags.DEFAULT) + + # Delete reference to source or target and the binding will remove its own + # "self reference". ref = self.source.weak_ref() del self.source gc.collect() self.assertEqual(ref(), None) - self.assertEqual(binding(), None) + self.assertEqual(binding.__grefcount__, 1) + + # Finally clear out the last ref held by the python wrapper + ref = binding.weak_ref() + del binding + gc.collect() + self.assertEqual(ref(), None) class TestGValue(unittest.TestCase): @@ -657,5 +775,86 @@ class TestGValue(unittest.TestCase): value = GObject.Value(GObject.TYPE_OBJECT, obj) self.assertEqual(value.get_value(), obj) -if __name__ == '__main__': - unittest.main() + def test_value_array(self): + value = GObject.Value(GObject.ValueArray) + self.assertEqual(value.g_type, GObject.type_from_name('GValueArray')) + value.set_value([32, 'foo_bar', 0.3]) + self.assertEqual(value.get_value(), [32, 'foo_bar', 0.3]) + + def test_value_array_from_gvalue_list(self): + value = GObject.Value(GObject.ValueArray, [ + GObject.Value(GObject.TYPE_UINT, 0xffffffff), + GObject.Value(GObject.TYPE_STRING, 'foo_bar')]) + self.assertEqual(value.g_type, GObject.type_from_name('GValueArray')) + self.assertEqual(value.get_value(), [0xffffffff, 'foo_bar']) + self.assertEqual(testhelper.value_array_get_nth_type(value, 0), GObject.TYPE_UINT) + self.assertEqual(testhelper.value_array_get_nth_type(value, 1), GObject.TYPE_STRING) + + def test_value_array_append_gvalue(self): + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + + arr = GObject.ValueArray.new(0) + arr.append(GObject.Value(GObject.TYPE_UINT, 0xffffffff)) + arr.append(GObject.Value(GObject.TYPE_STRING, 'foo_bar')) + self.assertEqual(arr.get_nth(0), 0xffffffff) + self.assertEqual(arr.get_nth(1), 'foo_bar') + self.assertEqual(testhelper.value_array_get_nth_type(arr, 0), GObject.TYPE_UINT) + self.assertEqual(testhelper.value_array_get_nth_type(arr, 1), GObject.TYPE_STRING) + + def test_gerror_boxing(self): + error = GLib.Error('test message', domain='mydomain', code=42) + value = GObject.Value(GLib.Error, error) + self.assertEqual(value.g_type, GObject.type_from_name('GError')) + + unboxed = value.get_value() + self.assertEqual(unboxed.message, error.message) + self.assertEqual(unboxed.domain, error.domain) + self.assertEqual(unboxed.code, error.code) + + def test_gerror_novalue(self): + GLib.Error('test message', domain='mydomain', code=42) + value = GObject.Value(GLib.Error) + self.assertEqual(value.g_type, GObject.type_from_name('GError')) + self.assertEqual(value.get_value(), None) + + +def test_list_properties(): + + def find_param(props, name): + for param in props: + if param.name == name: + return param + return + + list_props = GObject.list_properties + + props = list_props(Gio.Action) + param = find_param(props, "enabled") + assert param + assert param.value_type == GObject.TYPE_BOOLEAN + assert list_props("GAction") == list_props(Gio.Action) + assert list_props(Gio.Action.__gtype__) == list_props(Gio.Action) + + props = list_props(Gio.SimpleAction) + assert find_param(props, "enabled") + + def names(props): + return [p.name for p in props] + + assert (set(names(list_props(Gio.Action))) <= + set(names(list_props(Gio.SimpleAction)))) + + props = list_props(Gio.FileIcon) + param = find_param(props, "file") + assert param + assert param.value_type == Gio.File.__gtype__ + + assert list_props("GFileIcon") == list_props(Gio.FileIcon) + assert list_props(Gio.FileIcon.__gtype__) == list_props(Gio.FileIcon) + assert list_props(Gio.FileIcon( + file=Gio.File.new_for_path('.'))) == list_props(Gio.FileIcon) + + for obj in [Gio.ActionEntry, Gio.DBusError, 0, object()]: + with pytest.raises(TypeError): + list_props(obj) |