summaryrefslogtreecommitdiff
path: root/tests/test_gobject.py
diff options
context:
space:
mode:
authorTizenOpenSource <tizenopensrc@samsung.com>2023-12-08 13:16:12 +0900
committerTizenOpenSource <tizenopensrc@samsung.com>2023-12-08 13:16:12 +0900
commit454aa52f950f2348756dfffc9c26fb74d4aa3bef (patch)
tree4e8be3f8c8218dbafe65e22dfc73e9351c1d5bbb /tests/test_gobject.py
parentf3eae5a895fc60cb99c0c366bdd011018ce3bc7b (diff)
downloadpygobject2-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.py305
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)