cleanup
[platform/upstream/glib.git] / 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   volatile 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 toggle_cb (gpointer data, GObject *obj, gboolean is_last)
156 {
157   gboolean *b = data;
158
159   *b = TRUE;
160 }
161
162 static void
163 test_object_value (void)
164 {
165   GObject *v;
166   GObject *v2;
167   GValue value = G_VALUE_INIT;
168   gboolean toggled = FALSE;
169
170   g_value_init (&value, G_TYPE_OBJECT);
171
172   v = g_object_new (G_TYPE_OBJECT, NULL);
173   g_object_add_toggle_ref (v, toggle_cb, &toggled);
174
175   g_value_take_object (&value, v);
176
177   v2 = g_value_get_object (&value);
178   g_assert (v2 == v);
179
180   v2 = g_value_dup_object (&value);
181   g_assert (v2 == v);  /* objects use ref/unref for copy/free */
182   g_object_unref (v2);
183
184   g_assert (!toggled);
185   g_value_unset (&value);
186   g_assert (toggled);
187
188   /* test the deprecated variant too */
189   g_value_init (&value, G_TYPE_OBJECT);
190   /* get a new reference */
191   g_object_ref (v);
192
193 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
194   g_value_set_object_take_ownership (&value, v);
195 G_GNUC_END_IGNORE_DEPRECATIONS
196
197   toggled = FALSE;
198   g_value_unset (&value);
199   g_assert (toggled);
200
201   g_object_remove_toggle_ref (v, toggle_cb, &toggled);
202 }
203
204 static void
205 test_initially_unowned (void)
206 {
207   GObject *obj;
208
209   obj = g_object_new (G_TYPE_INITIALLY_UNOWNED, NULL);
210   g_assert (g_object_is_floating (obj));
211   g_assert_cmpint (obj->ref_count, ==, 1);
212
213   g_object_ref_sink (obj);
214   g_assert (!g_object_is_floating (obj));
215   g_assert_cmpint (obj->ref_count, ==, 1);
216
217   g_object_ref_sink (obj);
218   g_assert (!g_object_is_floating (obj));
219   g_assert_cmpint (obj->ref_count, ==, 2);
220
221   g_object_unref (obj);
222   g_assert_cmpint (obj->ref_count, ==, 1);
223
224   g_object_force_floating (obj);
225   g_assert (g_object_is_floating (obj));
226   g_assert_cmpint (obj->ref_count, ==, 1);
227
228   g_object_ref_sink (obj);
229   g_object_unref (obj);
230 }
231
232 static void
233 test_weak_pointer (void)
234 {
235   GObject *obj;
236   gpointer weak;
237   gpointer weak2;
238
239   weak = weak2 = obj = g_object_new (G_TYPE_OBJECT, NULL);
240   g_assert_cmpint (obj->ref_count, ==, 1);
241
242   g_object_add_weak_pointer (obj, &weak);
243   g_object_add_weak_pointer (obj, &weak2);
244   g_assert_cmpint (obj->ref_count, ==, 1);
245   g_assert (weak == obj);
246   g_assert (weak2 == obj);
247
248   g_object_remove_weak_pointer (obj, &weak2);
249   g_assert_cmpint (obj->ref_count, ==, 1);
250   g_assert (weak == obj);
251   g_assert (weak2 == obj);
252
253   g_object_unref (obj);
254   g_assert (weak == NULL);
255   g_assert (weak2 == obj);
256 }
257
258 /* See gobject/tests/threadtests.c for the threaded version */
259 static void
260 test_weak_ref (void)
261 {
262   GObject *obj;
263   GObject *obj2;
264   GObject *tmp;
265   GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
266   GWeakRef weak2 = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
267   GWeakRef weak3 = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
268   GWeakRef *dynamic_weak = g_new (GWeakRef, 1);
269
270   /* you can initialize to empty like this... */
271   g_weak_ref_init (&weak2, NULL);
272   g_assert (g_weak_ref_get (&weak2) == NULL);
273
274   /* ... or via an initializer */
275   g_weak_ref_init (&weak3, NULL);
276   g_assert (g_weak_ref_get (&weak3) == NULL);
277
278   obj = g_object_new (G_TYPE_OBJECT, NULL);
279   g_assert_cmpint (obj->ref_count, ==, 1);
280
281   obj2 = g_object_new (G_TYPE_OBJECT, NULL);
282   g_assert_cmpint (obj2->ref_count, ==, 1);
283
284   /* you can init with an object (even if uninitialized) */
285   g_weak_ref_init (&weak, obj);
286   g_weak_ref_init (dynamic_weak, obj);
287   /* or set to point at an object, if initialized (maybe to 0) */
288   g_weak_ref_set (&weak2, obj);
289   g_weak_ref_set (&weak3, obj);
290   /* none of this affects its refcount */
291   g_assert_cmpint (obj->ref_count, ==, 1);
292
293   /* getting the value takes a ref */
294   tmp = g_weak_ref_get (&weak);
295   g_assert (tmp == obj);
296   g_assert_cmpint (obj->ref_count, ==, 2);
297   g_object_unref (tmp);
298   g_assert_cmpint (obj->ref_count, ==, 1);
299
300   tmp = g_weak_ref_get (&weak2);
301   g_assert (tmp == obj);
302   g_assert_cmpint (obj->ref_count, ==, 2);
303   g_object_unref (tmp);
304   g_assert_cmpint (obj->ref_count, ==, 1);
305
306   tmp = g_weak_ref_get (&weak3);
307   g_assert (tmp == obj);
308   g_assert_cmpint (obj->ref_count, ==, 2);
309   g_object_unref (tmp);
310   g_assert_cmpint (obj->ref_count, ==, 1);
311
312   tmp = g_weak_ref_get (dynamic_weak);
313   g_assert (tmp == obj);
314   g_assert_cmpint (obj->ref_count, ==, 2);
315   g_object_unref (tmp);
316   g_assert_cmpint (obj->ref_count, ==, 1);
317
318   /* clearing a weak ref stops tracking */
319   g_weak_ref_clear (&weak);
320
321   /* setting a weak ref to NULL stops tracking too */
322   g_weak_ref_set (&weak2, NULL);
323   g_assert (g_weak_ref_get (&weak2) == NULL);
324   g_weak_ref_clear (&weak2);
325
326   /* setting a weak ref to a new object stops tracking the old one */
327   g_weak_ref_set (dynamic_weak, obj2);
328   tmp = g_weak_ref_get (dynamic_weak);
329   g_assert (tmp == obj2);
330   g_assert_cmpint (obj2->ref_count, ==, 2);
331   g_object_unref (tmp);
332   g_assert_cmpint (obj2->ref_count, ==, 1);
333
334   g_assert_cmpint (obj->ref_count, ==, 1);
335
336   /* free the object: weak3 is the only one left pointing there */
337   g_object_unref (obj);
338   g_assert (g_weak_ref_get (&weak3) == NULL);
339
340   /* setting a weak ref to a new object stops tracking the old one */
341   g_weak_ref_set (dynamic_weak, obj2);
342   tmp = g_weak_ref_get (dynamic_weak);
343   g_assert (tmp == obj2);
344   g_assert_cmpint (obj2->ref_count, ==, 2);
345   g_object_unref (tmp);
346   g_assert_cmpint (obj2->ref_count, ==, 1);
347
348   g_weak_ref_clear (&weak3);
349
350   /* clear and free dynamic_weak... */
351   g_weak_ref_clear (dynamic_weak);
352
353   /* ... to prove that doing so stops this from being a use-after-free */
354   g_object_unref (obj2);
355   g_free (dynamic_weak);
356 }
357
358 typedef struct
359 {
360   gboolean should_be_last;
361   gint count;
362 } Count;
363
364 static void
365 toggle_notify (gpointer  data,
366                GObject  *obj,
367                gboolean  is_last)
368 {
369   Count *c = data;
370
371   g_assert (is_last == c->should_be_last);
372
373   c->count++;
374 }
375
376 static void
377 test_toggle_ref (void)
378 {
379   GObject *obj;
380   Count c, c2;
381
382   obj = g_object_new (G_TYPE_OBJECT, NULL);
383
384   g_object_add_toggle_ref (obj, toggle_notify, &c);
385   g_object_add_toggle_ref (obj, toggle_notify, &c2);
386
387   c.should_be_last = c2.should_be_last = TRUE;
388   c.count = c2.count = 0;
389
390   g_object_unref (obj);
391
392   g_assert_cmpint (c.count, ==, 0);
393   g_assert_cmpint (c2.count, ==, 0);
394
395   g_object_ref (obj);
396
397   g_assert_cmpint (c.count, ==, 0);
398   g_assert_cmpint (c2.count, ==, 0);
399
400   g_object_remove_toggle_ref (obj, toggle_notify, &c2);
401
402   g_object_unref (obj);
403
404   g_assert_cmpint (c.count, ==, 1);
405
406   c.should_be_last = FALSE;
407
408   g_object_ref (obj);
409
410   g_assert_cmpint (c.count, ==, 2);
411
412   c.should_be_last = TRUE;
413
414   g_object_unref (obj);
415
416   g_assert_cmpint (c.count, ==, 3);
417
418   g_object_remove_toggle_ref (obj, toggle_notify, &c);
419 }
420
421 static gboolean destroyed;
422 static gint value;
423
424 static void
425 data_destroy (gpointer data)
426 {
427   g_assert_cmpint (GPOINTER_TO_INT (data), ==, value);
428
429   destroyed = TRUE;
430 }
431
432 static void
433 test_object_qdata (void)
434 {
435   GObject *obj;
436   gpointer v;
437   GQuark quark;
438
439   obj = g_object_new (G_TYPE_OBJECT, NULL);
440
441   value = 1;
442   destroyed = FALSE;
443   g_object_set_data_full (obj, "test", GINT_TO_POINTER (1), data_destroy);
444   v = g_object_get_data (obj, "test");
445   g_assert_cmpint (GPOINTER_TO_INT (v), ==, 1);
446   g_object_set_data_full (obj, "test", GINT_TO_POINTER (2), data_destroy);
447   g_assert (destroyed);
448   value = 2;
449   destroyed = FALSE;
450   v = g_object_steal_data (obj, "test");
451   g_assert_cmpint (GPOINTER_TO_INT (v), ==, 2);
452   g_assert (!destroyed);
453
454   value = 1;
455   destroyed = FALSE;
456   quark = g_quark_from_string ("test");
457   g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (1), data_destroy);
458   v = g_object_get_qdata (obj, quark);
459   g_assert_cmpint (GPOINTER_TO_INT (v), ==, 1);
460   g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (2), data_destroy);
461   g_assert (destroyed);
462   value = 2;
463   destroyed = FALSE;
464   v = g_object_steal_qdata (obj, quark);
465   g_assert_cmpint (GPOINTER_TO_INT (v), ==, 2);
466   g_assert (!destroyed);
467
468   g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (3), data_destroy);
469   value = 3;
470   destroyed = FALSE;
471   g_object_unref (obj);
472
473   g_assert (destroyed);
474 }
475
476 typedef struct {
477   const gchar *value;
478   gint refcount;
479 } Value;
480
481 static gpointer
482 ref_value (gpointer value, gpointer user_data)
483 {
484   Value *v = value;
485   Value **old_value_p = user_data;
486
487   if (old_value_p)
488     *old_value_p = v;
489
490   if (v)
491     v->refcount += 1;
492
493   return value;
494 }
495
496 static void
497 unref_value (gpointer value)
498 {
499   Value *v = value;
500
501   v->refcount -= 1;
502   if (v->refcount == 0)
503     g_free (value);
504 }
505
506 static
507 Value *
508 new_value (const gchar *s)
509 {
510   Value *v;
511
512   v = g_new (Value, 1);
513   v->value = s;
514   v->refcount = 1;
515
516   return v;
517 }
518
519 static void
520 test_object_qdata2 (void)
521 {
522   GObject *obj;
523   Value *v, *v1, *v2, *v3, *old_val;
524   GDestroyNotify old_destroy;
525   gboolean res;
526
527   obj = g_object_new (G_TYPE_OBJECT, NULL);
528
529   v1 = new_value ("bla");
530
531   g_object_set_data_full (obj, "test", v1, unref_value);
532
533   v = g_object_get_data (obj, "test");
534   g_assert_cmpstr (v->value, ==, "bla");
535   g_assert_cmpint (v->refcount, ==, 1);
536
537   v = g_object_dup_data (obj, "test", ref_value, &old_val);
538   g_assert (old_val == v1);
539   g_assert_cmpstr (v->value, ==, "bla");
540   g_assert_cmpint (v->refcount, ==, 2);
541   unref_value (v);
542
543   v = g_object_dup_data (obj, "nono", ref_value, &old_val);
544   g_assert (old_val == NULL);
545   g_assert (v == NULL);
546
547   v2 = new_value ("not");
548
549   res = g_object_replace_data (obj, "test", v1, v2, unref_value, &old_destroy);
550   g_assert (res == TRUE);
551   g_assert (old_destroy == unref_value);
552   g_assert_cmpstr (v1->value, ==, "bla");
553   g_assert_cmpint (v1->refcount, ==, 1);
554
555   v = g_object_get_data (obj, "test");
556   g_assert_cmpstr (v->value, ==, "not");
557   g_assert_cmpint (v->refcount, ==, 1);
558
559   v3 = new_value ("xyz");
560   res = g_object_replace_data (obj, "test", v1, v3, unref_value, &old_destroy);
561   g_assert (res == FALSE);
562   g_assert_cmpstr (v2->value, ==, "not");
563   g_assert_cmpint (v2->refcount, ==, 1);
564
565   unref_value (v1);
566
567   res = g_object_replace_data (obj, "test", NULL, v3, unref_value, &old_destroy);
568   g_assert (res == FALSE);
569   g_assert_cmpstr (v2->value, ==, "not");
570   g_assert_cmpint (v2->refcount, ==, 1);
571
572   res = g_object_replace_data (obj, "test", v2, NULL, unref_value, &old_destroy);
573   g_assert (res == TRUE);
574   g_assert (old_destroy == unref_value);
575   g_assert_cmpstr (v2->value, ==, "not");
576   g_assert_cmpint (v2->refcount, ==, 1);
577
578   unref_value (v2);
579
580   v = g_object_get_data (obj, "test");
581   g_assert (v == NULL);
582
583   res = g_object_replace_data (obj, "test", NULL, v3, unref_value, &old_destroy);
584   g_assert (res == TRUE);
585
586   v = g_object_get_data (obj, "test");
587   g_assert (v == v3);
588
589   ref_value (v3, NULL);
590   g_assert_cmpint (v3->refcount, ==, 2);
591   g_object_unref (obj);
592   g_assert_cmpint (v3->refcount, ==, 1);
593   unref_value (v3);
594 }
595
596 int
597 main (int argc, char **argv)
598 {
599   g_test_init (&argc, &argv, NULL);
600
601   g_test_add_func ("/type/fundamentals", test_fundamentals);
602   g_test_add_func ("/type/qdata", test_type_qdata);
603   g_test_add_func ("/type/query", test_type_query);
604   g_test_add_func ("/type/class-private", test_class_private);
605   g_test_add_func ("/object/clear", test_clear);
606   g_test_add_func ("/object/clear-function", test_clear_function);
607   g_test_add_func ("/object/value", test_object_value);
608   g_test_add_func ("/object/initially-unowned", test_initially_unowned);
609   g_test_add_func ("/object/weak-pointer", test_weak_pointer);
610   g_test_add_func ("/object/weak-ref", test_weak_ref);
611   g_test_add_func ("/object/toggle-ref", test_toggle_ref);
612   g_test_add_func ("/object/qdata", test_object_qdata);
613   g_test_add_func ("/object/qdata2", test_object_qdata2);
614
615   return g_test_run ();
616 }