[pygobject] Add tests for refcount of a GObject owned by a library



commit cae2cf3d4fb049c94389bf8f84d7d97a544d7a3f
Author: Steve Frécinaux <code istique net>
Date:   Wed Jan 19 16:57:57 2011 +0100

    Add tests for refcount of a GObject owned by a library
    
    When the object is constructed, its refcount is 2 because the library
    refs it once. It should remain around until we ask the library to
    release its reference.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=639949

 tests/test-floating.c    |   30 ++++++++++++++++++++++
 tests/test-floating.h    |   20 +++++++++++++++
 tests/test_gobject.py    |   62 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/testhelpermodule.c |   51 +++++++++++++++++++++++++++++++++++++
 4 files changed, 163 insertions(+), 0 deletions(-)
---
diff --git a/tests/test-floating.c b/tests/test-floating.c
index 918a42d..393784e 100644
--- a/tests/test-floating.c
+++ b/tests/test-floating.c
@@ -93,3 +93,33 @@ test_floating_without_sink_func_init (TestFloatingWithoutSinkFunc *self)
 {
 }
 
+/* TestOwnedByLibrary */
+
+G_DEFINE_TYPE(TestOwnedByLibrary, test_owned_by_library, G_TYPE_OBJECT)
+
+static GSList *obl_instance_list = NULL;
+
+static void
+test_owned_by_library_class_init (TestOwnedByLibraryClass *klass)
+{
+}
+
+static void
+test_owned_by_library_init (TestOwnedByLibrary *self)
+{
+    g_object_ref (self);
+    obl_instance_list = g_slist_prepend (obl_instance_list, self);
+}
+
+void
+test_owned_by_library_release (TestOwnedByLibrary *self)
+{
+    obl_instance_list = g_slist_remove (obl_instance_list, self);
+    g_object_unref (self);
+}
+
+GSList *
+test_owned_by_library_get_instance_list (void)
+{
+    return obl_instance_list;
+}
diff --git a/tests/test-floating.h b/tests/test-floating.h
index e53df32..05cd394 100644
--- a/tests/test-floating.h
+++ b/tests/test-floating.h
@@ -58,3 +58,23 @@ typedef struct {
 
 GType test_floating_without_sink_func_get_type (void);
 
+/* TestOwnedByLibrary */
+
+typedef struct {
+  GObject parent;
+} TestOwnedByLibrary;
+
+typedef struct {
+  GObjectClass parent_class;
+} TestOwnedByLibraryClass;
+
+#define TEST_TYPE_OWNED_BY_LIBRARY            (test_owned_by_library_get_type())
+#define TEST_OWNED_BY_LIBRARY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_OWNED_BY_LIBRARY, TestOwnedByLibrary))
+#define TEST_OWNED_BY_LIBRARY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_OWNED_BY_LIBRARY, TestOwnedByLibraryClass))
+#define TEST_IS_OWNED_BY_LIBRARY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_OWNED_BY_LIBRARY))
+#define TEST_IS_OWNED_BY_LIBRARY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), TEST_TYPE_OWNED_BY_LIBRARY))
+#define TEST_OWNED_BY_LIBRARY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), TEST_TYPE_OWNED_BY_LIBRARY, TestOwnedByLibraryClass))
+
+GType test_owned_by_library_get_type (void);
+void test_owned_by_library_release (TestOwnedByLibrary *self);
+GSList *test_owned_by_library_get_instance_list (void);
diff --git a/tests/test_gobject.py b/tests/test_gobject.py
index b445be9..cfcebfd 100644
--- a/tests/test_gobject.py
+++ b/tests/test_gobject.py
@@ -34,3 +34,65 @@ class TestReferenceCounting(unittest.TestCase):
 
         obj = gobject.new(testhelper.FloatingWithoutSinkFunc)
         self.assertEquals(obj.__grefcount__, 1)
+
+    def testOwnedByLibrary(self):
+        # Upon creation, the refcount of the object should be 2:
+        # - someone already has a reference on the new object.
+        # - the python wrapper should hold its own reference.
+        obj = testhelper.OwnedByLibrary()
+        self.assertEquals(obj.__grefcount__, 2)
+
+        # We ask the library to release its reference, so the only
+        # remaining ref should be our wrapper's. Once the wrapper
+        # will run out of scope, the object will get finalized.
+        obj.release()
+        self.assertEquals(obj.__grefcount__, 1)
+
+    def testOwnedByLibraryOutOfScope(self):
+        obj = testhelper.OwnedByLibrary()
+        self.assertEquals(obj.__grefcount__, 2)
+
+        # We are manually taking the object out of scope. This means
+        # that our wrapper has been freed, and its reference dropped. We
+        # cannot check it but the refcount should now be 1 (the ref held
+        # by the library is still there, we didn't call release()
+        obj = None
+
+        # When we get the object back from the lib, the wrapper is
+        # re-created, so our refcount will be 2 once again.
+        obj = testhelper.owned_by_library_get_instance_list()[0]
+        self.assertEquals(obj.__grefcount__, 2)
+
+        obj.release()
+        self.assertEquals(obj.__grefcount__, 1)
+
+    def testOwnedByLibraryUsingGObjectNew(self):
+        # Upon creation, the refcount of the object should be 2:
+        # - someone already has a reference on the new object.
+        # - the python wrapper should hold its own reference.
+        obj = gobject.new(testhelper.OwnedByLibrary)
+        self.assertEquals(obj.__grefcount__, 2)
+
+        # We ask the library to release its reference, so the only
+        # remaining ref should be our wrapper's. Once the wrapper
+        # will run out of scope, the object will get finalized.
+        obj.release()
+        self.assertEquals(obj.__grefcount__, 1)
+
+    def testOwnedByLibraryOutOfScopeUsingGobjectNew(self):
+        obj = gobject.new(testhelper.OwnedByLibrary)
+        self.assertEquals(obj.__grefcount__, 2)
+
+        # We are manually taking the object out of scope. This means
+        # that our wrapper has been freed, and its reference dropped. We
+        # cannot check it but the refcount should now be 1 (the ref held
+        # by the library is still there, we didn't call release()
+        obj = None
+
+        # When we get the object back from the lib, the wrapper is
+        # re-created, so our refcount will be 2 once again.
+        obj = testhelper.owned_by_library_get_instance_list()[0]
+        self.assertEquals(obj.__grefcount__, 2)
+
+        obj.release()
+        self.assertEquals(obj.__grefcount__, 1)
diff --git a/tests/testhelpermodule.c b/tests/testhelpermodule.c
index 5610a5d..9a0be36 100644
--- a/tests/testhelpermodule.c
+++ b/tests/testhelpermodule.c
@@ -230,6 +230,22 @@ PYGLIB_DEFINE_TYPE("testhelper.FloatingWithSinkFunc", PyTestFloatingWithSinkFunc
 /* TestFloatingWithoutSinkFunc */
 PYGLIB_DEFINE_TYPE("testhelper.FloatingWithoutSinkFunc", PyTestFloatingWithoutSinkFunc_Type, PyGObject);
 
+/* TestOwnedByLibrary */
+PYGLIB_DEFINE_TYPE("testhelper.OwnedByLibrary", PyTestOwnedByLibrary_Type, PyGObject);
+
+static PyObject *
+_wrap_test_owned_by_library_release (PyGObject *self)
+{
+    test_owned_by_library_release (TEST_OWNED_BY_LIBRARY (self->obj));
+    return Py_None;
+}
+
+static const PyMethodDef _PyTestOwnedByLibrary_methods[] = {
+    { "release", (PyCFunction)_wrap_test_owned_by_library_release, METH_NOARGS, NULL },
+    { NULL, NULL, 0, NULL }
+};
+
+
 #include <string.h>
 #include <glib-object.h>
 
@@ -431,6 +447,29 @@ _wrap_test_gerror_exception(PyObject *self, PyObject *args)
     return Py_None;
 }
 
+static PyObject *
+_wrap_test_owned_by_library_get_instance_list (PyObject *self)
+{
+    PyObject *py_list, *py_obj;
+    GSList *list, *tmp;
+
+    list = test_owned_by_library_get_instance_list ();
+
+    if ((py_list = PyList_New (0)) == NULL) {
+	return NULL;
+    }
+    for (tmp = list; tmp != NULL; tmp = tmp->next) {
+	py_obj = pygobject_new (G_OBJECT (tmp->data));
+	if (py_obj == NULL) {
+	    Py_DECREF (py_list);
+	    return NULL;
+	}
+	PyList_Append (py_list, py_obj);
+	Py_DECREF (py_obj);
+    }
+    return py_list;
+}
+
 static PyMethodDef testhelper_functions[] = {
     { "get_test_thread", (PyCFunction)_wrap_get_test_thread, METH_NOARGS },
     { "get_unknown", (PyCFunction)_wrap_get_unknown, METH_NOARGS },
@@ -440,6 +479,7 @@ static PyMethodDef testhelper_functions[] = {
     { "test_value", (PyCFunction)_wrap_test_value, METH_VARARGS },      
     { "test_value_array", (PyCFunction)_wrap_test_value_array, METH_VARARGS },
     { "test_gerror_exception", (PyCFunction)_wrap_test_gerror_exception, METH_VARARGS },
+    { "owned_by_library_get_instance_list", (PyCFunction)_wrap_test_owned_by_library_get_instance_list, METH_NOARGS },
     { NULL, NULL }
 };
 
@@ -507,6 +547,17 @@ PYGLIB_MODULE_START(testhelper, "testhelper")
 			   Py_BuildValue("(O)",
                            &PyGObject_Type));
   pyg_set_object_has_new_constructor(TEST_TYPE_FLOATING_WITHOUT_SINK_FUNC);
+
+  /* TestOwnedByLibrary */
+  PyTestOwnedByLibrary_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE);
+  PyTestOwnedByLibrary_Type.tp_methods = (struct PyMethodDef*)_PyTestOwnedByLibrary_methods;
+  PyTestOwnedByLibrary_Type.tp_weaklistoffset = offsetof(PyGObject, weakreflist);
+  PyTestOwnedByLibrary_Type.tp_dictoffset = offsetof(PyGObject, inst_dict);
+  pygobject_register_class(d, "OwnedByLibrary", TEST_TYPE_OWNED_BY_LIBRARY,
+			   &PyTestOwnedByLibrary_Type,
+			   Py_BuildValue("(O)",
+                           &PyGObject_Type));
+  pyg_set_object_has_new_constructor(TEST_TYPE_OWNED_BY_LIBRARY);
 }
 PYGLIB_MODULE_END
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]