(root)/
glib-2.79.0/
gobject/
tests/
reference.c
       1  #include <glib-object.h>
       2  
       3  static void
       4  test_fundamentals (void)
       5  {
       6    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_NONE));
       7    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_INTERFACE));
       8    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_CHAR));
       9    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_UCHAR));
      10    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_BOOLEAN));
      11    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_INT));
      12    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_UINT));
      13    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_LONG));
      14    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_ULONG));
      15    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_INT64));
      16    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_UINT64));
      17    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_ENUM));
      18    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_FLAGS));
      19    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_FLOAT));
      20    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_DOUBLE));
      21    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_STRING));
      22    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_POINTER));
      23    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_BOXED));
      24    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_PARAM));
      25    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_OBJECT));
      26    g_assert (G_TYPE_OBJECT == g_object_get_type ());
      27    g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_VARIANT));
      28    g_assert (G_TYPE_IS_DERIVED (G_TYPE_INITIALLY_UNOWNED));
      29  
      30    g_assert (g_type_fundamental_next () == G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST));
      31  }
      32  
      33  static void
      34  test_type_qdata (void)
      35  {
      36    gchar *data;
      37  
      38    g_type_set_qdata (G_TYPE_ENUM, g_quark_from_string ("bla"), "bla");
      39    data = g_type_get_qdata (G_TYPE_ENUM, g_quark_from_string ("bla"));
      40    g_assert_cmpstr (data, ==, "bla");
      41  }
      42  
      43  static void
      44  test_type_query (void)
      45  {
      46    GTypeQuery query;
      47  
      48    g_type_query (G_TYPE_ENUM, &query);
      49    g_assert_cmpint (query.type, ==, G_TYPE_ENUM);
      50    g_assert_cmpstr (query.type_name, ==, "GEnum");
      51    g_assert_cmpint (query.class_size, ==, sizeof (GEnumClass));
      52    g_assert_cmpint (query.instance_size, ==, 0);
      53  }
      54  
      55  typedef struct _MyObject MyObject;
      56  typedef struct _MyObjectClass MyObjectClass;
      57  typedef struct _MyObjectClassPrivate MyObjectClassPrivate;
      58  
      59  struct _MyObject
      60  {
      61    GObject parent_instance;
      62  
      63    gint count;
      64  };
      65  
      66  struct _MyObjectClass
      67  {
      68    GObjectClass parent_class;
      69  };
      70  
      71  struct _MyObjectClassPrivate
      72  {
      73    gint secret_class_count;
      74  };
      75  
      76  static GType my_object_get_type (void);
      77  G_DEFINE_TYPE_WITH_CODE (MyObject, my_object, G_TYPE_OBJECT,
      78                           g_type_add_class_private (g_define_type_id, sizeof (MyObjectClassPrivate)) );
      79  
      80  static void
      81  my_object_init (MyObject *obj)
      82  {
      83    obj->count = 42;
      84  }
      85  
      86  static void
      87  my_object_class_init (MyObjectClass *klass)
      88  {
      89  }
      90  
      91  static void
      92  test_class_private (void)
      93  {
      94    GObject *obj;
      95    MyObjectClass *class;
      96    MyObjectClassPrivate *priv;
      97  
      98    obj = g_object_new (my_object_get_type (), NULL);
      99  
     100    class = g_type_class_ref (my_object_get_type ());
     101    priv = G_TYPE_CLASS_GET_PRIVATE (class, my_object_get_type (), MyObjectClassPrivate);
     102    priv->secret_class_count = 13;
     103    g_type_class_unref (class);
     104  
     105    g_object_unref (obj);
     106  
     107    g_assert_cmpint (g_type_qname (my_object_get_type ()), ==, g_quark_from_string ("MyObject"));
     108  }
     109  
     110  static void
     111  test_clear (void)
     112  {
     113    GObject *o = NULL;
     114    GObject *tmp;
     115  
     116    g_clear_object (&o);
     117    g_assert (o == NULL);
     118  
     119    tmp = g_object_new (G_TYPE_OBJECT, NULL);
     120    g_assert_cmpint (tmp->ref_count, ==, 1);
     121    o = g_object_ref (tmp);
     122    g_assert (o != NULL);
     123  
     124    g_assert_cmpint (tmp->ref_count, ==, 2);
     125    g_clear_object (&o);
     126    g_assert_cmpint (tmp->ref_count, ==, 1);
     127    g_assert (o == NULL);
     128  
     129    g_object_unref (tmp);
     130  }
     131  
     132  static void
     133  test_clear_function (void)
     134  {
     135    GObject *o = NULL;
     136    GObject *tmp;
     137  
     138    (g_clear_object) (&o);
     139    g_assert (o == NULL);
     140  
     141    tmp = g_object_new (G_TYPE_OBJECT, NULL);
     142    g_assert_cmpint (tmp->ref_count, ==, 1);
     143    o = g_object_ref (tmp);
     144    g_assert (o != NULL);
     145  
     146    g_assert_cmpint (tmp->ref_count, ==, 2);
     147    (g_clear_object) (&o);
     148    g_assert_cmpint (tmp->ref_count, ==, 1);
     149    g_assert (o == NULL);
     150  
     151    g_object_unref (tmp);
     152  }
     153  
     154  static void
     155  test_set (void)
     156  {
     157    GObject *o = NULL;
     158    GObject *tmp;
     159    gpointer tmp_weak = NULL;
     160  
     161    g_assert (!g_set_object (&o, NULL));
     162    g_assert (o == NULL);
     163  
     164    tmp = g_object_new (G_TYPE_OBJECT, NULL);
     165    tmp_weak = tmp;
     166    g_object_add_weak_pointer (tmp, &tmp_weak);
     167    g_assert_cmpint (tmp->ref_count, ==, 1);
     168  
     169    g_assert (g_set_object (&o, tmp));
     170    g_assert (o == tmp);
     171    g_assert_cmpint (tmp->ref_count, ==, 2);
     172  
     173    g_object_unref (tmp);
     174    g_assert_cmpint (tmp->ref_count, ==, 1);
     175  
     176    /* Setting it again shouldn’t cause finalisation. */
     177    g_assert (!g_set_object (&o, tmp));
     178    g_assert (o == tmp);
     179    g_assert_cmpint (tmp->ref_count, ==, 1);
     180    g_assert_nonnull (tmp_weak);
     181  
     182    g_assert (g_set_object (&o, NULL));
     183    g_assert (o == NULL);
     184    g_assert_null (tmp_weak);
     185  }
     186  
     187  static void
     188  test_set_function (void)
     189  {
     190    GObject *o = NULL;
     191    GObject *tmp;
     192    gpointer tmp_weak = NULL;
     193  
     194    g_assert (!(g_set_object) (&o, NULL));
     195    g_assert (o == NULL);
     196  
     197    tmp = g_object_new (G_TYPE_OBJECT, NULL);
     198    tmp_weak = tmp;
     199    g_object_add_weak_pointer (tmp, &tmp_weak);
     200    g_assert_cmpint (tmp->ref_count, ==, 1);
     201  
     202    g_assert ((g_set_object) (&o, tmp));
     203    g_assert (o == tmp);
     204    g_assert_cmpint (tmp->ref_count, ==, 2);
     205  
     206    g_object_unref (tmp);
     207    g_assert_cmpint (tmp->ref_count, ==, 1);
     208  
     209    /* Setting it again shouldn’t cause finalisation. */
     210    g_assert (!(g_set_object) (&o, tmp));
     211    g_assert (o == tmp);
     212    g_assert_cmpint (tmp->ref_count, ==, 1);
     213    g_assert_nonnull (tmp_weak);
     214  
     215    g_assert ((g_set_object) (&o, NULL));
     216    g_assert (o == NULL);
     217    g_assert_null (tmp_weak);
     218  }
     219  
     220  static void
     221  test_set_derived_type (void)
     222  {
     223    GBinding *obj = NULL;
     224    GObject *o = NULL;
     225    GBinding *b = NULL;
     226  
     227    g_test_summary ("Check that g_set_object() doesn’t give strict aliasing "
     228                    "warnings when used on types derived from GObject");
     229  
     230    g_assert_false (g_set_object (&o, NULL));
     231    g_assert_null (o);
     232  
     233    g_assert_false (g_set_object (&b, NULL));
     234    g_assert_null (b);
     235  
     236    obj = g_object_new (my_object_get_type (), NULL);
     237  
     238    g_assert_true (g_set_object (&o, G_OBJECT (obj)));
     239    g_assert_true (o == G_OBJECT (obj));
     240  
     241    g_assert_true (g_set_object (&b, obj));
     242    g_assert_true (b == obj);
     243  
     244    g_object_unref (obj);
     245    g_clear_object (&b);
     246    g_clear_object (&o);
     247  }
     248  
     249  static void
     250  toggle_cb (gpointer data, GObject *obj, gboolean is_last)
     251  {
     252    gboolean *b = data;
     253  
     254    *b = TRUE;
     255  }
     256  
     257  static void
     258  test_object_value (void)
     259  {
     260    GObject *v;
     261    GObject *v2;
     262    GValue value = G_VALUE_INIT;
     263    gboolean toggled = FALSE;
     264  
     265    g_value_init (&value, G_TYPE_OBJECT);
     266  
     267    v = g_object_new (G_TYPE_OBJECT, NULL);
     268    g_object_add_toggle_ref (v, toggle_cb, &toggled);
     269  
     270    g_value_take_object (&value, v);
     271  
     272    v2 = g_value_get_object (&value);
     273    g_assert (v2 == v);
     274  
     275    v2 = g_value_dup_object (&value);
     276    g_assert (v2 == v);  /* objects use ref/unref for copy/free */
     277    g_object_unref (v2);
     278  
     279    g_assert (!toggled);
     280    g_value_unset (&value);
     281    g_assert (toggled);
     282  
     283    /* test the deprecated variant too */
     284    g_value_init (&value, G_TYPE_OBJECT);
     285    /* get a new reference */
     286    g_object_ref (v);
     287  
     288  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     289    g_value_set_object_take_ownership (&value, v);
     290  G_GNUC_END_IGNORE_DEPRECATIONS
     291  
     292    toggled = FALSE;
     293    g_value_unset (&value);
     294    g_assert (toggled);
     295  
     296    g_object_remove_toggle_ref (v, toggle_cb, &toggled);
     297  }
     298  
     299  static void
     300  test_initially_unowned (void)
     301  {
     302    GObject *obj;
     303  
     304    obj = g_object_new (G_TYPE_INITIALLY_UNOWNED, NULL);
     305    g_assert (g_object_is_floating (obj));
     306    g_assert_cmpint (obj->ref_count, ==, 1);
     307  
     308    g_object_ref_sink (obj);
     309    g_assert (!g_object_is_floating (obj));
     310    g_assert_cmpint (obj->ref_count, ==, 1);
     311  
     312    g_object_ref_sink (obj);
     313    g_assert (!g_object_is_floating (obj));
     314    g_assert_cmpint (obj->ref_count, ==, 2);
     315  
     316    g_object_unref (obj);
     317    g_assert_cmpint (obj->ref_count, ==, 1);
     318  
     319    g_object_force_floating (obj);
     320    g_assert (g_object_is_floating (obj));
     321    g_assert_cmpint (obj->ref_count, ==, 1);
     322  
     323    g_object_ref_sink (obj);
     324    g_object_unref (obj);
     325  
     326    obj = g_object_new (G_TYPE_INITIALLY_UNOWNED, NULL);
     327    g_assert_true (g_object_is_floating (obj));
     328    g_assert_cmpint (obj->ref_count, ==, 1);
     329  
     330    g_object_take_ref (obj);
     331    g_assert_false (g_object_is_floating (obj));
     332    g_assert_cmpint (obj->ref_count, ==, 1);
     333  
     334    g_object_take_ref (obj);
     335    g_assert_false (g_object_is_floating (obj));
     336    g_assert_cmpint (obj->ref_count, ==, 1);
     337  
     338    g_object_unref (obj);
     339  
     340    if (g_test_undefined ())
     341      {
     342        obj = g_object_new (G_TYPE_INITIALLY_UNOWNED, NULL);
     343  
     344  #ifdef G_ENABLE_DEBUG
     345        g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
     346                               "A floating object GInitiallyUnowned * was finalized*");
     347  #endif
     348        g_object_unref (obj);
     349  #ifdef G_ENABLE_DEBUG
     350        g_test_assert_expected_messages ();
     351  #endif
     352      }
     353  }
     354  
     355  static void
     356  test_weak_pointer (void)
     357  {
     358    GObject *obj;
     359    gpointer weak;
     360    gpointer weak2;
     361  
     362    weak = weak2 = obj = g_object_new (G_TYPE_OBJECT, NULL);
     363    g_assert_cmpint (obj->ref_count, ==, 1);
     364  
     365    g_object_add_weak_pointer (obj, &weak);
     366    g_object_add_weak_pointer (obj, &weak2);
     367    g_assert_cmpint (obj->ref_count, ==, 1);
     368    g_assert (weak == obj);
     369    g_assert (weak2 == obj);
     370  
     371    g_object_remove_weak_pointer (obj, &weak2);
     372    g_assert_cmpint (obj->ref_count, ==, 1);
     373    g_assert (weak == obj);
     374    g_assert (weak2 == obj);
     375  
     376    g_object_unref (obj);
     377    g_assert (weak == NULL);
     378    g_assert (weak2 == obj);
     379  }
     380  
     381  static void
     382  test_weak_pointer_clear (void)
     383  {
     384    GObject *obj;
     385    gpointer weak = NULL;
     386  
     387    g_clear_weak_pointer (&weak);
     388    g_assert_null (weak);
     389  
     390    weak = obj = g_object_new (G_TYPE_OBJECT, NULL);
     391    g_assert_cmpint (obj->ref_count, ==, 1);
     392  
     393    g_object_add_weak_pointer (obj, &weak);
     394    g_assert_cmpint (obj->ref_count, ==, 1);
     395    g_assert_true (weak == obj);
     396  
     397    g_clear_weak_pointer (&weak);
     398    g_assert_cmpint (obj->ref_count, ==, 1);
     399    g_assert_null (weak);
     400  
     401    g_object_unref (obj);
     402  }
     403  
     404  static void
     405  test_weak_pointer_clear_function (void)
     406  {
     407    GObject *obj;
     408    gpointer weak = NULL;
     409  
     410    (g_clear_weak_pointer) (&weak);
     411    g_assert_null (weak);
     412  
     413    weak = obj = g_object_new (G_TYPE_OBJECT, NULL);
     414    g_assert_cmpint (obj->ref_count, ==, 1);
     415  
     416    g_object_add_weak_pointer (obj, &weak);
     417    g_assert_cmpint (obj->ref_count, ==, 1);
     418    g_assert_true (weak == obj);
     419  
     420    (g_clear_weak_pointer) (&weak);
     421    g_assert_cmpint (obj->ref_count, ==, 1);
     422    g_assert_null (weak);
     423  
     424    g_object_unref (obj);
     425  }
     426  
     427  static void
     428  test_weak_pointer_set (void)
     429  {
     430    GObject *obj;
     431    gpointer weak = NULL;
     432  
     433    g_assert_false (g_set_weak_pointer (&weak, NULL));
     434    g_assert_null (weak);
     435  
     436    obj = g_object_new (G_TYPE_OBJECT, NULL);
     437    g_assert_cmpint (obj->ref_count, ==, 1);
     438  
     439    g_assert_true (g_set_weak_pointer (&weak, obj));
     440    g_assert_cmpint (obj->ref_count, ==, 1);
     441    g_assert_true (weak == obj);
     442  
     443    g_assert_true (g_set_weak_pointer (&weak, NULL));
     444    g_assert_cmpint (obj->ref_count, ==, 1);
     445    g_assert_null (weak);
     446  
     447    g_assert_true (g_set_weak_pointer (&weak, obj));
     448    g_assert_cmpint (obj->ref_count, ==, 1);
     449    g_assert_true (weak == obj);
     450  
     451    g_object_unref (obj);
     452    g_assert_null (weak);
     453  }
     454  
     455  static void
     456  test_weak_pointer_set_function (void)
     457  {
     458    GObject *obj;
     459    gpointer weak = NULL;
     460  
     461    g_assert_false ((g_set_weak_pointer) (&weak, NULL));
     462    g_assert_null (weak);
     463  
     464    obj = g_object_new (G_TYPE_OBJECT, NULL);
     465    g_assert_cmpint (obj->ref_count, ==, 1);
     466  
     467    g_assert_true ((g_set_weak_pointer) (&weak, obj));
     468    g_assert_cmpint (obj->ref_count, ==, 1);
     469    g_assert_true (weak == obj);
     470  
     471    g_assert_true ((g_set_weak_pointer) (&weak, NULL));
     472    g_assert_cmpint (obj->ref_count, ==, 1);
     473    g_assert_null (weak);
     474  
     475    g_assert_true ((g_set_weak_pointer) (&weak, obj));
     476    g_assert_cmpint (obj->ref_count, ==, 1);
     477    g_assert_true (weak == obj);
     478  
     479    g_object_unref (obj);
     480    g_assert_null (weak);
     481  }
     482  
     483  /* See gobject/tests/threadtests.c for the threaded version */
     484  static void
     485  test_weak_ref (void)
     486  {
     487    GObject *obj;
     488    GObject *obj2;
     489    GObject *tmp;
     490    GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
     491    GWeakRef weak2 = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
     492    GWeakRef weak3 = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
     493    GWeakRef *dynamic_weak = g_new (GWeakRef, 1);
     494  
     495    /* you can initialize to empty like this... */
     496    g_weak_ref_init (&weak2, NULL);
     497    g_assert (g_weak_ref_get (&weak2) == NULL);
     498  
     499    /* ... or via an initializer */
     500    g_weak_ref_init (&weak3, NULL);
     501    g_assert (g_weak_ref_get (&weak3) == NULL);
     502  
     503    obj = g_object_new (G_TYPE_OBJECT, NULL);
     504    g_assert_cmpint (obj->ref_count, ==, 1);
     505  
     506    obj2 = g_object_new (G_TYPE_OBJECT, NULL);
     507    g_assert_cmpint (obj2->ref_count, ==, 1);
     508  
     509    /* you can init with an object (even if uninitialized) */
     510    g_weak_ref_init (&weak, obj);
     511    g_weak_ref_init (dynamic_weak, obj);
     512    /* or set to point at an object, if initialized (maybe to 0) */
     513    g_weak_ref_set (&weak2, obj);
     514    g_weak_ref_set (&weak3, obj);
     515    /* none of this affects its refcount */
     516    g_assert_cmpint (obj->ref_count, ==, 1);
     517  
     518    /* getting the value takes a ref */
     519    tmp = g_weak_ref_get (&weak);
     520    g_assert (tmp == obj);
     521    g_assert_cmpint (obj->ref_count, ==, 2);
     522    g_object_unref (tmp);
     523    g_assert_cmpint (obj->ref_count, ==, 1);
     524  
     525    tmp = g_weak_ref_get (&weak2);
     526    g_assert (tmp == obj);
     527    g_assert_cmpint (obj->ref_count, ==, 2);
     528    g_object_unref (tmp);
     529    g_assert_cmpint (obj->ref_count, ==, 1);
     530  
     531    tmp = g_weak_ref_get (&weak3);
     532    g_assert (tmp == obj);
     533    g_assert_cmpint (obj->ref_count, ==, 2);
     534    g_object_unref (tmp);
     535    g_assert_cmpint (obj->ref_count, ==, 1);
     536  
     537    tmp = g_weak_ref_get (dynamic_weak);
     538    g_assert (tmp == obj);
     539    g_assert_cmpint (obj->ref_count, ==, 2);
     540    g_object_unref (tmp);
     541    g_assert_cmpint (obj->ref_count, ==, 1);
     542  
     543    /* clearing a weak ref stops tracking */
     544    g_weak_ref_clear (&weak);
     545  
     546    /* setting a weak ref to NULL stops tracking too */
     547    g_weak_ref_set (&weak2, NULL);
     548    g_assert (g_weak_ref_get (&weak2) == NULL);
     549    g_weak_ref_clear (&weak2);
     550  
     551    /* setting a weak ref to a new object stops tracking the old one */
     552    g_weak_ref_set (dynamic_weak, obj2);
     553    tmp = g_weak_ref_get (dynamic_weak);
     554    g_assert (tmp == obj2);
     555    g_assert_cmpint (obj2->ref_count, ==, 2);
     556    g_object_unref (tmp);
     557    g_assert_cmpint (obj2->ref_count, ==, 1);
     558  
     559    g_assert_cmpint (obj->ref_count, ==, 1);
     560  
     561    /* free the object: weak3 is the only one left pointing there */
     562    g_object_unref (obj);
     563    g_assert (g_weak_ref_get (&weak3) == NULL);
     564  
     565    /* setting a weak ref to a new object stops tracking the old one */
     566    g_weak_ref_set (dynamic_weak, obj2);
     567    tmp = g_weak_ref_get (dynamic_weak);
     568    g_assert (tmp == obj2);
     569    g_assert_cmpint (obj2->ref_count, ==, 2);
     570    g_object_unref (tmp);
     571    g_assert_cmpint (obj2->ref_count, ==, 1);
     572  
     573    g_weak_ref_clear (&weak3);
     574  
     575    /* unset dynamic_weak... */
     576    g_weak_ref_set (dynamic_weak, NULL);
     577    g_assert_null (g_weak_ref_get (dynamic_weak));
     578  
     579    /* initializing a weak reference to an object that had before works */
     580    g_weak_ref_set (dynamic_weak, obj2);
     581    tmp = g_weak_ref_get (dynamic_weak);
     582    g_assert_true (tmp == obj2);
     583    g_assert_cmpint (obj2->ref_count, ==, 2);
     584    g_object_unref (tmp);
     585    g_assert_cmpint (obj2->ref_count, ==, 1);
     586  
     587    /* clear and free dynamic_weak... */
     588    g_weak_ref_clear (dynamic_weak);
     589  
     590    /* ... to prove that doing so stops this from being a use-after-free */
     591    g_object_unref (obj2);
     592    g_free (dynamic_weak);
     593  }
     594  
     595  G_DECLARE_FINAL_TYPE (WeakReffedObject, weak_reffed_object,
     596                        WEAK, REFFED_OBJECT, GObject)
     597  
     598  struct _WeakReffedObject
     599  {
     600    GObject parent;
     601  
     602    GWeakRef *weak_ref;
     603  };
     604  
     605  G_DEFINE_TYPE (WeakReffedObject, weak_reffed_object, G_TYPE_OBJECT)
     606  
     607  static void
     608  weak_reffed_object_dispose (GObject *object)
     609  {
     610    WeakReffedObject *weak_reffed = WEAK_REFFED_OBJECT (object);
     611  
     612    g_assert_cmpint (object->ref_count, ==, 1);
     613  
     614    g_weak_ref_set (weak_reffed->weak_ref, object);
     615  
     616    G_OBJECT_CLASS (weak_reffed_object_parent_class)->dispose (object);
     617  
     618    g_assert_null (g_weak_ref_get (weak_reffed->weak_ref));
     619  }
     620  
     621  static void
     622  weak_reffed_object_init (WeakReffedObject *connector)
     623  {
     624  }
     625  
     626  static void
     627  weak_reffed_object_class_init (WeakReffedObjectClass *klass)
     628  {
     629    GObjectClass *object_class = G_OBJECT_CLASS (klass);
     630  
     631    object_class->dispose = weak_reffed_object_dispose;
     632  }
     633  
     634  static void
     635  test_weak_ref_on_dispose (void)
     636  {
     637    WeakReffedObject *obj;
     638    GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
     639  
     640    g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2390");
     641    g_test_summary ("Test that a weak ref set during dispose vfunc is cleared");
     642  
     643    g_weak_ref_init (&weak, NULL);
     644  
     645    obj = g_object_new (weak_reffed_object_get_type (), NULL);
     646    obj->weak_ref = &weak;
     647  
     648    g_assert_cmpint (G_OBJECT (obj)->ref_count, ==, 1);
     649    g_clear_object (&obj);
     650  
     651    g_assert_null (g_weak_ref_get (&weak));
     652  }
     653  
     654  static void
     655  test_weak_ref_on_run_dispose (void)
     656  {
     657    GObject *obj;
     658    GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
     659  
     660    g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/865");
     661    g_test_summary ("Test that a weak ref is cleared on g_object_run_dispose()");
     662  
     663    obj = g_object_new (G_TYPE_OBJECT, NULL);
     664    g_weak_ref_init (&weak, obj);
     665  
     666    g_assert_true (obj == g_weak_ref_get (&weak));
     667    g_object_unref (obj);
     668  
     669    g_object_run_dispose (obj);
     670    g_assert_null (g_weak_ref_get (&weak));
     671  
     672    g_clear_object (&obj);
     673    g_assert_null (g_weak_ref_get (&weak));
     674  }
     675  
     676  static void
     677  on_weak_ref_toggle_notify (gpointer data,
     678                             GObject *object,
     679                             gboolean is_last_ref)
     680  {
     681    GWeakRef *weak = data;
     682  
     683    if (is_last_ref)
     684      g_weak_ref_set (weak, object);
     685  }
     686  
     687  static void
     688  on_weak_ref_toggle_notify_disposed (gpointer data,
     689                                      GObject *object)
     690  {
     691    g_assert_cmpint (object->ref_count, ==, 1);
     692  
     693    g_object_ref (object);
     694    g_object_unref (object);
     695  }
     696  
     697  static void
     698  test_weak_ref_on_toggle_notify (void)
     699  {
     700    GObject *obj;
     701    GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
     702  
     703    g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2390");
     704    g_test_summary ("Test that a weak ref set on toggle notify is cleared");
     705  
     706    g_weak_ref_init (&weak, NULL);
     707  
     708    obj = g_object_new (G_TYPE_OBJECT, NULL);
     709    g_object_add_toggle_ref (obj, on_weak_ref_toggle_notify, &weak);
     710    g_object_weak_ref (obj, on_weak_ref_toggle_notify_disposed, NULL);
     711    g_object_unref (obj);
     712  
     713    g_assert_cmpint (obj->ref_count, ==, 1);
     714    g_clear_object (&obj);
     715  
     716    g_assert_null (g_weak_ref_get (&weak));
     717  }
     718  
     719  typedef struct
     720  {
     721    gboolean should_be_last;
     722    gint count;
     723  } Count;
     724  
     725  static void
     726  toggle_notify (gpointer  data,
     727                 GObject  *obj,
     728                 gboolean  is_last)
     729  {
     730    Count *c = data;
     731  
     732    g_assert (is_last == c->should_be_last);
     733  
     734    if (is_last)
     735      g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 1);
     736    else
     737      g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 2);
     738  
     739    c->count++;
     740  }
     741  
     742  static void
     743  test_toggle_ref (void)
     744  {
     745    GObject *obj;
     746    Count c, c2;
     747  
     748    obj = g_object_new (G_TYPE_OBJECT, NULL);
     749  
     750    g_object_add_toggle_ref (obj, toggle_notify, &c);
     751    g_object_add_toggle_ref (obj, toggle_notify, &c2);
     752  
     753    c.should_be_last = c2.should_be_last = TRUE;
     754    c.count = c2.count = 0;
     755  
     756    g_object_unref (obj);
     757  
     758    g_assert_cmpint (c.count, ==, 0);
     759    g_assert_cmpint (c2.count, ==, 0);
     760  
     761    g_object_ref (obj);
     762  
     763    g_assert_cmpint (c.count, ==, 0);
     764    g_assert_cmpint (c2.count, ==, 0);
     765  
     766    g_object_remove_toggle_ref (obj, toggle_notify, &c2);
     767  
     768    g_object_unref (obj);
     769  
     770    g_assert_cmpint (c.count, ==, 1);
     771  
     772    c.should_be_last = FALSE;
     773  
     774    g_object_ref (obj);
     775  
     776    g_assert_cmpint (c.count, ==, 2);
     777  
     778    c.should_be_last = TRUE;
     779  
     780    g_object_unref (obj);
     781  
     782    g_assert_cmpint (c.count, ==, 3);
     783  
     784    g_object_remove_toggle_ref (obj, toggle_notify, &c);
     785  }
     786  
     787  G_DECLARE_FINAL_TYPE (DisposeReffingObject, dispose_reffing_object,
     788                        DISPOSE, REFFING_OBJECT, GObject)
     789  
     790  typedef enum
     791  {
     792    PROP_INT_PROP = 1,
     793    N_PROPS,
     794  } DisposeReffingObjectProperty;
     795  
     796  static GParamSpec *dispose_reffing_object_properties[N_PROPS] = {0};
     797  
     798  struct _DisposeReffingObject
     799  {
     800    GObject parent;
     801  
     802    GToggleNotify toggle_notify;
     803    Count actual;
     804    Count expected;
     805    unsigned disposing_refs;
     806    gboolean disposing_refs_all_normal;
     807  
     808    GCallback notify_handler;
     809    unsigned notify_called;
     810  
     811    int int_prop;
     812  
     813    GWeakRef *weak_ref;
     814  };
     815  
     816  G_DEFINE_TYPE (DisposeReffingObject, dispose_reffing_object, G_TYPE_OBJECT)
     817  
     818  static void
     819  on_object_notify (GObject    *object,
     820                    GParamSpec *pspec,
     821                    void       *data)
     822  {
     823    DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
     824  
     825    obj->notify_called++;
     826  }
     827  
     828  static void
     829  dispose_reffing_object_dispose (GObject *object)
     830  {
     831    DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
     832  
     833    g_assert_cmpint (object->ref_count, ==, 1);
     834    g_assert_cmpint (obj->actual.count, ==, obj->expected.count);
     835  
     836    for (unsigned i = 0; i < obj->disposing_refs; ++i)
     837      {
     838        if (i == 0 && !obj->disposing_refs_all_normal)
     839          {
     840            g_object_add_toggle_ref (object, obj->toggle_notify, &obj->actual);
     841          }
     842        else
     843          {
     844            obj->actual.should_be_last = FALSE;
     845            g_object_ref (obj);
     846            g_assert_cmpint (obj->actual.count, ==, obj->expected.count);
     847          }
     848  
     849        obj->actual.should_be_last = TRUE;
     850      }
     851  
     852    G_OBJECT_CLASS (dispose_reffing_object_parent_class)->dispose (object);
     853  
     854    if (obj->notify_handler)
     855      {
     856        unsigned old_notify_called = obj->notify_called;
     857  
     858        g_assert_cmpuint (g_signal_handler_find (object, G_SIGNAL_MATCH_FUNC,
     859                          0, 0, NULL, obj->notify_handler, NULL), ==, 0);
     860  
     861        g_signal_connect (object, "notify", G_CALLBACK (obj->notify_handler), NULL);
     862  
     863        /* This would trigger a toggle notification, but is not something we may
     864         * want with https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2377
     865         * so, we only test this in case we have more than one ref
     866         */
     867        if (obj->toggle_notify == toggle_notify)
     868          g_assert_cmpint (obj->disposing_refs, >, 1);
     869  
     870        g_object_notify (object, "int-prop");
     871        g_assert_cmpuint (obj->notify_called, ==, old_notify_called);
     872      }
     873  
     874    g_assert_cmpint (obj->actual.count, ==, obj->expected.count);
     875  }
     876  
     877  static void
     878  dispose_reffing_object_init (DisposeReffingObject *connector)
     879  {
     880  }
     881  
     882  static void
     883  dispose_reffing_object_set_property (GObject *object,
     884                                       guint property_id,
     885                                       const GValue *value,
     886                                       GParamSpec *pspec)
     887  {
     888    DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
     889  
     890    switch ((DisposeReffingObjectProperty) property_id)
     891      {
     892      case PROP_INT_PROP:
     893        obj->int_prop = g_value_get_int (value);
     894        break;
     895      default:
     896        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     897        break;
     898      }
     899  }
     900  
     901  static void
     902  dispose_reffing_object_get_property (GObject *object,
     903                                       guint property_id,
     904                                       GValue *value,
     905                                       GParamSpec *pspec)
     906  {
     907    DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
     908  
     909    switch ((DisposeReffingObjectProperty) property_id)
     910      {
     911      case PROP_INT_PROP:
     912        g_value_set_int (value, obj->int_prop);
     913        break;
     914      default:
     915        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     916        break;
     917      }
     918  }
     919  
     920  static void
     921  dispose_reffing_object_class_init (DisposeReffingObjectClass *klass)
     922  {
     923    GObjectClass *object_class = G_OBJECT_CLASS (klass);
     924  
     925    dispose_reffing_object_properties[PROP_INT_PROP] =
     926        g_param_spec_int ("int-prop", "int-prop", "int-prop",
     927                          G_MININT, G_MAXINT,
     928                          0,
     929                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     930  
     931    object_class->dispose = dispose_reffing_object_dispose;
     932    object_class->set_property = dispose_reffing_object_set_property;
     933    object_class->get_property = dispose_reffing_object_get_property;
     934  
     935    g_object_class_install_properties (object_class, N_PROPS,
     936                                       dispose_reffing_object_properties);
     937  }
     938  
     939  static void
     940  test_toggle_ref_on_dispose (void)
     941  {
     942    DisposeReffingObject *obj;
     943    gpointer disposed_checker = &obj;
     944  
     945    /* This tests wants to ensure that an object that gets re-referenced
     946     * (one or multiple times) during its dispose virtual function:
     947     *  - Notifies all the queued "notify" signal handlers
     948     *  - Notifies toggle notifications if any
     949     *  - It does not get finalized
     950     */
     951  
     952    obj = g_object_new (dispose_reffing_object_get_type (), NULL);
     953    obj->toggle_notify = toggle_notify;
     954    obj->notify_handler = G_CALLBACK (on_object_notify);
     955    g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
     956  
     957    /* Convert to toggle notification */
     958    g_object_add_toggle_ref (G_OBJECT (obj), obj->toggle_notify, &obj->actual);
     959    g_assert_cmpint (obj->actual.count, ==, 0);
     960  
     961    obj->actual.should_be_last = TRUE;
     962    obj->notify_handler = G_CALLBACK (on_object_notify);
     963    g_object_unref (obj);
     964    g_assert_cmpint (obj->actual.count, ==, 1);
     965    g_assert_cmpuint (obj->notify_called, ==, 0);
     966  
     967    /* Remove the toggle reference, making it to dispose and resurrect again */
     968    obj->disposing_refs = 1;
     969    obj->expected.count = 1;
     970    obj->notify_handler = NULL; /* FIXME: enable it when !2377 is in */
     971    g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
     972    g_assert_cmpint (obj->actual.count, ==, 2);
     973    g_assert_cmpuint (obj->notify_called, ==, 0);
     974  
     975    g_assert_null (disposed_checker);
     976    g_assert_cmpint (g_atomic_int_get (&G_OBJECT (obj)->ref_count), ==,
     977                     obj->disposing_refs);
     978  
     979    /* Object has been disposed, but is still alive, so add another weak pointer */
     980    disposed_checker = &obj;
     981    g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
     982  
     983    /* Remove the toggle reference, making it to dispose and resurrect with
     984     * more references than before, so that no toggle notify is called
     985     */
     986    obj->disposing_refs = 3;
     987    obj->expected.count = 2;
     988    obj->notify_handler = G_CALLBACK (on_object_notify);
     989    g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
     990    g_assert_cmpint (obj->actual.count, ==, 2);
     991    g_assert_cmpint (obj->notify_called, ==, 1);
     992    obj->expected.count = obj->actual.count;
     993  
     994    g_assert_null (disposed_checker);
     995    g_assert_cmpint (g_atomic_int_get (&G_OBJECT (obj)->ref_count), ==,
     996                     obj->disposing_refs);
     997  
     998    disposed_checker = &obj;
     999    g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
    1000  
    1001    /* Now remove the first added reference */
    1002    obj->disposing_refs = 0;
    1003    g_object_unref (obj);
    1004    g_assert_nonnull (disposed_checker);
    1005    g_assert_cmpint (g_atomic_int_get (&G_OBJECT (obj)->ref_count), ==, 2);
    1006    g_assert_cmpint (obj->actual.count, ==, 2);
    1007    g_assert_cmpint (obj->notify_called, ==, 1);
    1008  
    1009    /* And the toggle one */
    1010    obj->actual.should_be_last = TRUE;
    1011    obj->notify_handler = NULL;
    1012    g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
    1013    g_assert_nonnull (disposed_checker);
    1014    g_assert_cmpint (g_atomic_int_get (&G_OBJECT (obj)->ref_count), ==, 1);
    1015    g_assert_cmpint (obj->actual.count, ==, 2);
    1016    obj->expected.count = obj->actual.count;
    1017  
    1018    g_clear_object (&obj);
    1019    g_assert_null (disposed_checker);
    1020  }
    1021  
    1022  static void
    1023  toggle_notify_counter (gpointer  data,
    1024                         GObject  *obj,
    1025                         gboolean  is_last)
    1026  {
    1027    Count *c = data;
    1028    c->count++;
    1029  
    1030    if (is_last)
    1031      g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 1);
    1032    else
    1033      g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 2);
    1034  }
    1035  
    1036  static void
    1037  on_object_notify_switch_to_normal_ref (GObject    *object,
    1038                                         GParamSpec *pspec,
    1039                                         void       *data)
    1040  {
    1041    DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
    1042  
    1043    obj->notify_called++;
    1044  
    1045    g_object_ref (object);
    1046    g_object_remove_toggle_ref (object, obj->toggle_notify, NULL);
    1047  }
    1048  
    1049  static void
    1050  on_object_notify_switch_to_toggle_ref (GObject    *object,
    1051                                         GParamSpec *pspec,
    1052                                         void       *data)
    1053  {
    1054    DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
    1055  
    1056    obj->notify_called++;
    1057  
    1058    g_object_add_toggle_ref (object, obj->toggle_notify, &obj->actual);
    1059    g_object_unref (object);
    1060  }
    1061  
    1062  static void
    1063  on_object_notify_add_ref (GObject    *object,
    1064                            GParamSpec *pspec,
    1065                            void       *data)
    1066  {
    1067    DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
    1068    int old_toggle_cout = obj->actual.count;
    1069  
    1070    obj->notify_called++;
    1071  
    1072    g_object_ref (object);
    1073    g_assert_cmpint (obj->actual.count, ==, old_toggle_cout);
    1074  }
    1075  
    1076  static void
    1077  test_toggle_ref_and_notify_on_dispose (void)
    1078  {
    1079    DisposeReffingObject *obj;
    1080    gpointer disposed_checker = &obj;
    1081  
    1082    /* This tests wants to ensure that toggle signal emission during dispose
    1083     * is properly working if the object is revitalized by adding new references.
    1084     * It also wants to check that toggle notifications are not happening if a
    1085     * notify handler is removing them at this phase.
    1086     */
    1087  
    1088    obj = g_object_new (dispose_reffing_object_get_type (), NULL);
    1089    obj->toggle_notify = toggle_notify_counter;
    1090    g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
    1091  
    1092    /* Convert to toggle notification */
    1093    g_object_add_toggle_ref (G_OBJECT (obj), obj->toggle_notify, &obj->actual);
    1094    g_assert_cmpint (obj->actual.count, ==, 0);
    1095  
    1096    obj->notify_handler = G_CALLBACK (on_object_notify);
    1097    g_object_unref (obj);
    1098    g_assert_cmpint (obj->actual.count, ==, 1);
    1099    g_assert_cmpuint (obj->notify_called, ==, 0);
    1100  
    1101    disposed_checker = &obj;
    1102    g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
    1103  
    1104    /* Check that notification is triggered after being queued */
    1105    obj->disposing_refs = 1;
    1106    obj->expected.count = 1;
    1107    obj->notify_handler = G_CALLBACK (on_object_notify);
    1108    g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
    1109     /* FIXME: adjust the count to 1 when !2377 is in */
    1110    g_assert_cmpint (obj->actual.count, ==, 4);
    1111    g_assert_cmpuint (obj->notify_called, ==, 1);
    1112  
    1113    disposed_checker = &obj;
    1114    g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
    1115  
    1116    /* Check that notification is triggered after being queued, but no toggle
    1117     * notification is happening if notify handler switches to normal reference
    1118     */
    1119    obj->disposing_refs = 1;
    1120    obj->expected.count = 4;
    1121    obj->notify_handler = G_CALLBACK (on_object_notify_switch_to_normal_ref);
    1122    g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
    1123    g_assert_cmpint (obj->actual.count, ==, 5);
    1124    g_assert_cmpuint (obj->notify_called, ==, 2);
    1125  
    1126    disposed_checker = &obj;
    1127    g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
    1128  
    1129    /* Check that notification is triggered after being queued, but that toggle
    1130     * is happening if notify handler switched to toggle reference
    1131     */
    1132    obj->disposing_refs = 1;
    1133    obj->disposing_refs_all_normal = TRUE;
    1134    obj->expected.count = 5;
    1135    obj->notify_handler = G_CALLBACK (on_object_notify_switch_to_toggle_ref);
    1136    g_object_unref (obj);
    1137    g_assert_cmpint (obj->actual.count, ==, 7);
    1138    g_assert_cmpuint (obj->notify_called, ==, 3);
    1139  
    1140    disposed_checker = &obj;
    1141    g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
    1142  
    1143    /* Check that notification is triggered after being queued, but that toggle
    1144     * is not happening if current refcount changed.
    1145     */
    1146    obj->disposing_refs = 1;
    1147    obj->disposing_refs_all_normal = FALSE;
    1148    obj->expected.count = 7;
    1149    obj->notify_handler = G_CALLBACK (on_object_notify_add_ref);
    1150    g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
    1151    g_assert_cmpint (obj->actual.count, ==, 8);
    1152    g_assert_cmpuint (obj->notify_called, ==, 4);
    1153    g_object_unref (obj);
    1154  
    1155    disposed_checker = &obj;
    1156    g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
    1157  
    1158    obj->disposing_refs = 0;
    1159    obj->expected.count = 9;
    1160    g_clear_object (&obj);
    1161    g_assert_null (disposed_checker);
    1162  }
    1163  
    1164  static gboolean global_destroyed;
    1165  static gint global_value;
    1166  
    1167  static void
    1168  data_destroy (gpointer data)
    1169  {
    1170    g_assert_cmpint (GPOINTER_TO_INT (data), ==, global_value);
    1171  
    1172    global_destroyed = TRUE;
    1173  }
    1174  
    1175  static void
    1176  test_object_qdata (void)
    1177  {
    1178    GObject *obj;
    1179    gpointer v;
    1180    GQuark quark;
    1181  
    1182    obj = g_object_new (G_TYPE_OBJECT, NULL);
    1183  
    1184    global_value = 1;
    1185    global_destroyed = FALSE;
    1186    g_object_set_data_full (obj, "test", GINT_TO_POINTER (1), data_destroy);
    1187    v = g_object_get_data (obj, "test");
    1188    g_assert_cmpint (GPOINTER_TO_INT (v), ==, 1);
    1189    g_object_set_data_full (obj, "test", GINT_TO_POINTER (2), data_destroy);
    1190    g_assert (global_destroyed);
    1191    global_value = 2;
    1192    global_destroyed = FALSE;
    1193    v = g_object_steal_data (obj, "test");
    1194    g_assert_cmpint (GPOINTER_TO_INT (v), ==, 2);
    1195    g_assert (!global_destroyed);
    1196  
    1197    global_value = 1;
    1198    global_destroyed = FALSE;
    1199    quark = g_quark_from_string ("test");
    1200    g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (1), data_destroy);
    1201    v = g_object_get_qdata (obj, quark);
    1202    g_assert_cmpint (GPOINTER_TO_INT (v), ==, 1);
    1203    g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (2), data_destroy);
    1204    g_assert (global_destroyed);
    1205    global_value = 2;
    1206    global_destroyed = FALSE;
    1207    v = g_object_steal_qdata (obj, quark);
    1208    g_assert_cmpint (GPOINTER_TO_INT (v), ==, 2);
    1209    g_assert (!global_destroyed);
    1210  
    1211    g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (3), data_destroy);
    1212    global_value = 3;
    1213    global_destroyed = FALSE;
    1214    g_object_unref (obj);
    1215  
    1216    g_assert (global_destroyed);
    1217  }
    1218  
    1219  typedef struct {
    1220    const gchar *value;
    1221    gint refcount;
    1222  } Value;
    1223  
    1224  static gpointer
    1225  ref_value (gpointer value, gpointer user_data)
    1226  {
    1227    Value *v = value;
    1228    Value **old_value_p = user_data;
    1229  
    1230    if (old_value_p)
    1231      *old_value_p = v;
    1232  
    1233    if (v)
    1234      v->refcount += 1;
    1235  
    1236    return value;
    1237  }
    1238  
    1239  static void
    1240  unref_value (gpointer value)
    1241  {
    1242    Value *v = value;
    1243  
    1244    v->refcount -= 1;
    1245    if (v->refcount == 0)
    1246      g_free (value);
    1247  }
    1248  
    1249  static
    1250  Value *
    1251  new_value (const gchar *s)
    1252  {
    1253    Value *v;
    1254  
    1255    v = g_new (Value, 1);
    1256    v->value = s;
    1257    v->refcount = 1;
    1258  
    1259    return v;
    1260  }
    1261  
    1262  static void
    1263  test_object_qdata2 (void)
    1264  {
    1265    GObject *obj;
    1266    Value *v, *v1, *v2, *v3, *old_val;
    1267    GDestroyNotify old_destroy;
    1268    gboolean res;
    1269  
    1270    obj = g_object_new (G_TYPE_OBJECT, NULL);
    1271  
    1272    v1 = new_value ("bla");
    1273  
    1274    g_object_set_data_full (obj, "test", v1, unref_value);
    1275  
    1276    v = g_object_get_data (obj, "test");
    1277    g_assert_cmpstr (v->value, ==, "bla");
    1278    g_assert_cmpint (v->refcount, ==, 1);
    1279  
    1280    v = g_object_dup_data (obj, "test", ref_value, &old_val);
    1281    g_assert (old_val == v1);
    1282    g_assert_cmpstr (v->value, ==, "bla");
    1283    g_assert_cmpint (v->refcount, ==, 2);
    1284    unref_value (v);
    1285  
    1286    v = g_object_dup_data (obj, "nono", ref_value, &old_val);
    1287    g_assert (old_val == NULL);
    1288    g_assert (v == NULL);
    1289  
    1290    v2 = new_value ("not");
    1291  
    1292    res = g_object_replace_data (obj, "test", v1, v2, unref_value, &old_destroy);
    1293    g_assert (res == TRUE);
    1294    g_assert (old_destroy == unref_value);
    1295    g_assert_cmpstr (v1->value, ==, "bla");
    1296    g_assert_cmpint (v1->refcount, ==, 1);
    1297  
    1298    v = g_object_get_data (obj, "test");
    1299    g_assert_cmpstr (v->value, ==, "not");
    1300    g_assert_cmpint (v->refcount, ==, 1);
    1301  
    1302    v3 = new_value ("xyz");
    1303    res = g_object_replace_data (obj, "test", v1, v3, unref_value, &old_destroy);
    1304    g_assert (res == FALSE);
    1305    g_assert_cmpstr (v2->value, ==, "not");
    1306    g_assert_cmpint (v2->refcount, ==, 1);
    1307  
    1308    unref_value (v1);
    1309  
    1310    res = g_object_replace_data (obj, "test", NULL, v3, unref_value, &old_destroy);
    1311    g_assert (res == FALSE);
    1312    g_assert_cmpstr (v2->value, ==, "not");
    1313    g_assert_cmpint (v2->refcount, ==, 1);
    1314  
    1315    res = g_object_replace_data (obj, "test", v2, NULL, unref_value, &old_destroy);
    1316    g_assert (res == TRUE);
    1317    g_assert (old_destroy == unref_value);
    1318    g_assert_cmpstr (v2->value, ==, "not");
    1319    g_assert_cmpint (v2->refcount, ==, 1);
    1320  
    1321    unref_value (v2);
    1322  
    1323    v = g_object_get_data (obj, "test");
    1324    g_assert (v == NULL);
    1325  
    1326    res = g_object_replace_data (obj, "test", NULL, v3, unref_value, &old_destroy);
    1327    g_assert (res == TRUE);
    1328  
    1329    v = g_object_get_data (obj, "test");
    1330    g_assert (v == v3);
    1331  
    1332    ref_value (v3, NULL);
    1333    g_assert_cmpint (v3->refcount, ==, 2);
    1334    g_object_unref (obj);
    1335    g_assert_cmpint (v3->refcount, ==, 1);
    1336    unref_value (v3);
    1337  }
    1338  
    1339  int
    1340  main (int argc, char **argv)
    1341  {
    1342    g_test_init (&argc, &argv, NULL);
    1343  
    1344    g_setenv ("G_ENABLE_DIAGNOSTIC", "1", TRUE);
    1345  
    1346    g_test_add_func ("/type/fundamentals", test_fundamentals);
    1347    g_test_add_func ("/type/qdata", test_type_qdata);
    1348    g_test_add_func ("/type/query", test_type_query);
    1349    g_test_add_func ("/type/class-private", test_class_private);
    1350    g_test_add_func ("/object/clear", test_clear);
    1351    g_test_add_func ("/object/clear-function", test_clear_function);
    1352    g_test_add_func ("/object/set", test_set);
    1353    g_test_add_func ("/object/set-function", test_set_function);
    1354    g_test_add_func ("/object/set/derived-type", test_set_derived_type);
    1355    g_test_add_func ("/object/value", test_object_value);
    1356    g_test_add_func ("/object/initially-unowned", test_initially_unowned);
    1357    g_test_add_func ("/object/weak-pointer", test_weak_pointer);
    1358    g_test_add_func ("/object/weak-pointer/clear", test_weak_pointer_clear);
    1359    g_test_add_func ("/object/weak-pointer/clear-function", test_weak_pointer_clear_function);
    1360    g_test_add_func ("/object/weak-pointer/set", test_weak_pointer_set);
    1361    g_test_add_func ("/object/weak-pointer/set-function", test_weak_pointer_set_function);
    1362    g_test_add_func ("/object/weak-ref", test_weak_ref);
    1363    g_test_add_func ("/object/weak-ref/on-dispose", test_weak_ref_on_dispose);
    1364    g_test_add_func ("/object/weak-ref/on-run-dispose", test_weak_ref_on_run_dispose);
    1365    g_test_add_func ("/object/weak-ref/on-toggle-notify", test_weak_ref_on_toggle_notify);
    1366    g_test_add_func ("/object/toggle-ref", test_toggle_ref);
    1367    g_test_add_func ("/object/toggle-ref/ref-on-dispose", test_toggle_ref_on_dispose);
    1368    g_test_add_func ("/object/toggle-ref/ref-and-notify-on-dispose", test_toggle_ref_and_notify_on_dispose);
    1369    g_test_add_func ("/object/qdata", test_object_qdata);
    1370    g_test_add_func ("/object/qdata2", test_object_qdata2);
    1371  
    1372    return g_test_run ();
    1373  }