X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gobject%2Ftests%2Freference.c;h=0742339a1ac13a477225472dadebcfc1d82ac635;hb=1dc774a653e992e1153fbed16f90097fa8db467f;hp=37793dd263e2f09b6cb43225260c0f8cc0e59b6f;hpb=1b033919845cef366842373da9f1cfb56f522d01;p=platform%2Fupstream%2Fglib.git diff --git a/gobject/tests/reference.c b/gobject/tests/reference.c index 37793dd..0742339 100644 --- a/gobject/tests/reference.c +++ b/gobject/tests/reference.c @@ -25,7 +25,6 @@ test_fundamentals (void) g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_OBJECT)); g_assert (G_TYPE_OBJECT == g_object_get_type ()); g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_VARIANT)); - g_assert (G_TYPE_VARIANT == g_variant_get_gtype ()); g_assert (G_TYPE_IS_DERIVED (G_TYPE_INITIALLY_UNOWNED)); g_assert (g_type_fundamental_next () == G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST)); @@ -74,6 +73,7 @@ struct _MyObjectClassPrivate gint secret_class_count; }; +static GType my_object_get_type (void); G_DEFINE_TYPE_WITH_CODE (MyObject, my_object, G_TYPE_OBJECT, g_type_add_class_private (g_define_type_id, sizeof (MyObjectClassPrivate)) ); @@ -152,15 +152,26 @@ test_clear_function (void) } static void +toggle_cb (gpointer data, GObject *obj, gboolean is_last) +{ + gboolean *b = data; + + *b = TRUE; +} + +static void test_object_value (void) { GObject *v; GObject *v2; - GValue value = { 0, }; + GValue value = G_VALUE_INIT; + gboolean toggled = FALSE; g_value_init (&value, G_TYPE_OBJECT); v = g_object_new (G_TYPE_OBJECT, NULL); + g_object_add_toggle_ref (v, toggle_cb, &toggled); + g_value_take_object (&value, v); v2 = g_value_get_object (&value); @@ -170,7 +181,24 @@ test_object_value (void) g_assert (v2 == v); /* objects use ref/unref for copy/free */ g_object_unref (v2); + g_assert (!toggled); + g_value_unset (&value); + g_assert (toggled); + + /* test the deprecated variant too */ + g_value_init (&value, G_TYPE_OBJECT); + /* get a new reference */ + g_object_ref (v); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + g_value_set_object_take_ownership (&value, v); +G_GNUC_END_IGNORE_DEPRECATIONS + + toggled = FALSE; g_value_unset (&value); + g_assert (toggled); + + g_object_remove_toggle_ref (v, toggle_cb, &toggled); } static void @@ -227,13 +255,349 @@ test_weak_pointer (void) g_assert (weak2 == obj); } +/* See gobject/tests/threadtests.c for the threaded version */ +static void +test_weak_ref (void) +{ + GObject *obj; + GObject *obj2; + GObject *tmp; + GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } }; + GWeakRef weak2 = { { GUINT_TO_POINTER (0xDEADBEEFU) } }; + GWeakRef weak3 = { { GUINT_TO_POINTER (0xDEADBEEFU) } }; + GWeakRef *dynamic_weak = g_new (GWeakRef, 1); + + /* you can initialize to empty like this... */ + g_weak_ref_init (&weak2, NULL); + g_assert (g_weak_ref_get (&weak2) == NULL); + + /* ... or via an initializer */ + g_weak_ref_init (&weak3, NULL); + g_assert (g_weak_ref_get (&weak3) == NULL); + + obj = g_object_new (G_TYPE_OBJECT, NULL); + g_assert_cmpint (obj->ref_count, ==, 1); + + obj2 = g_object_new (G_TYPE_OBJECT, NULL); + g_assert_cmpint (obj2->ref_count, ==, 1); + + /* you can init with an object (even if uninitialized) */ + g_weak_ref_init (&weak, obj); + g_weak_ref_init (dynamic_weak, obj); + /* or set to point at an object, if initialized (maybe to 0) */ + g_weak_ref_set (&weak2, obj); + g_weak_ref_set (&weak3, obj); + /* none of this affects its refcount */ + g_assert_cmpint (obj->ref_count, ==, 1); + + /* getting the value takes a ref */ + tmp = g_weak_ref_get (&weak); + g_assert (tmp == obj); + g_assert_cmpint (obj->ref_count, ==, 2); + g_object_unref (tmp); + g_assert_cmpint (obj->ref_count, ==, 1); + + tmp = g_weak_ref_get (&weak2); + g_assert (tmp == obj); + g_assert_cmpint (obj->ref_count, ==, 2); + g_object_unref (tmp); + g_assert_cmpint (obj->ref_count, ==, 1); + + tmp = g_weak_ref_get (&weak3); + g_assert (tmp == obj); + g_assert_cmpint (obj->ref_count, ==, 2); + g_object_unref (tmp); + g_assert_cmpint (obj->ref_count, ==, 1); + + tmp = g_weak_ref_get (dynamic_weak); + g_assert (tmp == obj); + g_assert_cmpint (obj->ref_count, ==, 2); + g_object_unref (tmp); + g_assert_cmpint (obj->ref_count, ==, 1); + + /* clearing a weak ref stops tracking */ + g_weak_ref_clear (&weak); + + /* setting a weak ref to NULL stops tracking too */ + g_weak_ref_set (&weak2, NULL); + g_assert (g_weak_ref_get (&weak2) == NULL); + g_weak_ref_clear (&weak2); + + /* setting a weak ref to a new object stops tracking the old one */ + g_weak_ref_set (dynamic_weak, obj2); + tmp = g_weak_ref_get (dynamic_weak); + g_assert (tmp == obj2); + g_assert_cmpint (obj2->ref_count, ==, 2); + g_object_unref (tmp); + g_assert_cmpint (obj2->ref_count, ==, 1); + + g_assert_cmpint (obj->ref_count, ==, 1); + + /* free the object: weak3 is the only one left pointing there */ + g_object_unref (obj); + g_assert (g_weak_ref_get (&weak3) == NULL); + + /* setting a weak ref to a new object stops tracking the old one */ + g_weak_ref_set (dynamic_weak, obj2); + tmp = g_weak_ref_get (dynamic_weak); + g_assert (tmp == obj2); + g_assert_cmpint (obj2->ref_count, ==, 2); + g_object_unref (tmp); + g_assert_cmpint (obj2->ref_count, ==, 1); + + g_weak_ref_clear (&weak3); + + /* clear and free dynamic_weak... */ + g_weak_ref_clear (dynamic_weak); + + /* ... to prove that doing so stops this from being a use-after-free */ + g_object_unref (obj2); + g_free (dynamic_weak); +} + +typedef struct +{ + gboolean should_be_last; + gint count; +} Count; + +static void +toggle_notify (gpointer data, + GObject *obj, + gboolean is_last) +{ + Count *c = data; + + g_assert (is_last == c->should_be_last); + + c->count++; +} + +static void +test_toggle_ref (void) +{ + GObject *obj; + Count c, c2; + + obj = g_object_new (G_TYPE_OBJECT, NULL); + + g_object_add_toggle_ref (obj, toggle_notify, &c); + g_object_add_toggle_ref (obj, toggle_notify, &c2); + + c.should_be_last = c2.should_be_last = TRUE; + c.count = c2.count = 0; + + g_object_unref (obj); + + g_assert_cmpint (c.count, ==, 0); + g_assert_cmpint (c2.count, ==, 0); + + g_object_ref (obj); + + g_assert_cmpint (c.count, ==, 0); + g_assert_cmpint (c2.count, ==, 0); + + g_object_remove_toggle_ref (obj, toggle_notify, &c2); + + g_object_unref (obj); + + g_assert_cmpint (c.count, ==, 1); + + c.should_be_last = FALSE; + + g_object_ref (obj); + + g_assert_cmpint (c.count, ==, 2); + + c.should_be_last = TRUE; + + g_object_unref (obj); + + g_assert_cmpint (c.count, ==, 3); + + g_object_remove_toggle_ref (obj, toggle_notify, &c); +} + +static gboolean destroyed; +static gint value; + +static void +data_destroy (gpointer data) +{ + g_assert_cmpint (GPOINTER_TO_INT (data), ==, value); + + destroyed = TRUE; +} + +static void +test_object_qdata (void) +{ + GObject *obj; + gpointer v; + GQuark quark; + + obj = g_object_new (G_TYPE_OBJECT, NULL); + + value = 1; + destroyed = FALSE; + g_object_set_data_full (obj, "test", GINT_TO_POINTER (1), data_destroy); + v = g_object_get_data (obj, "test"); + g_assert_cmpint (GPOINTER_TO_INT (v), ==, 1); + g_object_set_data_full (obj, "test", GINT_TO_POINTER (2), data_destroy); + g_assert (destroyed); + value = 2; + destroyed = FALSE; + v = g_object_steal_data (obj, "test"); + g_assert_cmpint (GPOINTER_TO_INT (v), ==, 2); + g_assert (!destroyed); + + value = 1; + destroyed = FALSE; + quark = g_quark_from_string ("test"); + g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (1), data_destroy); + v = g_object_get_qdata (obj, quark); + g_assert_cmpint (GPOINTER_TO_INT (v), ==, 1); + g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (2), data_destroy); + g_assert (destroyed); + value = 2; + destroyed = FALSE; + v = g_object_steal_qdata (obj, quark); + g_assert_cmpint (GPOINTER_TO_INT (v), ==, 2); + g_assert (!destroyed); + + g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (3), data_destroy); + value = 3; + destroyed = FALSE; + g_object_unref (obj); + + g_assert (destroyed); +} + +typedef struct { + const gchar *value; + gint refcount; +} Value; + +static gpointer +ref_value (gpointer value, gpointer user_data) +{ + Value *v = value; + Value **old_value_p = user_data; + + if (old_value_p) + *old_value_p = v; + + if (v) + v->refcount += 1; + + return value; +} + +static void +unref_value (gpointer value) +{ + Value *v = value; + + v->refcount -= 1; + if (v->refcount == 0) + g_free (value); +} + +static +Value * +new_value (const gchar *s) +{ + Value *v; + + v = g_new (Value, 1); + v->value = s; + v->refcount = 1; + + return v; +} + +static void +test_object_qdata2 (void) +{ + GObject *obj; + Value *v, *v1, *v2, *v3, *old_val; + GDestroyNotify old_destroy; + gboolean res; + + obj = g_object_new (G_TYPE_OBJECT, NULL); + + v1 = new_value ("bla"); + + g_object_set_data_full (obj, "test", v1, unref_value); + + v = g_object_get_data (obj, "test"); + g_assert_cmpstr (v->value, ==, "bla"); + g_assert_cmpint (v->refcount, ==, 1); + + v = g_object_dup_data (obj, "test", ref_value, &old_val); + g_assert (old_val == v1); + g_assert_cmpstr (v->value, ==, "bla"); + g_assert_cmpint (v->refcount, ==, 2); + unref_value (v); + + v = g_object_dup_data (obj, "nono", ref_value, &old_val); + g_assert (old_val == NULL); + g_assert (v == NULL); + + v2 = new_value ("not"); + + res = g_object_replace_data (obj, "test", v1, v2, unref_value, &old_destroy); + g_assert (res == TRUE); + g_assert (old_destroy == unref_value); + g_assert_cmpstr (v1->value, ==, "bla"); + g_assert_cmpint (v1->refcount, ==, 1); + + v = g_object_get_data (obj, "test"); + g_assert_cmpstr (v->value, ==, "not"); + g_assert_cmpint (v->refcount, ==, 1); + + v3 = new_value ("xyz"); + res = g_object_replace_data (obj, "test", v1, v3, unref_value, &old_destroy); + g_assert (res == FALSE); + g_assert_cmpstr (v2->value, ==, "not"); + g_assert_cmpint (v2->refcount, ==, 1); + + unref_value (v1); + + res = g_object_replace_data (obj, "test", NULL, v3, unref_value, &old_destroy); + g_assert (res == FALSE); + g_assert_cmpstr (v2->value, ==, "not"); + g_assert_cmpint (v2->refcount, ==, 1); + + res = g_object_replace_data (obj, "test", v2, NULL, unref_value, &old_destroy); + g_assert (res == TRUE); + g_assert (old_destroy == unref_value); + g_assert_cmpstr (v2->value, ==, "not"); + g_assert_cmpint (v2->refcount, ==, 1); + + unref_value (v2); + + v = g_object_get_data (obj, "test"); + g_assert (v == NULL); + + res = g_object_replace_data (obj, "test", NULL, v3, unref_value, &old_destroy); + g_assert (res == TRUE); + + v = g_object_get_data (obj, "test"); + g_assert (v == v3); + + ref_value (v3, NULL); + g_assert_cmpint (v3->refcount, ==, 2); + g_object_unref (obj); + g_assert_cmpint (v3->refcount, ==, 1); + unref_value (v3); +} + int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); - g_type_init (); - g_test_add_func ("/type/fundamentals", test_fundamentals); g_test_add_func ("/type/qdata", test_type_qdata); g_test_add_func ("/type/query", test_type_query); @@ -243,6 +607,10 @@ main (int argc, char **argv) g_test_add_func ("/object/value", test_object_value); g_test_add_func ("/object/initially-unowned", test_initially_unowned); g_test_add_func ("/object/weak-pointer", test_weak_pointer); + g_test_add_func ("/object/weak-ref", test_weak_ref); + g_test_add_func ("/object/toggle-ref", test_toggle_ref); + g_test_add_func ("/object/qdata", test_object_qdata); + g_test_add_func ("/object/qdata2", test_object_qdata2); return g_test_run (); }