Branch data Line data Source code
1 : : #include <glib-object.h>
2 : :
3 : : static void
4 : 1 : 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 : 1 : g_assert (G_TYPE_OBJECT == g_object_get_type ());
27 : : g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_VARIANT));
28 : 1 : g_assert (G_TYPE_IS_DERIVED (G_TYPE_INITIALLY_UNOWNED));
29 : :
30 : 1 : g_assert (g_type_fundamental_next () == G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST));
31 : 1 : }
32 : :
33 : : static void
34 : 1 : test_type_qdata (void)
35 : : {
36 : : gchar *data;
37 : :
38 : 1 : g_type_set_qdata (G_TYPE_ENUM, g_quark_from_string ("bla"), "bla");
39 : 1 : data = g_type_get_qdata (G_TYPE_ENUM, g_quark_from_string ("bla"));
40 : 1 : g_assert_cmpstr (data, ==, "bla");
41 : 1 : }
42 : :
43 : : static void
44 : 1 : test_type_query (void)
45 : : {
46 : : GTypeQuery query;
47 : :
48 : 1 : g_type_query (G_TYPE_ENUM, &query);
49 : 1 : g_assert_cmpint (query.type, ==, G_TYPE_ENUM);
50 : 1 : g_assert_cmpstr (query.type_name, ==, "GEnum");
51 : 1 : g_assert_cmpint (query.class_size, ==, sizeof (GEnumClass));
52 : 1 : g_assert_cmpint (query.instance_size, ==, 0);
53 : 1 : }
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 : 7 : 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 : 2 : my_object_init (MyObject *obj)
82 : : {
83 : 2 : obj->count = 42;
84 : 2 : }
85 : :
86 : : static void
87 : 1 : my_object_class_init (MyObjectClass *klass)
88 : : {
89 : 1 : }
90 : :
91 : : static void
92 : 1 : test_class_private (void)
93 : : {
94 : : GObject *obj;
95 : : MyObjectClass *class;
96 : : MyObjectClassPrivate *priv;
97 : :
98 : 1 : obj = g_object_new (my_object_get_type (), NULL);
99 : :
100 : 1 : class = g_type_class_ref (my_object_get_type ());
101 : 1 : priv = G_TYPE_CLASS_GET_PRIVATE (class, my_object_get_type (), MyObjectClassPrivate);
102 : 1 : priv->secret_class_count = 13;
103 : 1 : g_type_class_unref (class);
104 : :
105 : 1 : g_object_unref (obj);
106 : :
107 : 1 : g_assert_cmpint (g_type_qname (my_object_get_type ()), ==, g_quark_from_string ("MyObject"));
108 : 1 : }
109 : :
110 : : static void
111 : 1 : test_clear (void)
112 : : {
113 : 1 : GObject *o = NULL;
114 : : GObject *tmp;
115 : :
116 : 1 : g_clear_object (&o);
117 : 1 : g_assert (o == NULL);
118 : :
119 : 1 : tmp = g_object_new (G_TYPE_OBJECT, NULL);
120 : 1 : g_assert_cmpint (tmp->ref_count, ==, 1);
121 : 1 : o = g_object_ref (tmp);
122 : 1 : g_assert (o != NULL);
123 : :
124 : 1 : g_assert_cmpint (tmp->ref_count, ==, 2);
125 : 1 : g_clear_object (&o);
126 : 1 : g_assert_cmpint (tmp->ref_count, ==, 1);
127 : 1 : g_assert (o == NULL);
128 : :
129 : 1 : g_object_unref (tmp);
130 : 1 : }
131 : :
132 : : static void
133 : 1 : test_clear_function (void)
134 : : {
135 : 1 : GObject *o = NULL;
136 : : GObject *tmp;
137 : :
138 : 1 : (g_clear_object) (&o);
139 : 1 : g_assert (o == NULL);
140 : :
141 : 1 : tmp = g_object_new (G_TYPE_OBJECT, NULL);
142 : 1 : g_assert_cmpint (tmp->ref_count, ==, 1);
143 : 1 : o = g_object_ref (tmp);
144 : 1 : g_assert (o != NULL);
145 : :
146 : 1 : g_assert_cmpint (tmp->ref_count, ==, 2);
147 : 1 : (g_clear_object) (&o);
148 : 1 : g_assert_cmpint (tmp->ref_count, ==, 1);
149 : 1 : g_assert (o == NULL);
150 : :
151 : 1 : g_object_unref (tmp);
152 : 1 : }
153 : :
154 : : static void
155 : 1 : test_set (void)
156 : : {
157 : 1 : GObject *o = NULL;
158 : : GObject *tmp;
159 : 1 : gpointer tmp_weak = NULL;
160 : :
161 : 1 : g_assert (!g_set_object (&o, NULL));
162 : 1 : g_assert (o == NULL);
163 : :
164 : 1 : tmp = g_object_new (G_TYPE_OBJECT, NULL);
165 : 1 : tmp_weak = tmp;
166 : 1 : g_object_add_weak_pointer (tmp, &tmp_weak);
167 : 1 : g_assert_cmpint (tmp->ref_count, ==, 1);
168 : :
169 : 1 : g_assert (g_set_object (&o, tmp));
170 : 1 : g_assert (o == tmp);
171 : 1 : g_assert_cmpint (tmp->ref_count, ==, 2);
172 : :
173 : 1 : g_object_unref (tmp);
174 : 1 : g_assert_cmpint (tmp->ref_count, ==, 1);
175 : :
176 : : /* Setting it again shouldn’t cause finalisation. */
177 : 1 : g_assert (!g_set_object (&o, tmp));
178 : 1 : g_assert (o == tmp);
179 : 1 : g_assert_cmpint (tmp->ref_count, ==, 1);
180 : 1 : g_assert_nonnull (tmp_weak);
181 : :
182 : 1 : g_assert (g_set_object (&o, NULL));
183 : 1 : g_assert (o == NULL);
184 : 1 : g_assert_null (tmp_weak);
185 : 1 : }
186 : :
187 : : static void
188 : 1 : test_set_function (void)
189 : : {
190 : 1 : GObject *o = NULL;
191 : : GObject *tmp;
192 : 1 : gpointer tmp_weak = NULL;
193 : :
194 : 1 : g_assert (!(g_set_object) (&o, NULL));
195 : 1 : g_assert (o == NULL);
196 : :
197 : 1 : tmp = g_object_new (G_TYPE_OBJECT, NULL);
198 : 1 : tmp_weak = tmp;
199 : 1 : g_object_add_weak_pointer (tmp, &tmp_weak);
200 : 1 : g_assert_cmpint (tmp->ref_count, ==, 1);
201 : :
202 : 1 : g_assert ((g_set_object) (&o, tmp));
203 : 1 : g_assert (o == tmp);
204 : 1 : g_assert_cmpint (tmp->ref_count, ==, 2);
205 : :
206 : 1 : g_object_unref (tmp);
207 : 1 : g_assert_cmpint (tmp->ref_count, ==, 1);
208 : :
209 : : /* Setting it again shouldn’t cause finalisation. */
210 : 1 : g_assert (!(g_set_object) (&o, tmp));
211 : 1 : g_assert (o == tmp);
212 : 1 : g_assert_cmpint (tmp->ref_count, ==, 1);
213 : 1 : g_assert_nonnull (tmp_weak);
214 : :
215 : 1 : g_assert ((g_set_object) (&o, NULL));
216 : 1 : g_assert (o == NULL);
217 : 1 : g_assert_null (tmp_weak);
218 : 1 : }
219 : :
220 : : static void
221 : 1 : test_set_derived_type (void)
222 : : {
223 : 1 : GBinding *obj = NULL;
224 : 1 : GObject *o = NULL;
225 : 1 : GBinding *b = NULL;
226 : :
227 : 1 : g_test_summary ("Check that g_set_object() doesn’t give strict aliasing "
228 : : "warnings when used on types derived from GObject");
229 : :
230 : 1 : g_assert_false (g_set_object (&o, NULL));
231 : 1 : g_assert_null (o);
232 : :
233 : 1 : g_assert_false (g_set_object (&b, NULL));
234 : 1 : g_assert_null (b);
235 : :
236 : 1 : obj = g_object_new (my_object_get_type (), NULL);
237 : :
238 : 1 : g_assert_true (g_set_object (&o, G_OBJECT (obj)));
239 : 1 : g_assert_true (o == G_OBJECT (obj));
240 : :
241 : 1 : g_assert_true (g_set_object (&b, obj));
242 : 1 : g_assert_true (b == obj);
243 : :
244 : 1 : g_object_unref (obj);
245 : 1 : g_clear_object (&b);
246 : 1 : g_clear_object (&o);
247 : 1 : }
248 : :
249 : : static void
250 : 3 : toggle_cb (gpointer data, GObject *obj, gboolean is_last)
251 : : {
252 : 3 : gboolean *b = data;
253 : :
254 : 3 : *b = TRUE;
255 : 3 : }
256 : :
257 : : static void
258 : 1 : test_object_value (void)
259 : : {
260 : : GObject *v;
261 : : GObject *v2;
262 : 1 : GValue value = G_VALUE_INIT;
263 : 1 : gboolean toggled = FALSE;
264 : :
265 : 1 : g_value_init (&value, G_TYPE_OBJECT);
266 : :
267 : 1 : v = g_object_new (G_TYPE_OBJECT, NULL);
268 : 1 : g_object_add_toggle_ref (v, toggle_cb, &toggled);
269 : :
270 : 1 : g_value_take_object (&value, v);
271 : :
272 : 1 : v2 = g_value_get_object (&value);
273 : 1 : g_assert (v2 == v);
274 : :
275 : 1 : v2 = g_value_dup_object (&value);
276 : 1 : g_assert (v2 == v); /* objects use ref/unref for copy/free */
277 : 1 : g_object_unref (v2);
278 : :
279 : 1 : g_assert (!toggled);
280 : 1 : g_value_unset (&value);
281 : 1 : g_assert (toggled);
282 : :
283 : : /* test the deprecated variant too */
284 : 1 : g_value_init (&value, G_TYPE_OBJECT);
285 : : /* get a new reference */
286 : 1 : g_object_ref (v);
287 : :
288 : : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
289 : 1 : g_value_set_object_take_ownership (&value, v);
290 : : G_GNUC_END_IGNORE_DEPRECATIONS
291 : :
292 : 1 : toggled = FALSE;
293 : 1 : g_value_unset (&value);
294 : 1 : g_assert (toggled);
295 : :
296 : 1 : g_object_remove_toggle_ref (v, toggle_cb, &toggled);
297 : 1 : }
298 : :
299 : : static void
300 : 1 : test_initially_unowned (void)
301 : : {
302 : : GObject *obj;
303 : :
304 : 1 : obj = g_object_new (G_TYPE_INITIALLY_UNOWNED, NULL);
305 : 1 : g_assert (g_object_is_floating (obj));
306 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
307 : :
308 : 1 : g_object_ref_sink (obj);
309 : 1 : g_assert (!g_object_is_floating (obj));
310 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
311 : :
312 : 1 : g_object_ref_sink (obj);
313 : 1 : g_assert (!g_object_is_floating (obj));
314 : 1 : g_assert_cmpint (obj->ref_count, ==, 2);
315 : :
316 : 1 : g_object_unref (obj);
317 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
318 : :
319 : 1 : g_object_force_floating (obj);
320 : 1 : g_assert (g_object_is_floating (obj));
321 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
322 : :
323 : 1 : g_object_ref_sink (obj);
324 : 1 : g_object_unref (obj);
325 : :
326 : 1 : obj = g_object_new (G_TYPE_INITIALLY_UNOWNED, NULL);
327 : 1 : g_assert_true (g_object_is_floating (obj));
328 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
329 : :
330 : 1 : g_object_take_ref (obj);
331 : 1 : g_assert_false (g_object_is_floating (obj));
332 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
333 : :
334 : 1 : g_object_take_ref (obj);
335 : 1 : g_assert_false (g_object_is_floating (obj));
336 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
337 : :
338 : 1 : g_object_unref (obj);
339 : :
340 : 1 : if (g_test_undefined ())
341 : : {
342 : 1 : obj = g_object_new (G_TYPE_INITIALLY_UNOWNED, NULL);
343 : :
344 : : #ifdef G_ENABLE_DEBUG
345 : 1 : g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
346 : : "A floating object GInitiallyUnowned * was finalized*");
347 : : #endif
348 : 1 : g_object_unref (obj);
349 : : #ifdef G_ENABLE_DEBUG
350 : 1 : g_test_assert_expected_messages ();
351 : : #endif
352 : : }
353 : 1 : }
354 : :
355 : : static void
356 : 1 : test_weak_pointer (void)
357 : : {
358 : : GObject *obj;
359 : : gpointer weak;
360 : : gpointer weak2;
361 : :
362 : 1 : weak = weak2 = obj = g_object_new (G_TYPE_OBJECT, NULL);
363 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
364 : :
365 : 1 : g_object_add_weak_pointer (obj, &weak);
366 : 1 : g_object_add_weak_pointer (obj, &weak2);
367 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
368 : 1 : g_assert (weak == obj);
369 : 1 : g_assert (weak2 == obj);
370 : :
371 : 1 : g_object_remove_weak_pointer (obj, &weak2);
372 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
373 : 1 : g_assert (weak == obj);
374 : 1 : g_assert (weak2 == obj);
375 : :
376 : 1 : g_object_unref (obj);
377 : 1 : g_assert (weak == NULL);
378 : 1 : g_assert (weak2 == obj);
379 : 1 : }
380 : :
381 : : static void
382 : 1 : test_weak_pointer_clear (void)
383 : : {
384 : : GObject *obj;
385 : 1 : gpointer weak = NULL;
386 : :
387 : 1 : g_clear_weak_pointer (&weak);
388 : 1 : g_assert_null (weak);
389 : :
390 : 1 : weak = obj = g_object_new (G_TYPE_OBJECT, NULL);
391 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
392 : :
393 : 1 : g_object_add_weak_pointer (obj, &weak);
394 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
395 : 1 : g_assert_true (weak == obj);
396 : :
397 : 1 : g_clear_weak_pointer (&weak);
398 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
399 : 1 : g_assert_null (weak);
400 : :
401 : 1 : g_object_unref (obj);
402 : 1 : }
403 : :
404 : : static void
405 : 1 : test_weak_pointer_clear_function (void)
406 : : {
407 : : GObject *obj;
408 : 1 : gpointer weak = NULL;
409 : :
410 : 1 : (g_clear_weak_pointer) (&weak);
411 : 1 : g_assert_null (weak);
412 : :
413 : 1 : weak = obj = g_object_new (G_TYPE_OBJECT, NULL);
414 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
415 : :
416 : 1 : g_object_add_weak_pointer (obj, &weak);
417 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
418 : 1 : g_assert_true (weak == obj);
419 : :
420 : 1 : (g_clear_weak_pointer) (&weak);
421 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
422 : 1 : g_assert_null (weak);
423 : :
424 : 1 : g_object_unref (obj);
425 : 1 : }
426 : :
427 : : static void
428 : 1 : test_weak_pointer_set (void)
429 : : {
430 : : GObject *obj;
431 : 1 : gpointer weak = NULL;
432 : :
433 : 1 : g_assert_false (g_set_weak_pointer (&weak, NULL));
434 : 1 : g_assert_null (weak);
435 : :
436 : 1 : obj = g_object_new (G_TYPE_OBJECT, NULL);
437 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
438 : :
439 : 1 : g_assert_true (g_set_weak_pointer (&weak, obj));
440 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
441 : 1 : g_assert_true (weak == obj);
442 : :
443 : 1 : g_assert_true (g_set_weak_pointer (&weak, NULL));
444 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
445 : 1 : g_assert_null (weak);
446 : :
447 : 1 : g_assert_true (g_set_weak_pointer (&weak, obj));
448 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
449 : 1 : g_assert_true (weak == obj);
450 : :
451 : 1 : g_object_unref (obj);
452 : 1 : g_assert_null (weak);
453 : 1 : }
454 : :
455 : : static void
456 : 1 : test_weak_pointer_set_function (void)
457 : : {
458 : : GObject *obj;
459 : 1 : gpointer weak = NULL;
460 : :
461 : 1 : g_assert_false ((g_set_weak_pointer) (&weak, NULL));
462 : 1 : g_assert_null (weak);
463 : :
464 : 1 : obj = g_object_new (G_TYPE_OBJECT, NULL);
465 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
466 : :
467 : 1 : g_assert_true ((g_set_weak_pointer) (&weak, obj));
468 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
469 : 1 : g_assert_true (weak == obj);
470 : :
471 : 1 : g_assert_true ((g_set_weak_pointer) (&weak, NULL));
472 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
473 : 1 : g_assert_null (weak);
474 : :
475 : 1 : g_assert_true ((g_set_weak_pointer) (&weak, obj));
476 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
477 : 1 : g_assert_true (weak == obj);
478 : :
479 : 1 : g_object_unref (obj);
480 : 1 : g_assert_null (weak);
481 : 1 : }
482 : :
483 : : /* See gobject/tests/threadtests.c for the threaded version */
484 : : static void
485 : 1 : test_weak_ref (void)
486 : : {
487 : : GObject *obj;
488 : : GObject *obj2;
489 : : GObject *tmp;
490 : 1 : GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
491 : 1 : GWeakRef weak2 = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
492 : 1 : GWeakRef weak3 = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
493 : 1 : GWeakRef *dynamic_weak = g_new (GWeakRef, 1);
494 : :
495 : : /* you can initialize to empty like this... */
496 : 1 : g_weak_ref_init (&weak2, NULL);
497 : 1 : g_assert (g_weak_ref_get (&weak2) == NULL);
498 : :
499 : : /* ... or via an initializer */
500 : 1 : g_weak_ref_init (&weak3, NULL);
501 : 1 : g_assert (g_weak_ref_get (&weak3) == NULL);
502 : :
503 : 1 : obj = g_object_new (G_TYPE_OBJECT, NULL);
504 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
505 : :
506 : 1 : obj2 = g_object_new (G_TYPE_OBJECT, NULL);
507 : 1 : g_assert_cmpint (obj2->ref_count, ==, 1);
508 : :
509 : : /* you can init with an object (even if uninitialized) */
510 : 1 : g_weak_ref_init (&weak, obj);
511 : 1 : g_weak_ref_init (dynamic_weak, obj);
512 : : /* or set to point at an object, if initialized (maybe to 0) */
513 : 1 : g_weak_ref_set (&weak2, obj);
514 : 1 : g_weak_ref_set (&weak3, obj);
515 : : /* none of this affects its refcount */
516 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
517 : :
518 : : /* getting the value takes a ref */
519 : 1 : tmp = g_weak_ref_get (&weak);
520 : 1 : g_assert (tmp == obj);
521 : 1 : g_assert_cmpint (obj->ref_count, ==, 2);
522 : 1 : g_object_unref (tmp);
523 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
524 : :
525 : 1 : tmp = g_weak_ref_get (&weak2);
526 : 1 : g_assert (tmp == obj);
527 : 1 : g_assert_cmpint (obj->ref_count, ==, 2);
528 : 1 : g_object_unref (tmp);
529 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
530 : :
531 : 1 : tmp = g_weak_ref_get (&weak3);
532 : 1 : g_assert (tmp == obj);
533 : 1 : g_assert_cmpint (obj->ref_count, ==, 2);
534 : 1 : g_object_unref (tmp);
535 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
536 : :
537 : 1 : tmp = g_weak_ref_get (dynamic_weak);
538 : 1 : g_assert (tmp == obj);
539 : 1 : g_assert_cmpint (obj->ref_count, ==, 2);
540 : 1 : g_object_unref (tmp);
541 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
542 : :
543 : : /* clearing a weak ref stops tracking */
544 : 1 : g_weak_ref_clear (&weak);
545 : :
546 : : /* setting a weak ref to NULL stops tracking too */
547 : 1 : g_weak_ref_set (&weak2, NULL);
548 : 1 : g_assert (g_weak_ref_get (&weak2) == NULL);
549 : 1 : g_weak_ref_clear (&weak2);
550 : :
551 : : /* setting a weak ref to a new object stops tracking the old one */
552 : 1 : g_weak_ref_set (dynamic_weak, obj2);
553 : 1 : tmp = g_weak_ref_get (dynamic_weak);
554 : 1 : g_assert (tmp == obj2);
555 : 1 : g_assert_cmpint (obj2->ref_count, ==, 2);
556 : 1 : g_object_unref (tmp);
557 : 1 : g_assert_cmpint (obj2->ref_count, ==, 1);
558 : :
559 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
560 : :
561 : : /* free the object: weak3 is the only one left pointing there */
562 : 1 : g_object_unref (obj);
563 : 1 : g_assert (g_weak_ref_get (&weak3) == NULL);
564 : :
565 : : /* setting a weak ref to a new object stops tracking the old one */
566 : 1 : g_weak_ref_set (dynamic_weak, obj2);
567 : 1 : tmp = g_weak_ref_get (dynamic_weak);
568 : 1 : g_assert (tmp == obj2);
569 : 1 : g_assert_cmpint (obj2->ref_count, ==, 2);
570 : 1 : g_object_unref (tmp);
571 : 1 : g_assert_cmpint (obj2->ref_count, ==, 1);
572 : :
573 : 1 : g_weak_ref_clear (&weak3);
574 : :
575 : : /* unset dynamic_weak... */
576 : 1 : g_weak_ref_set (dynamic_weak, NULL);
577 : 1 : g_assert_null (g_weak_ref_get (dynamic_weak));
578 : :
579 : : /* initializing a weak reference to an object that had before works */
580 : 1 : g_weak_ref_set (dynamic_weak, obj2);
581 : 1 : tmp = g_weak_ref_get (dynamic_weak);
582 : 1 : g_assert_true (tmp == obj2);
583 : 1 : g_assert_cmpint (obj2->ref_count, ==, 2);
584 : 1 : g_object_unref (tmp);
585 : 1 : g_assert_cmpint (obj2->ref_count, ==, 1);
586 : :
587 : : /* clear and free dynamic_weak... */
588 : 1 : g_weak_ref_clear (dynamic_weak);
589 : :
590 : : /* ... to prove that doing so stops this from being a use-after-free */
591 : 1 : g_object_unref (obj2);
592 : 1 : g_free (dynamic_weak);
593 : 1 : }
594 : :
595 : 1 : 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 : 4 : G_DEFINE_TYPE (WeakReffedObject, weak_reffed_object, G_TYPE_OBJECT)
606 : :
607 : : static void
608 : 1 : weak_reffed_object_dispose (GObject *object)
609 : : {
610 : 1 : WeakReffedObject *weak_reffed = WEAK_REFFED_OBJECT (object);
611 : :
612 : 1 : g_assert_cmpint (object->ref_count, ==, 1);
613 : :
614 : 1 : g_weak_ref_set (weak_reffed->weak_ref, object);
615 : :
616 : 1 : G_OBJECT_CLASS (weak_reffed_object_parent_class)->dispose (object);
617 : :
618 : 1 : g_assert_true (object == g_weak_ref_get (weak_reffed->weak_ref));
619 : 1 : g_object_unref (object);
620 : 1 : }
621 : :
622 : : static void
623 : 1 : weak_reffed_object_init (WeakReffedObject *connector)
624 : : {
625 : 1 : }
626 : :
627 : : static void
628 : 1 : weak_reffed_object_class_init (WeakReffedObjectClass *klass)
629 : : {
630 : 1 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
631 : :
632 : 1 : object_class->dispose = weak_reffed_object_dispose;
633 : 1 : }
634 : :
635 : : static void
636 : 1 : test_weak_ref_on_dispose (void)
637 : : {
638 : : WeakReffedObject *obj;
639 : 1 : GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
640 : :
641 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2390");
642 : 1 : g_test_summary ("Test that a weak ref set during dispose vfunc is cleared");
643 : :
644 : 1 : g_weak_ref_init (&weak, NULL);
645 : :
646 : 1 : obj = g_object_new (weak_reffed_object_get_type (), NULL);
647 : 1 : obj->weak_ref = &weak;
648 : :
649 : 1 : g_assert_cmpint (G_OBJECT (obj)->ref_count, ==, 1);
650 : 1 : g_clear_object (&obj);
651 : :
652 : 1 : g_assert_null (g_weak_ref_get (&weak));
653 : 1 : }
654 : :
655 : : static void
656 : 1 : test_weak_ref_on_run_dispose (void)
657 : : {
658 : : GObject *obj;
659 : 1 : GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
660 : :
661 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/865");
662 : 1 : g_test_summary ("Test that a weak ref is cleared on g_object_run_dispose()");
663 : :
664 : 1 : obj = g_object_new (G_TYPE_OBJECT, NULL);
665 : 1 : g_weak_ref_init (&weak, obj);
666 : :
667 : 1 : g_assert_true (obj == g_weak_ref_get (&weak));
668 : 1 : g_object_unref (obj);
669 : :
670 : 1 : g_object_run_dispose (obj);
671 : 1 : g_assert_null (g_weak_ref_get (&weak));
672 : :
673 : 1 : g_weak_ref_set (&weak, obj);
674 : :
675 : 1 : g_clear_object (&obj);
676 : 1 : g_assert_null (g_weak_ref_get (&weak));
677 : 1 : }
678 : :
679 : : static void
680 : 3 : on_weak_ref_toggle_notify (gpointer data,
681 : : GObject *object,
682 : : gboolean is_last_ref)
683 : : {
684 : 3 : GWeakRef *weak = data;
685 : :
686 : 3 : if (is_last_ref)
687 : 2 : g_weak_ref_set (weak, object);
688 : 3 : }
689 : :
690 : : static void
691 : 1 : on_weak_ref_toggle_notify_disposed (gpointer data,
692 : : GObject *object)
693 : : {
694 : 1 : g_assert_cmpint (object->ref_count, ==, 1);
695 : :
696 : 1 : g_object_ref (object);
697 : 1 : g_object_unref (object);
698 : 1 : }
699 : :
700 : : static void
701 : 1 : test_weak_ref_on_toggle_notify (void)
702 : : {
703 : : GObject *obj;
704 : 1 : GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
705 : :
706 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2390");
707 : 1 : g_test_summary ("Test that a weak ref set on toggle notify is cleared");
708 : :
709 : 1 : g_weak_ref_init (&weak, NULL);
710 : :
711 : 1 : obj = g_object_new (G_TYPE_OBJECT, NULL);
712 : 1 : g_object_add_toggle_ref (obj, on_weak_ref_toggle_notify, &weak);
713 : 1 : g_object_weak_ref (obj, on_weak_ref_toggle_notify_disposed, NULL);
714 : 1 : g_object_unref (obj);
715 : :
716 : 1 : g_assert_cmpint (obj->ref_count, ==, 1);
717 : 1 : g_clear_object (&obj);
718 : :
719 : 1 : g_assert_null (g_weak_ref_get (&weak));
720 : 1 : }
721 : :
722 : : static void
723 : 2 : weak_ref_in_toggle_notify_toggle_cb (gpointer data,
724 : : GObject *object,
725 : : gboolean is_last_ref)
726 : : {
727 : : GWeakRef weak2;
728 : : GObject *obj2;
729 : :
730 : 2 : if (is_last_ref)
731 : 1 : return;
732 : :
733 : : /* We just got a second ref, while calling g_weak_ref_get().
734 : : *
735 : : * Test that taking another weak ref in this situation works.
736 : : */
737 : :
738 : 1 : g_weak_ref_init (&weak2, object);
739 : 1 : g_assert_true (object == g_weak_ref_get (&weak2));
740 : 1 : g_object_unref (object);
741 : :
742 : 1 : obj2 = g_object_new (G_TYPE_OBJECT, NULL);
743 : 1 : g_weak_ref_set (&weak2, obj2);
744 : 1 : g_object_unref (obj2);
745 : :
746 : 1 : g_assert_null (g_weak_ref_get (&weak2));
747 : : }
748 : :
749 : : static void
750 : 1 : test_weak_ref_in_toggle_notify (void)
751 : : {
752 : : GObject *obj;
753 : 1 : GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } };
754 : :
755 : 1 : obj = g_object_new (G_TYPE_OBJECT, NULL);
756 : 1 : g_object_add_toggle_ref (obj, weak_ref_in_toggle_notify_toggle_cb, NULL);
757 : 1 : g_object_unref (obj);
758 : :
759 : 1 : g_weak_ref_init (&weak, obj);
760 : :
761 : : /* We trigger a toggle notify via g_weak_ref_get(). */
762 : 1 : g_assert_true (g_weak_ref_get (&weak) == obj);
763 : :
764 : 1 : g_object_remove_toggle_ref (obj, weak_ref_in_toggle_notify_toggle_cb, NULL);
765 : 1 : g_object_unref (obj);
766 : :
767 : 1 : g_assert_null (g_weak_ref_get (&weak));
768 : 1 : }
769 : :
770 : : static void
771 : 1 : test_weak_ref_many (void)
772 : : {
773 : 2 : const guint N = g_test_slow ()
774 : : ? G_MAXUINT16
775 : 1 : : 211;
776 : 1 : const guint PRIME = 1048583;
777 : : GObject *obj;
778 : : GWeakRef *weak_refs;
779 : : GWeakRef weak_ref1;
780 : : guint j;
781 : : guint n;
782 : : guint i;
783 : :
784 : 1 : obj = g_object_new (G_TYPE_OBJECT, NULL);
785 : :
786 : 1 : weak_refs = g_new (GWeakRef, N);
787 : :
788 : : /* We register them in a somewhat juggled order. That's because below, we will clear them
789 : : * again, and we don't want to always clear them in the same order as they were registered.
790 : : * For that, we calculate the actual index by jumping around by adding a prime number. */
791 : 1 : j = (g_test_rand_int () % (N + 1));
792 : 212 : for (i = 0; i < N; i++)
793 : : {
794 : 211 : j = (j + PRIME) % N;
795 : 211 : g_weak_ref_init (&weak_refs[j], obj);
796 : : }
797 : :
798 : 1 : if (N == G_MAXUINT16)
799 : : {
800 : 0 : g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_CRITICAL, "*Too many GWeakRef registered");
801 : 0 : g_weak_ref_init (&weak_ref1, obj);
802 : 0 : g_test_assert_expected_messages ();
803 : 0 : g_assert_null (g_weak_ref_get (&weak_ref1));
804 : : }
805 : :
806 : 1 : n = g_test_rand_int () % (N + 1u);
807 : 212 : for (i = 0; i < N; i++)
808 : 211 : g_weak_ref_set (&weak_refs[i], i < n ? NULL : obj);
809 : :
810 : 1 : g_object_unref (obj);
811 : :
812 : 212 : for (i = 0; i < N; i++)
813 : 211 : g_assert_null (g_weak_ref_get (&weak_refs[i]));
814 : :
815 : : /* The API would expect us to also call g_weak_ref_clear() on all references
816 : : * to clean up. In practice, they are already all NULL, so we don't need
817 : : * that (it would have no effect, with the current implementation of
818 : : * GWeakRef). */
819 : :
820 : 1 : g_free (weak_refs);
821 : 1 : }
822 : :
823 : : /*****************************************************************************/
824 : :
825 : : #define CONCURRENT_N_OBJS 5
826 : : #define CONCURRENT_N_THREADS 5
827 : : #define CONCURRENT_N_RACES 100
828 : :
829 : : typedef struct
830 : : {
831 : : int TEST_IDX;
832 : : GObject *objs[CONCURRENT_N_OBJS];
833 : : int thread_done[CONCURRENT_N_THREADS];
834 : : } ConcurrentData;
835 : :
836 : : typedef struct
837 : : {
838 : : const ConcurrentData *data;
839 : : int idx;
840 : : int race_count;
841 : : GWeakRef *weak_ref;
842 : : GRand *rnd;
843 : : } ConcurrentThreadData;
844 : :
845 : : static gpointer
846 : 10 : _test_weak_ref_concurrent_thread_cb (gpointer data)
847 : : {
848 : 10 : ConcurrentThreadData *thread_data = data;
849 : :
850 : : while (TRUE)
851 : 6912 : {
852 : : gboolean all_done;
853 : : int i;
854 : : int r;
855 : :
856 : 110752 : for (r = 0; r < 15; r++)
857 : : {
858 : 103830 : GObject *obj_allocated = NULL;
859 : : GObject *obj;
860 : : GObject *obj2;
861 : : gboolean got_race;
862 : :
863 : : /* Choose a random object */
864 : 103830 : obj = thread_data->data->objs[g_rand_int (thread_data->rnd) % CONCURRENT_N_OBJS];
865 : 103830 : if (thread_data->data->TEST_IDX > 0 && (g_rand_int (thread_data->rnd) % 4 == 0))
866 : : {
867 : : /* With TEST_IDX>0 also randomly choose NULL or a newly created
868 : : * object. */
869 : 1920 : if (g_rand_boolean (thread_data->rnd))
870 : 955 : obj = NULL;
871 : : else
872 : : {
873 : 965 : obj_allocated = g_object_new (G_TYPE_OBJECT, NULL);
874 : 965 : obj = obj_allocated;
875 : : }
876 : : }
877 : :
878 : 103830 : g_assert (!obj || G_IS_OBJECT (obj));
879 : :
880 : 103830 : g_weak_ref_set (thread_data->weak_ref, obj);
881 : :
882 : : /* get the weak-ref. If there is no race, we expect to get the same
883 : : * object back. */
884 : 103830 : obj2 = g_weak_ref_get (thread_data->weak_ref);
885 : :
886 : 103830 : g_assert (!obj2 || G_IS_OBJECT (obj2));
887 : 103830 : if (!obj2)
888 : : {
889 : 1016 : g_assert (thread_data->data->TEST_IDX > 0);
890 : : }
891 : 103830 : if (obj != obj2)
892 : : {
893 : : int cnt;
894 : :
895 : 1122 : cnt = 0;
896 : 6732 : for (i = 0; i < CONCURRENT_N_OBJS; i++)
897 : : {
898 : 5610 : if (obj2 == thread_data->data->objs[i])
899 : 969 : cnt++;
900 : : }
901 : 1122 : if (!obj2)
902 : 101 : g_assert_cmpint (cnt, ==, 0);
903 : 1021 : else if (obj2 && obj2 == obj_allocated)
904 : 0 : g_assert_cmpint (cnt, ==, 0);
905 : 1021 : else if (thread_data->data->TEST_IDX > 0)
906 : 455 : g_assert_cmpint (cnt, <=, 1);
907 : : else
908 : 566 : g_assert_cmpint (cnt, ==, 1);
909 : 1122 : got_race = TRUE;
910 : : }
911 : : else
912 : 102708 : got_race = FALSE;
913 : :
914 : 103830 : g_clear_object (&obj2);
915 : 103830 : g_clear_object (&obj_allocated);
916 : :
917 : 103830 : if (got_race)
918 : : {
919 : : /* Each thread should see CONCURRENT_N_RACES before being done.
920 : : * Count them. */
921 : 1122 : if (g_atomic_int_get (&thread_data->race_count) > CONCURRENT_N_RACES)
922 : 112 : g_atomic_int_set (&thread_data->data->thread_done[thread_data->idx], 1);
923 : : else
924 : 1010 : g_atomic_int_add (&thread_data->race_count, 1);
925 : : }
926 : : }
927 : :
928 : : /* Each thread runs, until all threads saw the expected number of races. */
929 : 6922 : all_done = TRUE;
930 : 10633 : for (i = 0; i < CONCURRENT_N_THREADS; i++)
931 : : {
932 : 10623 : if (!g_atomic_int_get (&thread_data->data->thread_done[i]))
933 : : {
934 : 6912 : all_done = FALSE;
935 : 6912 : break;
936 : : }
937 : : }
938 : 6922 : if (all_done)
939 : 10 : return GINT_TO_POINTER (1);
940 : : }
941 : : }
942 : :
943 : : static void
944 : 2 : test_weak_ref_concurrent (gconstpointer testdata)
945 : : {
946 : 2 : const int TEST_IDX = GPOINTER_TO_INT (testdata);
947 : : GThread *threads[CONCURRENT_N_THREADS];
948 : : int i;
949 : 2 : ConcurrentData data = {
950 : : .TEST_IDX = TEST_IDX,
951 : : };
952 : : ConcurrentThreadData thread_data[CONCURRENT_N_THREADS];
953 : 2 : GWeakRef weak_ref = { 0 };
954 : :
955 : : /* Let several threads call g_weak_ref_set() & g_weak_ref_get() in a loop. */
956 : :
957 : 12 : for (i = 0; i < CONCURRENT_N_OBJS; i++)
958 : 10 : data.objs[i] = g_object_new (G_TYPE_OBJECT, NULL);
959 : :
960 : 12 : for (i = 0; i < CONCURRENT_N_THREADS; i++)
961 : : {
962 : 30 : const guint32 rnd_seed[] = {
963 : 10 : g_test_rand_int (),
964 : 10 : g_test_rand_int (),
965 : 10 : g_test_rand_int (),
966 : : };
967 : :
968 : 10 : thread_data[i] = (ConcurrentThreadData){
969 : : .idx = i,
970 : : .data = &data,
971 : : .weak_ref = &weak_ref,
972 : 10 : .rnd = g_rand_new_with_seed_array (rnd_seed, G_N_ELEMENTS (rnd_seed)),
973 : : };
974 : 10 : threads[i] = g_thread_new ("test-weak-ref-concurrent", _test_weak_ref_concurrent_thread_cb, &thread_data[i]);
975 : : }
976 : :
977 : 12 : for (i = 0; i < CONCURRENT_N_THREADS; i++)
978 : : {
979 : : gpointer r;
980 : :
981 : 10 : r = g_thread_join (g_steal_pointer (&threads[i]));
982 : 10 : g_assert_cmpint (GPOINTER_TO_INT (r), ==, 1);
983 : : }
984 : :
985 : 12 : for (i = 0; i < CONCURRENT_N_OBJS; i++)
986 : 10 : g_object_unref (g_steal_pointer (&data.objs[i]));
987 : 12 : for (i = 0; i < CONCURRENT_N_THREADS; i++)
988 : 10 : g_rand_free (g_steal_pointer (&thread_data[i].rnd));
989 : 2 : }
990 : :
991 : : /*****************************************************************************/
992 : :
993 : : typedef struct
994 : : {
995 : : gboolean should_be_last;
996 : : gint count;
997 : : } Count;
998 : :
999 : : static void
1000 : 5 : toggle_notify (gpointer data,
1001 : : GObject *obj,
1002 : : gboolean is_last)
1003 : : {
1004 : 5 : Count *c = data;
1005 : :
1006 : 5 : g_assert (is_last == c->should_be_last);
1007 : :
1008 : 5 : if (is_last)
1009 : 4 : g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 1);
1010 : : else
1011 : 1 : g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 2);
1012 : :
1013 : 5 : c->count++;
1014 : 5 : }
1015 : :
1016 : : static void
1017 : 1 : test_toggle_ref (void)
1018 : : {
1019 : : GObject *obj;
1020 : : Count c, c2;
1021 : :
1022 : 1 : obj = g_object_new (G_TYPE_OBJECT, NULL);
1023 : :
1024 : 1 : g_object_add_toggle_ref (obj, toggle_notify, &c);
1025 : 1 : g_object_add_toggle_ref (obj, toggle_notify, &c2);
1026 : :
1027 : 1 : c.should_be_last = c2.should_be_last = TRUE;
1028 : 1 : c.count = c2.count = 0;
1029 : :
1030 : 1 : g_object_unref (obj);
1031 : :
1032 : 1 : g_assert_cmpint (c.count, ==, 0);
1033 : 1 : g_assert_cmpint (c2.count, ==, 0);
1034 : :
1035 : 1 : g_object_ref (obj);
1036 : :
1037 : 1 : g_assert_cmpint (c.count, ==, 0);
1038 : 1 : g_assert_cmpint (c2.count, ==, 0);
1039 : :
1040 : 1 : g_object_remove_toggle_ref (obj, toggle_notify, &c2);
1041 : :
1042 : 1 : g_object_unref (obj);
1043 : :
1044 : 1 : g_assert_cmpint (c.count, ==, 1);
1045 : :
1046 : 1 : c.should_be_last = FALSE;
1047 : :
1048 : 1 : g_object_ref (obj);
1049 : :
1050 : 1 : g_assert_cmpint (c.count, ==, 2);
1051 : :
1052 : 1 : c.should_be_last = TRUE;
1053 : :
1054 : 1 : g_object_unref (obj);
1055 : :
1056 : 1 : g_assert_cmpint (c.count, ==, 3);
1057 : :
1058 : 1 : g_object_remove_toggle_ref (obj, toggle_notify, &c);
1059 : 1 : }
1060 : :
1061 : 13 : G_DECLARE_FINAL_TYPE (DisposeReffingObject, dispose_reffing_object,
1062 : : DISPOSE, REFFING_OBJECT, GObject)
1063 : :
1064 : : typedef enum
1065 : : {
1066 : : PROP_INT_PROP = 1,
1067 : : N_PROPS,
1068 : : } DisposeReffingObjectProperty;
1069 : :
1070 : : static GParamSpec *dispose_reffing_object_properties[N_PROPS] = {0};
1071 : :
1072 : : struct _DisposeReffingObject
1073 : : {
1074 : : GObject parent;
1075 : :
1076 : : GToggleNotify toggle_notify;
1077 : : Count actual;
1078 : : Count expected;
1079 : : unsigned disposing_refs;
1080 : : gboolean disposing_refs_all_normal;
1081 : :
1082 : : GCallback notify_handler;
1083 : : unsigned notify_called;
1084 : :
1085 : : int int_prop;
1086 : :
1087 : : GWeakRef *weak_ref;
1088 : : };
1089 : :
1090 : 17 : G_DEFINE_TYPE (DisposeReffingObject, dispose_reffing_object, G_TYPE_OBJECT)
1091 : :
1092 : : static void
1093 : 2 : on_object_notify (GObject *object,
1094 : : GParamSpec *pspec,
1095 : : void *data)
1096 : : {
1097 : 2 : DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
1098 : :
1099 : 2 : obj->notify_called++;
1100 : 2 : }
1101 : :
1102 : : static void
1103 : 8 : dispose_reffing_object_dispose (GObject *object)
1104 : : {
1105 : 8 : DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
1106 : :
1107 : 8 : g_assert_cmpint (object->ref_count, ==, 1);
1108 : 8 : g_assert_cmpint (obj->actual.count, ==, obj->expected.count);
1109 : :
1110 : 16 : for (unsigned i = 0; i < obj->disposing_refs; ++i)
1111 : : {
1112 : 8 : if (i == 0 && !obj->disposing_refs_all_normal)
1113 : : {
1114 : 5 : g_object_add_toggle_ref (object, obj->toggle_notify, &obj->actual);
1115 : : }
1116 : : else
1117 : : {
1118 : 3 : obj->actual.should_be_last = FALSE;
1119 : 3 : g_object_ref (obj);
1120 : 3 : g_assert_cmpint (obj->actual.count, ==, obj->expected.count);
1121 : : }
1122 : :
1123 : 8 : obj->actual.should_be_last = TRUE;
1124 : : }
1125 : :
1126 : 8 : G_OBJECT_CLASS (dispose_reffing_object_parent_class)->dispose (object);
1127 : :
1128 : 8 : if (obj->notify_handler)
1129 : : {
1130 : 6 : unsigned old_notify_called = obj->notify_called;
1131 : :
1132 : 6 : g_assert_cmpuint (g_signal_handler_find (object, G_SIGNAL_MATCH_FUNC,
1133 : : 0, 0, NULL, obj->notify_handler, NULL), ==, 0);
1134 : :
1135 : 6 : g_signal_connect (object, "notify", G_CALLBACK (obj->notify_handler), NULL);
1136 : :
1137 : : /* This would trigger a toggle notification, but is not something we may
1138 : : * want with https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2377
1139 : : * so, we only test this in case we have more than one ref
1140 : : */
1141 : 6 : if (obj->toggle_notify == toggle_notify)
1142 : 1 : g_assert_cmpint (obj->disposing_refs, >, 1);
1143 : :
1144 : 6 : g_object_notify (object, "int-prop");
1145 : 6 : g_assert_cmpuint (obj->notify_called, ==, old_notify_called);
1146 : : }
1147 : :
1148 : 8 : g_assert_cmpint (obj->actual.count, ==, obj->expected.count);
1149 : 8 : }
1150 : :
1151 : : static void
1152 : 2 : dispose_reffing_object_init (DisposeReffingObject *connector)
1153 : : {
1154 : 2 : }
1155 : :
1156 : : static void
1157 : 0 : dispose_reffing_object_set_property (GObject *object,
1158 : : guint property_id,
1159 : : const GValue *value,
1160 : : GParamSpec *pspec)
1161 : : {
1162 : 0 : DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
1163 : :
1164 : 0 : switch ((DisposeReffingObjectProperty) property_id)
1165 : : {
1166 : 0 : case PROP_INT_PROP:
1167 : 0 : obj->int_prop = g_value_get_int (value);
1168 : 0 : break;
1169 : 0 : default:
1170 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1171 : 0 : break;
1172 : : }
1173 : 0 : }
1174 : :
1175 : : static void
1176 : 0 : dispose_reffing_object_get_property (GObject *object,
1177 : : guint property_id,
1178 : : GValue *value,
1179 : : GParamSpec *pspec)
1180 : : {
1181 : 0 : DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
1182 : :
1183 : 0 : switch ((DisposeReffingObjectProperty) property_id)
1184 : : {
1185 : 0 : case PROP_INT_PROP:
1186 : 0 : g_value_set_int (value, obj->int_prop);
1187 : 0 : break;
1188 : 0 : default:
1189 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1190 : 0 : break;
1191 : : }
1192 : 0 : }
1193 : :
1194 : : static void
1195 : 1 : dispose_reffing_object_class_init (DisposeReffingObjectClass *klass)
1196 : : {
1197 : 1 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
1198 : :
1199 : 1 : dispose_reffing_object_properties[PROP_INT_PROP] =
1200 : 1 : g_param_spec_int ("int-prop", "int-prop", "int-prop",
1201 : : G_MININT, G_MAXINT,
1202 : : 0,
1203 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1204 : :
1205 : 1 : object_class->dispose = dispose_reffing_object_dispose;
1206 : 1 : object_class->set_property = dispose_reffing_object_set_property;
1207 : 1 : object_class->get_property = dispose_reffing_object_get_property;
1208 : :
1209 : 1 : g_object_class_install_properties (object_class, N_PROPS,
1210 : : dispose_reffing_object_properties);
1211 : 1 : }
1212 : :
1213 : : static void
1214 : 1 : test_toggle_ref_on_dispose (void)
1215 : : {
1216 : : DisposeReffingObject *obj;
1217 : 1 : gpointer disposed_checker = &obj;
1218 : :
1219 : : /* This tests wants to ensure that an object that gets re-referenced
1220 : : * (one or multiple times) during its dispose virtual function:
1221 : : * - Notifies all the queued "notify" signal handlers
1222 : : * - Notifies toggle notifications if any
1223 : : * - It does not get finalized
1224 : : */
1225 : :
1226 : 1 : obj = g_object_new (dispose_reffing_object_get_type (), NULL);
1227 : 1 : obj->toggle_notify = toggle_notify;
1228 : 1 : obj->notify_handler = G_CALLBACK (on_object_notify);
1229 : 1 : g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1230 : :
1231 : : /* Convert to toggle notification */
1232 : 1 : g_object_add_toggle_ref (G_OBJECT (obj), obj->toggle_notify, &obj->actual);
1233 : 1 : g_assert_cmpint (obj->actual.count, ==, 0);
1234 : :
1235 : 1 : obj->actual.should_be_last = TRUE;
1236 : 1 : obj->notify_handler = G_CALLBACK (on_object_notify);
1237 : 1 : g_object_unref (obj);
1238 : 1 : g_assert_cmpint (obj->actual.count, ==, 1);
1239 : 1 : g_assert_cmpuint (obj->notify_called, ==, 0);
1240 : :
1241 : : /* Remove the toggle reference, making it to dispose and resurrect again */
1242 : 1 : obj->disposing_refs = 1;
1243 : 1 : obj->expected.count = 1;
1244 : 1 : obj->notify_handler = NULL; /* FIXME: enable it when !2377 is in */
1245 : 1 : g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
1246 : 1 : g_assert_cmpint (obj->actual.count, ==, 2);
1247 : 1 : g_assert_cmpuint (obj->notify_called, ==, 0);
1248 : :
1249 : 1 : g_assert_null (disposed_checker);
1250 : 1 : g_assert_cmpint (g_atomic_int_get (&G_OBJECT (obj)->ref_count), ==,
1251 : : obj->disposing_refs);
1252 : :
1253 : : /* Object has been disposed, but is still alive, so add another weak pointer */
1254 : 1 : disposed_checker = &obj;
1255 : 1 : g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1256 : :
1257 : : /* Remove the toggle reference, making it to dispose and resurrect with
1258 : : * more references than before, so that no toggle notify is called
1259 : : */
1260 : 1 : obj->disposing_refs = 3;
1261 : 1 : obj->expected.count = 2;
1262 : 1 : obj->notify_handler = G_CALLBACK (on_object_notify);
1263 : 1 : g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
1264 : 1 : g_assert_cmpint (obj->actual.count, ==, 2);
1265 : 1 : g_assert_cmpint (obj->notify_called, ==, 1);
1266 : 1 : obj->expected.count = obj->actual.count;
1267 : :
1268 : 1 : g_assert_null (disposed_checker);
1269 : 1 : g_assert_cmpint (g_atomic_int_get (&G_OBJECT (obj)->ref_count), ==,
1270 : : obj->disposing_refs);
1271 : :
1272 : 1 : disposed_checker = &obj;
1273 : 1 : g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1274 : :
1275 : : /* Now remove the first added reference */
1276 : 1 : obj->disposing_refs = 0;
1277 : 1 : g_object_unref (obj);
1278 : 1 : g_assert_nonnull (disposed_checker);
1279 : 1 : g_assert_cmpint (g_atomic_int_get (&G_OBJECT (obj)->ref_count), ==, 2);
1280 : 1 : g_assert_cmpint (obj->actual.count, ==, 2);
1281 : 1 : g_assert_cmpint (obj->notify_called, ==, 1);
1282 : :
1283 : : /* And the toggle one */
1284 : 1 : obj->actual.should_be_last = TRUE;
1285 : 1 : obj->notify_handler = NULL;
1286 : 1 : g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
1287 : 1 : g_assert_nonnull (disposed_checker);
1288 : 1 : g_assert_cmpint (g_atomic_int_get (&G_OBJECT (obj)->ref_count), ==, 1);
1289 : 1 : g_assert_cmpint (obj->actual.count, ==, 2);
1290 : 1 : obj->expected.count = obj->actual.count;
1291 : :
1292 : 1 : g_clear_object (&obj);
1293 : 1 : g_assert_null (disposed_checker);
1294 : 1 : }
1295 : :
1296 : : static void
1297 : 4 : toggle_notify_counter (gpointer data,
1298 : : GObject *obj,
1299 : : gboolean is_last)
1300 : : {
1301 : 4 : Count *c = data;
1302 : 4 : c->count++;
1303 : :
1304 : 4 : if (is_last)
1305 : 4 : g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 1);
1306 : : else
1307 : 0 : g_assert_cmpint (g_atomic_int_get (&obj->ref_count), ==, 2);
1308 : 4 : }
1309 : :
1310 : : static void
1311 : 1 : on_object_notify_switch_to_normal_ref (GObject *object,
1312 : : GParamSpec *pspec,
1313 : : void *data)
1314 : : {
1315 : 1 : DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
1316 : :
1317 : 1 : obj->notify_called++;
1318 : :
1319 : 1 : g_object_ref (object);
1320 : 1 : g_object_remove_toggle_ref (object, obj->toggle_notify, NULL);
1321 : 1 : }
1322 : :
1323 : : static void
1324 : 1 : on_object_notify_switch_to_toggle_ref (GObject *object,
1325 : : GParamSpec *pspec,
1326 : : void *data)
1327 : : {
1328 : 1 : DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
1329 : :
1330 : 1 : obj->notify_called++;
1331 : :
1332 : 1 : g_object_add_toggle_ref (object, obj->toggle_notify, &obj->actual);
1333 : 1 : g_object_unref (object);
1334 : 1 : }
1335 : :
1336 : : static void
1337 : 1 : on_object_notify_add_ref (GObject *object,
1338 : : GParamSpec *pspec,
1339 : : void *data)
1340 : : {
1341 : 1 : DisposeReffingObject *obj = DISPOSE_REFFING_OBJECT (object);
1342 : 1 : int old_toggle_cout = obj->actual.count;
1343 : :
1344 : 1 : obj->notify_called++;
1345 : :
1346 : 1 : g_object_ref (object);
1347 : 1 : g_assert_cmpint (obj->actual.count, ==, old_toggle_cout);
1348 : 1 : }
1349 : :
1350 : : static void
1351 : 1 : test_toggle_ref_and_notify_on_dispose (void)
1352 : : {
1353 : : DisposeReffingObject *obj;
1354 : 1 : gpointer disposed_checker = &obj;
1355 : :
1356 : : /* This tests wants to ensure that toggle signal emission during dispose
1357 : : * is properly working if the object is revitalized by adding new references.
1358 : : * It also wants to check that toggle notifications are not happening if a
1359 : : * notify handler is removing them at this phase.
1360 : : */
1361 : :
1362 : 1 : obj = g_object_new (dispose_reffing_object_get_type (), NULL);
1363 : 1 : obj->toggle_notify = toggle_notify_counter;
1364 : 1 : g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1365 : :
1366 : : /* Convert to toggle notification */
1367 : 1 : g_object_add_toggle_ref (G_OBJECT (obj), obj->toggle_notify, &obj->actual);
1368 : 1 : g_assert_cmpint (obj->actual.count, ==, 0);
1369 : :
1370 : 1 : obj->notify_handler = G_CALLBACK (on_object_notify);
1371 : 1 : g_object_unref (obj);
1372 : 1 : g_assert_cmpint (obj->actual.count, ==, 1);
1373 : 1 : g_assert_cmpuint (obj->notify_called, ==, 0);
1374 : :
1375 : 1 : disposed_checker = &obj;
1376 : 1 : g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1377 : :
1378 : : /* Check that notification is triggered after being queued */
1379 : 1 : obj->disposing_refs = 1;
1380 : 1 : obj->expected.count = 1;
1381 : 1 : obj->notify_handler = G_CALLBACK (on_object_notify);
1382 : 1 : g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
1383 : 1 : g_assert_cmpint (obj->actual.count, ==, 2);
1384 : 1 : g_assert_cmpuint (obj->notify_called, ==, 1);
1385 : :
1386 : 1 : disposed_checker = &obj;
1387 : 1 : g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1388 : :
1389 : : /* Check that notification is triggered after being queued, but no toggle
1390 : : * notification is happening if notify handler switches to normal reference
1391 : : */
1392 : 1 : obj->disposing_refs = 1;
1393 : 1 : obj->expected.count = 2;
1394 : 1 : obj->notify_handler = G_CALLBACK (on_object_notify_switch_to_normal_ref);
1395 : 1 : g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
1396 : 1 : g_assert_cmpint (obj->actual.count, ==, 2);
1397 : 1 : g_assert_cmpuint (obj->notify_called, ==, 2);
1398 : :
1399 : 1 : disposed_checker = &obj;
1400 : 1 : g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1401 : :
1402 : : /* Check that notification is triggered after being queued, but that toggle
1403 : : * is happening if notify handler switched to toggle reference
1404 : : */
1405 : 1 : obj->disposing_refs = 1;
1406 : 1 : obj->disposing_refs_all_normal = TRUE;
1407 : 1 : obj->expected.count = 2;
1408 : 1 : obj->notify_handler = G_CALLBACK (on_object_notify_switch_to_toggle_ref);
1409 : 1 : g_object_unref (obj);
1410 : 1 : g_assert_cmpint (obj->actual.count, ==, 3);
1411 : 1 : g_assert_cmpuint (obj->notify_called, ==, 3);
1412 : :
1413 : 1 : disposed_checker = &obj;
1414 : 1 : g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1415 : :
1416 : : /* Check that notification is triggered after being queued, but that toggle
1417 : : * is not happening if current refcount changed.
1418 : : */
1419 : 1 : obj->disposing_refs = 1;
1420 : 1 : obj->disposing_refs_all_normal = FALSE;
1421 : 1 : obj->expected.count = 3;
1422 : 1 : obj->notify_handler = G_CALLBACK (on_object_notify_add_ref);
1423 : 1 : g_object_remove_toggle_ref (G_OBJECT (obj), obj->toggle_notify, NULL);
1424 : 1 : g_assert_cmpint (obj->actual.count, ==, 3);
1425 : 1 : g_assert_cmpuint (obj->notify_called, ==, 4);
1426 : 1 : g_object_unref (obj);
1427 : :
1428 : 1 : disposed_checker = &obj;
1429 : 1 : g_object_add_weak_pointer (G_OBJECT (obj), &disposed_checker);
1430 : :
1431 : 1 : obj->disposing_refs = 0;
1432 : 1 : obj->expected.count = 4;
1433 : 1 : g_clear_object (&obj);
1434 : 1 : g_assert_null (disposed_checker);
1435 : 1 : }
1436 : :
1437 : : static gboolean global_destroyed;
1438 : : static gint global_value;
1439 : :
1440 : : static void
1441 : 3 : data_destroy (gpointer data)
1442 : : {
1443 : 3 : g_assert_cmpint (GPOINTER_TO_INT (data), ==, global_value);
1444 : :
1445 : 3 : global_destroyed = TRUE;
1446 : 3 : }
1447 : :
1448 : : static void
1449 : 1 : test_object_qdata (void)
1450 : : {
1451 : : GObject *obj;
1452 : : gpointer v;
1453 : : GQuark quark;
1454 : :
1455 : 1 : obj = g_object_new (G_TYPE_OBJECT, NULL);
1456 : :
1457 : 1 : global_value = 1;
1458 : 1 : global_destroyed = FALSE;
1459 : 1 : g_object_set_data_full (obj, "test", GINT_TO_POINTER (1), data_destroy);
1460 : 1 : v = g_object_get_data (obj, "test");
1461 : 1 : g_assert_cmpint (GPOINTER_TO_INT (v), ==, 1);
1462 : 1 : g_object_set_data_full (obj, "test", GINT_TO_POINTER (2), data_destroy);
1463 : 1 : g_assert (global_destroyed);
1464 : 1 : global_value = 2;
1465 : 1 : global_destroyed = FALSE;
1466 : 1 : v = g_object_steal_data (obj, "test");
1467 : 1 : g_assert_cmpint (GPOINTER_TO_INT (v), ==, 2);
1468 : 1 : g_assert (!global_destroyed);
1469 : :
1470 : 1 : global_value = 1;
1471 : 1 : global_destroyed = FALSE;
1472 : 1 : quark = g_quark_from_string ("test");
1473 : 1 : g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (1), data_destroy);
1474 : 1 : v = g_object_get_qdata (obj, quark);
1475 : 1 : g_assert_cmpint (GPOINTER_TO_INT (v), ==, 1);
1476 : 1 : g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (2), data_destroy);
1477 : 1 : g_assert (global_destroyed);
1478 : 1 : global_value = 2;
1479 : 1 : global_destroyed = FALSE;
1480 : 1 : v = g_object_steal_qdata (obj, quark);
1481 : 1 : g_assert_cmpint (GPOINTER_TO_INT (v), ==, 2);
1482 : 1 : g_assert (!global_destroyed);
1483 : :
1484 : 1 : g_object_set_qdata_full (obj, quark, GINT_TO_POINTER (3), data_destroy);
1485 : 1 : global_value = 3;
1486 : 1 : global_destroyed = FALSE;
1487 : 1 : g_object_unref (obj);
1488 : :
1489 : 1 : g_assert (global_destroyed);
1490 : 1 : }
1491 : :
1492 : : typedef struct {
1493 : : const gchar *value;
1494 : : gint refcount;
1495 : : } Value;
1496 : :
1497 : : static gpointer
1498 : 3 : ref_value (gpointer value, gpointer user_data)
1499 : : {
1500 : 3 : Value *v = value;
1501 : 3 : Value **old_value_p = user_data;
1502 : :
1503 : 3 : if (old_value_p)
1504 : 2 : *old_value_p = v;
1505 : :
1506 : 3 : if (v)
1507 : 2 : v->refcount += 1;
1508 : :
1509 : 3 : return value;
1510 : : }
1511 : :
1512 : : static void
1513 : 5 : unref_value (gpointer value)
1514 : : {
1515 : 5 : Value *v = value;
1516 : :
1517 : 5 : v->refcount -= 1;
1518 : 5 : if (v->refcount == 0)
1519 : 3 : g_free (value);
1520 : 5 : }
1521 : :
1522 : : static
1523 : : Value *
1524 : 3 : new_value (const gchar *s)
1525 : : {
1526 : : Value *v;
1527 : :
1528 : 3 : v = g_new (Value, 1);
1529 : 3 : v->value = s;
1530 : 3 : v->refcount = 1;
1531 : :
1532 : 3 : return v;
1533 : : }
1534 : :
1535 : : static void
1536 : 1 : test_object_qdata2 (void)
1537 : : {
1538 : : GObject *obj;
1539 : : Value *v, *v1, *v2, *v3, *old_val;
1540 : : GDestroyNotify old_destroy;
1541 : : gboolean res;
1542 : :
1543 : 1 : obj = g_object_new (G_TYPE_OBJECT, NULL);
1544 : :
1545 : 1 : v1 = new_value ("bla");
1546 : :
1547 : 1 : g_object_set_data_full (obj, "test", v1, unref_value);
1548 : :
1549 : 1 : v = g_object_get_data (obj, "test");
1550 : 1 : g_assert_cmpstr (v->value, ==, "bla");
1551 : 1 : g_assert_cmpint (v->refcount, ==, 1);
1552 : :
1553 : 1 : v = g_object_dup_data (obj, "test", ref_value, &old_val);
1554 : 1 : g_assert (old_val == v1);
1555 : 1 : g_assert_cmpstr (v->value, ==, "bla");
1556 : 1 : g_assert_cmpint (v->refcount, ==, 2);
1557 : 1 : unref_value (v);
1558 : :
1559 : 1 : v = g_object_dup_data (obj, "nono", ref_value, &old_val);
1560 : 1 : g_assert (old_val == NULL);
1561 : 1 : g_assert (v == NULL);
1562 : :
1563 : 1 : v2 = new_value ("not");
1564 : :
1565 : 1 : res = g_object_replace_data (obj, "test", v1, v2, unref_value, &old_destroy);
1566 : 1 : g_assert (res == TRUE);
1567 : 1 : g_assert (old_destroy == unref_value);
1568 : 1 : g_assert_cmpstr (v1->value, ==, "bla");
1569 : 1 : g_assert_cmpint (v1->refcount, ==, 1);
1570 : :
1571 : 1 : v = g_object_get_data (obj, "test");
1572 : 1 : g_assert_cmpstr (v->value, ==, "not");
1573 : 1 : g_assert_cmpint (v->refcount, ==, 1);
1574 : :
1575 : 1 : v3 = new_value ("xyz");
1576 : 1 : res = g_object_replace_data (obj, "test", v1, v3, unref_value, &old_destroy);
1577 : 1 : g_assert (res == FALSE);
1578 : 1 : g_assert_cmpstr (v2->value, ==, "not");
1579 : 1 : g_assert_cmpint (v2->refcount, ==, 1);
1580 : :
1581 : 1 : unref_value (v1);
1582 : :
1583 : 1 : res = g_object_replace_data (obj, "test", NULL, v3, unref_value, &old_destroy);
1584 : 1 : g_assert (res == FALSE);
1585 : 1 : g_assert_cmpstr (v2->value, ==, "not");
1586 : 1 : g_assert_cmpint (v2->refcount, ==, 1);
1587 : :
1588 : 1 : res = g_object_replace_data (obj, "test", v2, NULL, unref_value, &old_destroy);
1589 : 1 : g_assert (res == TRUE);
1590 : 1 : g_assert (old_destroy == unref_value);
1591 : 1 : g_assert_cmpstr (v2->value, ==, "not");
1592 : 1 : g_assert_cmpint (v2->refcount, ==, 1);
1593 : :
1594 : 1 : unref_value (v2);
1595 : :
1596 : 1 : v = g_object_get_data (obj, "test");
1597 : 1 : g_assert (v == NULL);
1598 : :
1599 : 1 : res = g_object_replace_data (obj, "test", NULL, v3, unref_value, &old_destroy);
1600 : 1 : g_assert (res == TRUE);
1601 : :
1602 : 1 : v = g_object_get_data (obj, "test");
1603 : 1 : g_assert (v == v3);
1604 : :
1605 : 1 : ref_value (v3, NULL);
1606 : 1 : g_assert_cmpint (v3->refcount, ==, 2);
1607 : 1 : g_object_unref (obj);
1608 : 1 : g_assert_cmpint (v3->refcount, ==, 1);
1609 : 1 : unref_value (v3);
1610 : 1 : }
1611 : :
1612 : : int
1613 : 1 : main (int argc, char **argv)
1614 : : {
1615 : 1 : g_test_init (&argc, &argv, NULL);
1616 : :
1617 : 1 : g_setenv ("G_ENABLE_DIAGNOSTIC", "1", TRUE);
1618 : :
1619 : 1 : g_test_add_func ("/type/fundamentals", test_fundamentals);
1620 : 1 : g_test_add_func ("/type/qdata", test_type_qdata);
1621 : 1 : g_test_add_func ("/type/query", test_type_query);
1622 : 1 : g_test_add_func ("/type/class-private", test_class_private);
1623 : 1 : g_test_add_func ("/object/clear", test_clear);
1624 : 1 : g_test_add_func ("/object/clear-function", test_clear_function);
1625 : 1 : g_test_add_func ("/object/set", test_set);
1626 : 1 : g_test_add_func ("/object/set-function", test_set_function);
1627 : 1 : g_test_add_func ("/object/set/derived-type", test_set_derived_type);
1628 : 1 : g_test_add_func ("/object/value", test_object_value);
1629 : 1 : g_test_add_func ("/object/initially-unowned", test_initially_unowned);
1630 : 1 : g_test_add_func ("/object/weak-pointer", test_weak_pointer);
1631 : 1 : g_test_add_func ("/object/weak-pointer/clear", test_weak_pointer_clear);
1632 : 1 : g_test_add_func ("/object/weak-pointer/clear-function", test_weak_pointer_clear_function);
1633 : 1 : g_test_add_func ("/object/weak-pointer/set", test_weak_pointer_set);
1634 : 1 : g_test_add_func ("/object/weak-pointer/set-function", test_weak_pointer_set_function);
1635 : 1 : g_test_add_func ("/object/weak-ref", test_weak_ref);
1636 : 1 : g_test_add_func ("/object/weak-ref/on-dispose", test_weak_ref_on_dispose);
1637 : 1 : g_test_add_func ("/object/weak-ref/on-run-dispose", test_weak_ref_on_run_dispose);
1638 : 1 : g_test_add_func ("/object/weak-ref/on-toggle-notify", test_weak_ref_on_toggle_notify);
1639 : 1 : g_test_add_func ("/object/weak-ref/in-toggle-notify", test_weak_ref_in_toggle_notify);
1640 : 1 : g_test_add_func ("/object/weak-ref/many", test_weak_ref_many);
1641 : 1 : g_test_add_data_func ("/object/weak-ref/concurrent/0", GINT_TO_POINTER (0), test_weak_ref_concurrent);
1642 : 1 : g_test_add_data_func ("/object/weak-ref/concurrent/1", GINT_TO_POINTER (1), test_weak_ref_concurrent);
1643 : 1 : g_test_add_func ("/object/toggle-ref", test_toggle_ref);
1644 : 1 : g_test_add_func ("/object/toggle-ref/ref-on-dispose", test_toggle_ref_on_dispose);
1645 : 1 : g_test_add_func ("/object/toggle-ref/ref-and-notify-on-dispose", test_toggle_ref_and_notify_on_dispose);
1646 : 1 : g_test_add_func ("/object/qdata", test_object_qdata);
1647 : 1 : g_test_add_func ("/object/qdata2", test_object_qdata2);
1648 : :
1649 : 1 : return g_test_run ();
1650 : : }
|