1 #include <glib-object.h>
4 test_fundamentals (void)
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));
30 g_assert (g_type_fundamental_next () == G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST));
34 test_type_qdata (void)
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");
44 test_type_query (void)
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);
55 typedef struct _MyObject MyObject;
56 typedef struct _MyObjectClass MyObjectClass;
57 typedef struct _MyObjectClassPrivate MyObjectClassPrivate;
61 GObject parent_instance;
68 GObjectClass parent_class;
71 struct _MyObjectClassPrivate
73 gint secret_class_count;
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)) );
81 my_object_init (MyObject *obj)
87 my_object_class_init (MyObjectClass *klass)
92 test_class_private (void)
96 MyObjectClassPrivate *priv;
98 obj = g_object_new (my_object_get_type (), NULL);
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);
105 g_object_unref (obj);
107 g_assert_cmpint (g_type_qname (my_object_get_type ()), ==, g_quark_from_string ("MyObject"));
117 g_assert (o == NULL);
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);
124 g_assert_cmpint (tmp->ref_count, ==, 2);
126 g_assert_cmpint (tmp->ref_count, ==, 1);
127 g_assert (o == NULL);
129 g_object_unref (tmp);
133 test_clear_function (void)
138 (g_clear_object) (&o);
139 g_assert (o == NULL);
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);
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);
151 g_object_unref (tmp);
159 gpointer tmp_weak = NULL;
161 g_assert (!g_set_object (&o, NULL));
162 g_assert (o == NULL);
164 tmp = g_object_new (G_TYPE_OBJECT, NULL);
166 g_object_add_weak_pointer (tmp, &tmp_weak);
167 g_assert_cmpint (tmp->ref_count, ==, 1);
169 g_assert (g_set_object (&o, tmp));
171 g_assert_cmpint (tmp->ref_count, ==, 2);
173 g_object_unref (tmp);
174 g_assert_cmpint (tmp->ref_count, ==, 1);
176 /* Setting it again shouldn’t cause finalisation. */
177 g_assert (!g_set_object (&o, tmp));
179 g_assert_cmpint (tmp->ref_count, ==, 1);
180 g_assert_nonnull (tmp_weak);
182 g_assert (g_set_object (&o, NULL));
183 g_assert (o == NULL);
184 g_assert_null (tmp_weak);
188 test_set_function (void)
192 gpointer tmp_weak = NULL;
194 g_assert (!(g_set_object) (&o, NULL));
195 g_assert (o == NULL);
197 tmp = g_object_new (G_TYPE_OBJECT, NULL);
199 g_object_add_weak_pointer (tmp, &tmp_weak);
200 g_assert_cmpint (tmp->ref_count, ==, 1);
202 g_assert ((g_set_object) (&o, tmp));
204 g_assert_cmpint (tmp->ref_count, ==, 2);
206 g_object_unref (tmp);
207 g_assert_cmpint (tmp->ref_count, ==, 1);
209 /* Setting it again shouldn’t cause finalisation. */
210 g_assert (!(g_set_object) (&o, tmp));
212 g_assert_cmpint (tmp->ref_count, ==, 1);
213 g_assert_nonnull (tmp_weak);
215 g_assert ((g_set_object) (&o, NULL));
216 g_assert (o == NULL);
217 g_assert_null (tmp_weak);
221 test_set_derived_type (void)
223 GBinding *obj = NULL;
227 g_test_summary ("Check that g_set_object() doesn’t give strict aliasing "
228 "warnings when used on types derived from GObject");
230 g_assert_false (g_set_object (&o, NULL));
233 g_assert_false (g_set_object (&b, NULL));
236 obj = g_object_new (my_object_get_type (), NULL);
238 g_assert_true (g_set_object (&o, G_OBJECT (obj)));
239 g_assert_true (o == G_OBJECT (obj));
241 g_assert_true (g_set_object (&b, obj));
242 g_assert_true (b == obj);
244 g_object_unref (obj);
250 toggle_cb (gpointer data, GObject *obj, gboolean is_last)
258 test_object_value (void)
262 GValue value = G_VALUE_INIT;
263 gboolean toggled = FALSE;
265 g_value_init (&value, G_TYPE_OBJECT);
267 v = g_object_new (G_TYPE_OBJECT, NULL);
268 g_object_add_toggle_ref (v, toggle_cb, &toggled);
270 g_value_take_object (&value, v);
272 v2 = g_value_get_object (&value);
275 v2 = g_value_dup_object (&value);
276 g_assert (v2 == v); /* objects use ref/unref for copy/free */
280 g_value_unset (&value);
283 /* test the deprecated variant too */
284 g_value_init (&value, G_TYPE_OBJECT);
285 /* get a new reference */
288 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
289 g_value_set_object_take_ownership (&value, v);
290 G_GNUC_END_IGNORE_DEPRECATIONS
293 g_value_unset (&value);
296 g_object_remove_toggle_ref (v, toggle_cb, &toggled);
300 test_initially_unowned (void)
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);
308 g_object_ref_sink (obj);
309 g_assert (!g_object_is_floating (obj));
310 g_assert_cmpint (obj->ref_count, ==, 1);
312 g_object_ref_sink (obj);
313 g_assert (!g_object_is_floating (obj));
314 g_assert_cmpint (obj->ref_count, ==, 2);
316 g_object_unref (obj);
317 g_assert_cmpint (obj->ref_count, ==, 1);
319 g_object_force_floating (obj);
320 g_assert (g_object_is_floating (obj));
321 g_assert_cmpint (obj->ref_count, ==, 1);
323 g_object_ref_sink (obj);
324 g_object_unref (obj);
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);
330 g_object_take_ref (obj);
331 g_assert_false (g_object_is_floating (obj));
332 g_assert_cmpint (obj->ref_count, ==, 1);
334 g_object_take_ref (obj);
335 g_assert_false (g_object_is_floating (obj));
336 g_assert_cmpint (obj->ref_count, ==, 1);
338 g_object_unref (obj);
340 if (g_test_undefined ())
342 obj = g_object_new (G_TYPE_INITIALLY_UNOWNED, NULL);
344 #ifdef G_ENABLE_DEBUG
345 g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
346 "A floating object GInitiallyUnowned * was finalized*");
348 g_object_unref (obj);
349 #ifdef G_ENABLE_DEBUG
350 g_test_assert_expected_messages ();
356 test_weak_pointer (void)
362 weak = weak2 = obj = g_object_new (G_TYPE_OBJECT, NULL);
363 g_assert_cmpint (obj->ref_count, ==, 1);
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);
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);
376 g_object_unref (obj);
377 g_assert (weak == NULL);
378 g_assert (weak2 == obj);
382 test_weak_pointer_clear (void)
385 gpointer weak = NULL;
387 g_clear_weak_pointer (&weak);
388 g_assert_null (weak);
390 weak = obj = g_object_new (G_TYPE_OBJECT, NULL);
391 g_assert_cmpint (obj->ref_count, ==, 1);
393 g_object_add_weak_pointer (obj, &weak);
394 g_assert_cmpint (obj->ref_count, ==, 1);
395 g_assert_true (weak == obj);
397 g_clear_weak_pointer (&weak);
398 g_assert_cmpint (obj->ref_count, ==, 1);
399 g_assert_null (weak);
401 g_object_unref (obj);
405 test_weak_pointer_clear_function (void)
408 gpointer weak = NULL;
410 (g_clear_weak_pointer) (&weak);
411 g_assert_null (weak);
413 weak = obj = g_object_new (G_TYPE_OBJECT, NULL);
414 g_assert_cmpint (obj->ref_count, ==, 1);
416 g_object_add_weak_pointer (obj, &weak);
417 g_assert_cmpint (obj->ref_count, ==, 1);
418 g_assert_true (weak == obj);
420 (g_clear_weak_pointer) (&weak);
421 g_assert_cmpint (obj->ref_count, ==, 1);
422 g_assert_null (weak);
424 g_object_unref (obj);
428 test_weak_pointer_set (void)
431 gpointer weak = NULL;
433 g_assert_false (g_set_weak_pointer (&weak, NULL));
434 g_assert_null (weak);
436 obj = g_object_new (G_TYPE_OBJECT, NULL);
437 g_assert_cmpint (obj->ref_count, ==, 1);
439 g_assert_true (g_set_weak_pointer (&weak, obj));
440 g_assert_cmpint (obj->ref_count, ==, 1);
441 g_assert_true (weak == obj);
443 g_assert_true (g_set_weak_pointer (&weak, NULL));
444 g_assert_cmpint (obj->ref_count, ==, 1);
445 g_assert_null (weak);
447 g_assert_true (g_set_weak_pointer (&weak, obj));
448 g_assert_cmpint (obj->ref_count, ==, 1);
449 g_assert_true (weak == obj);
451 g_object_unref (obj);
452 g_assert_null (weak);
456 test_weak_pointer_set_function (void)
459 gpointer weak = NULL;
461 g_assert_false ((g_set_weak_pointer) (&weak, NULL));
462 g_assert_null (weak);
464 obj = g_object_new (G_TYPE_OBJECT, NULL);
465 g_assert_cmpint (obj->ref_count, ==, 1);
467 g_assert_true ((g_set_weak_pointer) (&weak, obj));
468 g_assert_cmpint (obj->ref_count, ==, 1);
469 g_assert_true (weak == obj);
471 g_assert_true ((g_set_weak_pointer) (&weak, NULL));
472 g_assert_cmpint (obj->ref_count, ==, 1);
473 g_assert_null (weak);
475 g_assert_true ((g_set_weak_pointer) (&weak, obj));
476 g_assert_cmpint (obj->ref_count, ==, 1);
477 g_assert_true (weak == obj);
479 g_object_unref (obj);
480 g_assert_null (weak);
483 /* See gobject/tests/threadtests.c for the threaded version */
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);
495 /* you can initialize to empty like this... */
496 g_weak_ref_init (&weak2, NULL);
497 g_assert (g_weak_ref_get (&weak2) == NULL);
499 /* ... or via an initializer */
500 g_weak_ref_init (&weak3, NULL);
501 g_assert (g_weak_ref_get (&weak3) == NULL);
503 obj = g_object_new (G_TYPE_OBJECT, NULL);
504 g_assert_cmpint (obj->ref_count, ==, 1);
506 obj2 = g_object_new (G_TYPE_OBJECT, NULL);
507 g_assert_cmpint (obj2->ref_count, ==, 1);
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);
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);
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);
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);
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);
543 /* clearing a weak ref stops tracking */
544 g_weak_ref_clear (&weak);
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);
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);
559 g_assert_cmpint (obj->ref_count, ==, 1);
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);
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);
573 g_weak_ref_clear (&weak3);
575 /* unset dynamic_weak... */
576 g_weak_ref_set (dynamic_weak, NULL);
577 g_assert_null (g_weak_ref_get (dynamic_weak));
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);
587 /* clear and free dynamic_weak... */
588 g_weak_ref_clear (dynamic_weak);
590 /* ... to prove that doing so stops this from being a use-after-free */
591 g_object_unref (obj2);
592 g_free (dynamic_weak);
595 G_DECLARE_FINAL_TYPE (WeakReffedObject, weak_reffed_object,
596 WEAK, REFFED_OBJECT, GObject)
598 struct _WeakReffedObject
605 G_DEFINE_TYPE (WeakReffedObject, weak_reffed_object, G_TYPE_OBJECT)
608 weak_reffed_object_dispose (GObject *object)
610 WeakReffedObject *weak_reffed = WEAK_REFFED_OBJECT (object);
612 g_assert_cmpint (object->ref_count, ==, 1);
614 g_weak_ref_set (weak_reffed->weak_ref, object);
616 G_OBJECT_CLASS (weak_reffed_object_parent_class)->dispose (object);
618 g_assert_null (g_weak_ref_get (weak_reffed->weak_ref));
622 weak_reffed_object_init (WeakReffedObject *connector)
627 weak_reffed_object_class_init (WeakReffedObjectClass *klass)
629 GObjectClass *object_class = G_OBJECT_CLASS (klass);
631 object_class->dispose = weak_reffed_object_dispose;
635 test_weak_ref_on_dispose (void)
637 WeakReffedObject *obj;
638 GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
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");
643 g_weak_ref_init (&weak, NULL);
645 obj = g_object_new (weak_reffed_object_get_type (), NULL);
646 obj->weak_ref = &weak;
648 g_assert_cmpint (G_OBJECT (obj)->ref_count, ==, 1);
649 g_clear_object (&obj);
651 g_assert_null (g_weak_ref_get (&weak));
655 test_weak_ref_on_run_dispose (void)
658 GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
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()");
663 obj = g_object_new (G_TYPE_OBJECT, NULL);
664 g_weak_ref_init (&weak, obj);
666 g_assert_true (obj == g_weak_ref_get (&weak));
667 g_object_unref (obj);
669 g_object_run_dispose (obj);
670 g_assert_null (g_weak_ref_get (&weak));
672 g_clear_object (&obj);
673 g_assert_null (g_weak_ref_get (&weak));
677 on_weak_ref_toggle_notify (gpointer data,
679 gboolean is_last_ref)
681 GWeakRef *weak = data;
684 g_weak_ref_set (weak, object);
688 on_weak_ref_toggle_notify_disposed (gpointer data,
691 g_assert_cmpint (object->ref_count, ==, 1);
693 g_object_ref (object);
694 g_object_unref (object);
698 test_weak_ref_on_toggle_notify (void)
701 GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
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");
706 g_weak_ref_init (&weak, NULL);
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);
713 g_assert_cmpint (obj->ref_count, ==, 1);
714 g_clear_object (&obj);
716 g_assert_null (g_weak_ref_get (&weak));
721 gboolean should_be_last;
726 toggle_notify (gpointer data,
732 g_assert (is_last == c->should_be_last);
735 g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 1);
737 g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 2);
743 test_toggle_ref (void)
748 obj = g_object_new (G_TYPE_OBJECT, NULL);
750 g_object_add_toggle_ref (obj, toggle_notify, &c);
751 g_object_add_toggle_ref (obj, toggle_notify, &c2);
753 c.should_be_last = c2.should_be_last = TRUE;
754 c.count = c2.count = 0;
756 g_object_unref (obj);
758 g_assert_cmpint (c.count, ==, 0);
759 g_assert_cmpint (c2.count, ==, 0);
763 g_assert_cmpint (c.count, ==, 0);
764 g_assert_cmpint (c2.count, ==, 0);
766 g_object_remove_toggle_ref (obj, toggle_notify, &c2);
768 g_object_unref (obj);
770 g_assert_cmpint (c.count, ==, 1);
772 c.should_be_last = FALSE;
776 g_assert_cmpint (c.count, ==, 2);
778 c.should_be_last = TRUE;
780 g_object_unref (obj);
782 g_assert_cmpint (c.count, ==, 3);
784 g_object_remove_toggle_ref (obj, toggle_notify, &c);
787 G_DECLARE_FINAL_TYPE (DisposeReffingObject, dispose_reffing_object,
788 DISPOSE, REFFING_OBJECT, GObject)
794 } DisposeReffingObjectProperty;
796 static GParamSpec *dispose_reffing_object_properties[N_PROPS] = {0};
798 struct _DisposeReffingObject
802 GToggleNotify toggle_notify;
805 unsigned disposing_refs;
806 gboolean disposing_refs_all_normal;
808 GCallback notify_handler;
809 unsigned notify_called;
816 G_DEFINE_TYPE (DisposeReffingObject, dispose_reffing_object, G_TYPE_OBJECT)
819 on_object_notify (GObject *object,
823 DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
825 obj->notify_called++;
829 dispose_reffing_object_dispose (GObject *object)
831 DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
833 g_assert_cmpint (object->ref_count, ==, 1);
834 g_assert_cmpint (obj->actual.count, ==, obj->expected.count);
836 for (unsigned i = 0; i < obj->disposing_refs; ++i)
838 if (i == 0 && !obj->disposing_refs_all_normal)
840 g_object_add_toggle_ref (object, obj->toggle_notify, &obj->actual);
844 obj->actual.should_be_last = FALSE;
846 g_assert_cmpint (obj->actual.count, ==, obj->expected.count);
849 obj->actual.should_be_last = TRUE;
852 G_OBJECT_CLASS (dispose_reffing_object_parent_class)->dispose (object);
854 if (obj->notify_handler)
856 unsigned old_notify_called = obj->notify_called;
858 g_assert_cmpuint (g_signal_handler_find (object, G_SIGNAL_MATCH_FUNC,
859 0, 0, NULL, obj->notify_handler, NULL), ==, 0);
861 g_signal_connect (object, "notify", G_CALLBACK (obj->notify_handler), NULL);
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
867 if (obj->toggle_notify == toggle_notify)
868 g_assert_cmpint (obj->disposing_refs, >, 1);
870 g_object_notify (object, "int-prop");
871 g_assert_cmpuint (obj->notify_called, ==, old_notify_called);
874 g_assert_cmpint (obj->actual.count, ==, obj->expected.count);
878 dispose_reffing_object_init (DisposeReffingObject *connector)
883 dispose_reffing_object_set_property (GObject *object,
888 DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
890 switch ((DisposeReffingObjectProperty) property_id)
893 obj->int_prop = g_value_get_int (value);
896 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
902 dispose_reffing_object_get_property (GObject *object,
907 DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
909 switch ((DisposeReffingObjectProperty) property_id)
912 g_value_set_int (value, obj->int_prop);
915 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
921 dispose_reffing_object_class_init (DisposeReffingObjectClass *klass)
923 GObjectClass *object_class = G_OBJECT_CLASS (klass);
925 dispose_reffing_object_properties[PROP_INT_PROP] =
926 g_param_spec_int ("int-prop", "int-prop", "int-prop",
929 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
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;
935 g_object_class_install_properties (object_class, N_PROPS,
936 dispose_reffing_object_properties);
940 test_toggle_ref_on_dispose (void)
942 DisposeReffingObject *obj;
943 gpointer disposed_checker = &obj;
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
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);
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);
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);
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);
975 g_assert_null (disposed_checker);
976 g_assert_cmpint (g_atomic_int_get (&G_OBJECT (obj)->ref_count), ==,
977 obj->disposing_refs);
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);
983 /* Remove the toggle reference, making it to dispose and resurrect with
984 * more references than before, so that no toggle notify is called
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;
994 g_assert_null (disposed_checker);
995 g_assert_cmpint (g_atomic_int_get (&G_OBJECT (obj)->ref_count), ==,
996 obj->disposing_refs);
998 disposed_checker = &obj;
999 g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
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);
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;
1018 g_clear_object (&obj);
1019 g_assert_null (disposed_checker);
1023 toggle_notify_counter (gpointer data,
1031 g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 1);
1033 g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 2);
1037 on_object_notify_switch_to_normal_ref (GObject *object,
1041 DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
1043 obj->notify_called++;
1045 g_object_ref (object);
1046 g_object_remove_toggle_ref (object, obj->toggle_notify, NULL);
1050 on_object_notify_switch_to_toggle_ref (GObject *object,
1054 DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
1056 obj->notify_called++;
1058 g_object_add_toggle_ref (object, obj->toggle_notify, &obj->actual);
1059 g_object_unref (object);
1063 on_object_notify_add_ref (GObject *object,
1067 DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
1068 int old_toggle_cout = obj->actual.count;
1070 obj->notify_called++;
1072 g_object_ref (object);
1073 g_assert_cmpint (obj->actual.count, ==, old_toggle_cout);
1077 test_toggle_ref_and_notify_on_dispose (void)
1079 DisposeReffingObject *obj;
1080 gpointer disposed_checker = &obj;
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.
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);
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);
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);
1101 disposed_checker = &obj;
1102 g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
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);
1113 disposed_checker = &obj;
1114 g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1116 /* Check that notification is triggered after being queued, but no toggle
1117 * notification is happening if notify handler switches to normal reference
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);
1126 disposed_checker = &obj;
1127 g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1129 /* Check that notification is triggered after being queued, but that toggle
1130 * is happening if notify handler switched to toggle reference
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);
1140 disposed_checker = &obj;
1141 g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1143 /* Check that notification is triggered after being queued, but that toggle
1144 * is not happening if current refcount changed.
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);
1155 disposed_checker = &obj;
1156 g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1158 obj->disposing_refs = 0;
1159 obj->expected.count = 9;
1160 g_clear_object (&obj);
1161 g_assert_null (disposed_checker);
1164 static gboolean global_destroyed;
1165 static gint global_value;
1168 data_destroy (gpointer data)
1170 g_assert_cmpint (GPOINTER_TO_INT (data), ==, global_value);
1172 global_destroyed = TRUE;
1176 test_object_qdata (void)
1182 obj = g_object_new (G_TYPE_OBJECT, NULL);
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);
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);
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);
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);
1211 g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (3), data_destroy);
1213 global_destroyed = FALSE;
1214 g_object_unref (obj);
1216 g_assert (global_destroyed);
1225 ref_value (gpointer value, gpointer user_data)
1228 Value **old_value_p = user_data;
1240 unref_value (gpointer value)
1245 if (v->refcount == 0)
1251 new_value (const gchar *s)
1255 v = g_new (Value, 1);
1263 test_object_qdata2 (void)
1266 Value *v, *v1, *v2, *v3, *old_val;
1267 GDestroyNotify old_destroy;
1270 obj = g_object_new (G_TYPE_OBJECT, NULL);
1272 v1 = new_value ("bla");
1274 g_object_set_data_full (obj, "test", v1, unref_value);
1276 v = g_object_get_data (obj, "test");
1277 g_assert_cmpstr (v->value, ==, "bla");
1278 g_assert_cmpint (v->refcount, ==, 1);
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);
1286 v = g_object_dup_data (obj, "nono", ref_value, &old_val);
1287 g_assert (old_val == NULL);
1288 g_assert (v == NULL);
1290 v2 = new_value ("not");
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);
1298 v = g_object_get_data (obj, "test");
1299 g_assert_cmpstr (v->value, ==, "not");
1300 g_assert_cmpint (v->refcount, ==, 1);
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);
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);
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);
1323 v = g_object_get_data (obj, "test");
1324 g_assert (v == NULL);
1326 res = g_object_replace_data (obj, "test", NULL, v3, unref_value, &old_destroy);
1327 g_assert (res == TRUE);
1329 v = g_object_get_data (obj, "test");
1332 ref_value (v3, NULL);
1333 g_assert_cmpint (v3->refcount, ==, 2);
1334 g_object_unref (obj);
1335 g_assert_cmpint (v3->refcount, ==, 1);
1340 main (int argc, char **argv)
1342 g_test_init (&argc, &argv, NULL);
1344 g_setenv ("G_ENABLE_DIAGNOSTIC", "1", TRUE);
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);
1372 return g_test_run ();