Branch data Line data Source code
1 : : /* GObject - GLib Type, Object, Parameter and Signal Library
2 : : * Copyright (C) 2005 Red Hat, Inc.
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General
17 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 : : */
19 : :
20 : : #include <glib-object.h>
21 : :
22 : : /* This test tests weak and toggle references */
23 : :
24 : : static GObject *global_object;
25 : :
26 : : static gboolean object_destroyed;
27 : : static gboolean weak_ref1_notified;
28 : : static gboolean weak_ref2_notified;
29 : : static gboolean toggle_ref1_weakened;
30 : : static gboolean toggle_ref1_strengthened;
31 : : static gboolean toggle_ref2_weakened;
32 : : static gboolean toggle_ref2_strengthened;
33 : : static gboolean toggle_ref3_weakened;
34 : : static gboolean toggle_ref3_strengthened;
35 : :
36 : : /* TestObject, a parent class for TestObject */
37 : : static GType test_object_get_type (void);
38 : : #define TEST_TYPE_OBJECT (test_object_get_type ())
39 : : typedef struct _TestObject TestObject;
40 : : typedef struct _TestObjectClass TestObjectClass;
41 : :
42 : : struct _TestObject
43 : : {
44 : : GObject parent_instance;
45 : : };
46 : : struct _TestObjectClass
47 : : {
48 : : GObjectClass parent_class;
49 : : };
50 : :
51 : 9 : G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
52 : :
53 : : static void
54 : 7 : test_object_finalize (GObject *object)
55 : : {
56 : 7 : object_destroyed = TRUE;
57 : :
58 : 7 : G_OBJECT_CLASS (test_object_parent_class)->finalize (object);
59 : 7 : }
60 : :
61 : : static void
62 : 1 : test_object_class_init (TestObjectClass *class)
63 : : {
64 : 1 : GObjectClass *object_class = G_OBJECT_CLASS (class);
65 : :
66 : 1 : object_class->finalize = test_object_finalize;
67 : 1 : }
68 : :
69 : : static void
70 : 7 : test_object_init (TestObject *test_object)
71 : : {
72 : 7 : }
73 : :
74 : : static void
75 : 10 : clear_flags (void)
76 : : {
77 : 10 : object_destroyed = FALSE;
78 : 10 : weak_ref1_notified = FALSE;
79 : 10 : weak_ref2_notified = FALSE;
80 : 10 : toggle_ref1_weakened = FALSE;
81 : 10 : toggle_ref1_strengthened = FALSE;
82 : 10 : toggle_ref2_weakened = FALSE;
83 : 10 : toggle_ref2_strengthened = FALSE;
84 : 10 : toggle_ref3_weakened = FALSE;
85 : 10 : toggle_ref3_strengthened = FALSE;
86 : 10 : }
87 : :
88 : : static void
89 : 2 : weak_ref1 (gpointer data,
90 : : GObject *object)
91 : : {
92 : 2 : g_assert_true (object == global_object);
93 : 2 : g_assert_cmpint (GPOINTER_TO_INT (data), ==, 42);
94 : :
95 : 2 : weak_ref1_notified = TRUE;
96 : 2 : }
97 : :
98 : : static void
99 : 2 : weak_ref2 (gpointer data,
100 : : GObject *object)
101 : : {
102 : 2 : g_assert_true (object == global_object);
103 : 2 : g_assert_cmpint (GPOINTER_TO_INT (data), ==, 24);
104 : :
105 : 2 : weak_ref2_notified = TRUE;
106 : 2 : }
107 : :
108 : : static void
109 : 1 : weak_ref3 (gpointer data,
110 : : GObject *object)
111 : : {
112 : 1 : GWeakRef *weak_ref = data;
113 : :
114 : 1 : g_assert_null (g_weak_ref_get (weak_ref));
115 : :
116 : 1 : weak_ref2_notified = TRUE;
117 : 1 : }
118 : :
119 : : static void
120 : 3 : toggle_ref1 (gpointer data,
121 : : GObject *object,
122 : : gboolean is_last_ref)
123 : : {
124 : 3 : g_assert_true (object == global_object);
125 : 3 : g_assert_cmpint (GPOINTER_TO_INT (data), ==, 42);
126 : :
127 : 3 : if (is_last_ref)
128 : 2 : toggle_ref1_weakened = TRUE;
129 : : else
130 : 1 : toggle_ref1_strengthened = TRUE;
131 : 3 : }
132 : :
133 : : static void
134 : 1 : toggle_ref2 (gpointer data,
135 : : GObject *object,
136 : : gboolean is_last_ref)
137 : : {
138 : 1 : g_assert_true (object == global_object);
139 : 1 : g_assert_cmpint (GPOINTER_TO_INT (data), ==, 24);
140 : :
141 : 1 : if (is_last_ref)
142 : 1 : toggle_ref2_weakened = TRUE;
143 : : else
144 : 0 : toggle_ref2_strengthened = TRUE;
145 : 1 : }
146 : :
147 : : static void
148 : 1 : toggle_ref3 (gpointer data,
149 : : GObject *object,
150 : : gboolean is_last_ref)
151 : : {
152 : 1 : g_assert_true (object == global_object);
153 : 1 : g_assert_cmpint (GPOINTER_TO_INT (data), ==, 34);
154 : :
155 : 1 : if (is_last_ref)
156 : : {
157 : 1 : toggle_ref3_weakened = TRUE;
158 : 1 : g_object_remove_toggle_ref (object, toggle_ref3, GUINT_TO_POINTER (34));
159 : : }
160 : : else
161 : 0 : toggle_ref3_strengthened = TRUE;
162 : 1 : }
163 : :
164 : : static void
165 : 1 : test_references (void)
166 : : {
167 : : GObject *object;
168 : : GWeakRef weak_ref;
169 : :
170 : : /* Test basic weak reference operation */
171 : 1 : global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
172 : :
173 : 1 : g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
174 : :
175 : 1 : clear_flags ();
176 : 1 : g_object_unref (object);
177 : 1 : g_assert_true (weak_ref1_notified);
178 : 1 : g_assert_true (object_destroyed);
179 : :
180 : : /* Test two weak references at once
181 : : */
182 : 1 : global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
183 : :
184 : 1 : g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
185 : 1 : g_object_weak_ref (object, weak_ref2, GUINT_TO_POINTER (24));
186 : :
187 : 1 : clear_flags ();
188 : 1 : g_object_unref (object);
189 : 1 : g_assert_true (weak_ref1_notified);
190 : 1 : g_assert_true (weak_ref2_notified);
191 : 1 : g_assert_true (object_destroyed);
192 : :
193 : : /* Test remove weak references */
194 : 1 : global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
195 : :
196 : 1 : g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
197 : 1 : g_object_weak_ref (object, weak_ref2, GUINT_TO_POINTER (24));
198 : 1 : g_object_weak_unref (object, weak_ref1, GUINT_TO_POINTER (42));
199 : :
200 : 1 : clear_flags ();
201 : 1 : g_object_unref (object);
202 : 1 : g_assert_false (weak_ref1_notified);
203 : 1 : g_assert_true (weak_ref2_notified);
204 : 1 : g_assert_true (object_destroyed);
205 : :
206 : : /* Test that within a GWeakNotify the GWeakRef is NULL already. */
207 : 1 : weak_ref2_notified = FALSE;
208 : 1 : object = g_object_new (G_TYPE_OBJECT, NULL);
209 : 1 : g_weak_ref_init (&weak_ref, object);
210 : 1 : g_assert_true (object == g_weak_ref_get (&weak_ref));
211 : 1 : g_object_weak_ref (object, weak_ref3, &weak_ref);
212 : 1 : g_object_unref (object);
213 : 1 : g_object_unref (object);
214 : 1 : g_assert_true (weak_ref2_notified);
215 : 1 : g_weak_ref_clear (&weak_ref);
216 : :
217 : : /* Test basic toggle reference operation */
218 : 1 : global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
219 : :
220 : 1 : g_object_add_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
221 : :
222 : 1 : clear_flags ();
223 : 1 : g_object_unref (object);
224 : 1 : g_assert_true (toggle_ref1_weakened);
225 : 1 : g_assert_false (toggle_ref1_strengthened);
226 : 1 : g_assert_false (object_destroyed);
227 : :
228 : 1 : clear_flags ();
229 : 1 : g_object_ref (object);
230 : 1 : g_assert_false (toggle_ref1_weakened);
231 : 1 : g_assert_true (toggle_ref1_strengthened);
232 : 1 : g_assert_false (object_destroyed);
233 : :
234 : 1 : g_object_unref (object);
235 : :
236 : 1 : clear_flags ();
237 : 1 : g_object_remove_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
238 : 1 : g_assert_false (toggle_ref1_weakened);
239 : 1 : g_assert_false (toggle_ref1_strengthened);
240 : 1 : g_assert_true (object_destroyed);
241 : :
242 : 1 : global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
243 : :
244 : : /* Test two toggle references at once */
245 : 1 : g_object_add_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
246 : 1 : g_object_add_toggle_ref (object, toggle_ref2, GUINT_TO_POINTER (24));
247 : :
248 : 1 : clear_flags ();
249 : 1 : g_object_unref (object);
250 : 1 : g_assert_false (toggle_ref1_weakened);
251 : 1 : g_assert_false (toggle_ref1_strengthened);
252 : 1 : g_assert_false (toggle_ref2_weakened);
253 : 1 : g_assert_false (toggle_ref2_strengthened);
254 : 1 : g_assert_false (object_destroyed);
255 : :
256 : 1 : clear_flags ();
257 : 1 : g_object_remove_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
258 : 1 : g_assert_false (toggle_ref1_weakened);
259 : 1 : g_assert_false (toggle_ref1_strengthened);
260 : 1 : g_assert_true (toggle_ref2_weakened);
261 : 1 : g_assert_false (toggle_ref2_strengthened);
262 : 1 : g_assert_false (object_destroyed);
263 : :
264 : 1 : clear_flags ();
265 : : /* Check that removing a toggle ref with %NULL data works fine. */
266 : 1 : g_object_remove_toggle_ref (object, toggle_ref2, NULL);
267 : 1 : g_assert_false (toggle_ref1_weakened);
268 : 1 : g_assert_false (toggle_ref1_strengthened);
269 : 1 : g_assert_false (toggle_ref2_weakened);
270 : 1 : g_assert_false (toggle_ref2_strengthened);
271 : 1 : g_assert_true (object_destroyed);
272 : :
273 : : /* Test a toggle reference that removes itself */
274 : 1 : global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
275 : :
276 : 1 : g_object_add_toggle_ref (object, toggle_ref3, GUINT_TO_POINTER (34));
277 : :
278 : 1 : clear_flags ();
279 : 1 : g_object_unref (object);
280 : 1 : g_assert_true (toggle_ref3_weakened);
281 : 1 : g_assert_false (toggle_ref3_strengthened);
282 : 1 : g_assert_true (object_destroyed);
283 : 1 : }
284 : :
285 : : /*****************************************************************************/
286 : :
287 : : static guint weak_ref4_notified;
288 : : static guint weak_ref4_finalizing_notified;
289 : : static guint weak_ref4_finalizing_notified_skipped;
290 : : static gint weak_ref4_finalizing_resurrected = -1;
291 : : static guint weak_ref4_indexes_n;
292 : : static const guint *weak_ref4_indexes;
293 : :
294 : : static void
295 : 142 : weak_ref4_finalizing (gpointer data,
296 : : GObject *object)
297 : : {
298 : : static gint last = -1;
299 : : gint idx;
300 : :
301 : 142 : g_assert_true (weak_ref4_finalizing_resurrected == FALSE || weak_ref4_finalizing_resurrected == 4);
302 : :
303 : 142 : idx = (gint) GPOINTER_TO_UINT (data);
304 : 142 : g_assert_cmpint (last, <, idx);
305 : 142 : last = idx;
306 : :
307 : 142 : weak_ref4_finalizing_notified++;
308 : 142 : }
309 : :
310 : : static void
311 : 142 : weak_ref4 (gpointer data,
312 : : GObject *object)
313 : : {
314 : : static gint last = -1;
315 : : guint idx;
316 : :
317 : 142 : g_assert_cmpint (weak_ref4_finalizing_notified, ==, 0);
318 : :
319 : 142 : idx = GPOINTER_TO_UINT (data);
320 : 142 : g_assert_cmpint (last, <, (gint) idx);
321 : 142 : last = (gint) idx;
322 : :
323 : 142 : weak_ref4_notified++;
324 : :
325 : 142 : if (weak_ref4_finalizing_resurrected == -1)
326 : : {
327 : 1 : if (g_random_boolean ())
328 : : {
329 : : /* Resurrect the object. */
330 : 0 : weak_ref4_finalizing_resurrected = TRUE;
331 : 0 : g_object_ref (object);
332 : : }
333 : : else
334 : 1 : weak_ref4_finalizing_resurrected = FALSE;
335 : : }
336 : :
337 : 142 : g_object_weak_ref (object, weak_ref4_finalizing, GUINT_TO_POINTER (idx));
338 : :
339 : 142 : if (weak_ref4_indexes_n > 0 && (g_random_int () % 4 == 0))
340 : : {
341 : :
342 : 60 : while (weak_ref4_indexes_n > 0 && weak_ref4_indexes[weak_ref4_indexes_n - 1] <= idx)
343 : : {
344 : : /* already invoked. Skip. */
345 : 31 : weak_ref4_indexes_n--;
346 : : }
347 : :
348 : : /* From the callback, we unregister another callback that we know is
349 : : * still registered. */
350 : 29 : if (weak_ref4_indexes_n > 0)
351 : : {
352 : 29 : guint new_idx = weak_ref4_indexes[weak_ref4_indexes_n - 1];
353 : :
354 : 29 : weak_ref4_indexes_n--;
355 : 29 : g_object_weak_unref (object, weak_ref4, GUINT_TO_POINTER (new_idx));
356 : :
357 : : /* Behave as if we got this callback invoked still, so that the remainder matches up. */
358 : 29 : weak_ref4_finalizing_notified_skipped++;
359 : 29 : weak_ref4_notified++;
360 : : }
361 : : }
362 : 142 : }
363 : :
364 : : static void
365 : 1 : test_references_many (void)
366 : : {
367 : : GObject *object;
368 : : guint *indexes;
369 : : guint i;
370 : : guint n;
371 : : guint m;
372 : :
373 : : /* Test subscribing a (random) number of weak references. */
374 : 1 : object = g_object_new (TEST_TYPE_OBJECT, NULL);
375 : 1 : n = g_random_int () % 1000;
376 : 1 : indexes = g_new (guint, MAX (n, 1));
377 : 699 : for (i = 0; i < n; i++)
378 : : {
379 : 698 : g_object_weak_ref (object, weak_ref4, GUINT_TO_POINTER (i));
380 : 698 : indexes[i] = i;
381 : : }
382 : 699 : for (i = 0; i < n; i++)
383 : : {
384 : : guint tmp, j;
385 : :
386 : 698 : j = (guint) g_random_int_range ((gint) i, (gint) n);
387 : 698 : tmp = indexes[i];
388 : 698 : indexes[i] = indexes[j];
389 : 698 : indexes[j] = tmp;
390 : : }
391 : 1 : m = g_random_int () % (n + 1u);
392 : 528 : for (i = 0; i < m; i++)
393 : 527 : g_object_weak_unref (object, weak_ref4, GUINT_TO_POINTER (indexes[i]));
394 : 1 : weak_ref4_indexes_n = n - m;
395 : 1 : weak_ref4_indexes = &indexes[m];
396 : 1 : g_object_unref (object);
397 : 1 : g_assert_cmpint (weak_ref4_notified, ==, n - m);
398 : 1 : if (n - m == 0)
399 : : {
400 : 0 : g_assert_cmpint (weak_ref4_finalizing_resurrected, ==, -1);
401 : 0 : g_assert_cmpint (weak_ref4_finalizing_notified, ==, 0);
402 : 0 : g_assert_cmpint (weak_ref4_finalizing_notified_skipped, ==, 0);
403 : : }
404 : 1 : else if (weak_ref4_finalizing_resurrected == TRUE)
405 : : {
406 : 0 : weak_ref4_finalizing_resurrected = 4;
407 : 0 : g_assert_cmpint (weak_ref4_finalizing_notified, ==, 0);
408 : 0 : g_object_unref (object);
409 : 0 : g_assert_cmpint (weak_ref4_notified, ==, n - m);
410 : 0 : g_assert_cmpint (weak_ref4_finalizing_notified + weak_ref4_finalizing_notified_skipped, ==, n - m);
411 : : }
412 : : else
413 : : {
414 : 1 : g_assert_cmpint (weak_ref4_finalizing_resurrected, ==, FALSE);
415 : 1 : g_assert_cmpint (weak_ref4_finalizing_notified + weak_ref4_finalizing_notified_skipped, ==, n - m);
416 : : }
417 : 1 : g_free (indexes);
418 : 1 : }
419 : :
420 : : /*****************************************************************************/
421 : :
422 : : static void notify_two (gpointer data, GObject *former_object);
423 : :
424 : : static void
425 : 1 : notify_one (gpointer data, GObject *former_object)
426 : : {
427 : 1 : g_object_weak_unref (data, notify_two, former_object);
428 : 1 : }
429 : :
430 : : static void
431 : 0 : notify_two (gpointer data, GObject *former_object)
432 : : {
433 : : g_assert_not_reached ();
434 : : }
435 : :
436 : : static void
437 : 1 : test_references_two (void)
438 : : {
439 : : GObject *obj;
440 : :
441 : : /* https://gitlab.gnome.org/GNOME/gtk/-/issues/5542#note_1688809 */
442 : :
443 : 1 : obj = g_object_new (G_TYPE_OBJECT, NULL);
444 : :
445 : 1 : g_object_weak_ref (obj, notify_one, obj);
446 : 1 : g_object_weak_ref (obj, notify_two, obj);
447 : :
448 : 1 : g_object_unref (obj);
449 : 1 : }
450 : :
451 : : /*****************************************************************************/
452 : :
453 : : #define RUN_DISPOSE_N_THREADS 5
454 : :
455 : : GThread *run_dispose_threads[RUN_DISPOSE_N_THREADS];
456 : : GObject *run_dispose_obj;
457 : : gint run_dispose_thread_ready_count;
458 : : const guint RUN_DISPOSE_N_ITERATIONS = 5000;
459 : :
460 : : gint run_dispose_weak_notify_pending;
461 : : gint run_dispose_weak_notify_pending_nested;
462 : :
463 : : static void
464 : 2595 : _run_dispose_weak_notify_nested (gpointer data,
465 : : GObject *where_the_object_was)
466 : : {
467 : 2595 : g_assert_true (run_dispose_obj == where_the_object_was);
468 : 2595 : g_assert_cmpint (g_atomic_int_add (&run_dispose_weak_notify_pending_nested, -1), >, 0);
469 : 2595 : }
470 : :
471 : : static void
472 : 25000 : _run_dispose_weak_notify (gpointer data,
473 : : GObject *where_the_object_was)
474 : : {
475 : 25000 : g_assert_true (run_dispose_obj == where_the_object_was);
476 : 25000 : g_assert_cmpint (g_atomic_int_add (&run_dispose_weak_notify_pending, -1), >, 0);
477 : :
478 : 25000 : if (g_random_int () % 10 == 0)
479 : : {
480 : 2527 : g_object_run_dispose (run_dispose_obj);
481 : : }
482 : :
483 : 25000 : if (g_random_int () % 10 == 0)
484 : : {
485 : 2595 : g_atomic_int_inc (&run_dispose_weak_notify_pending_nested);
486 : 2595 : g_object_weak_ref (run_dispose_obj, _run_dispose_weak_notify_nested, NULL);
487 : : }
488 : 25000 : }
489 : :
490 : : static gpointer
491 : 5 : _run_dispose_thread_fcn (gpointer thread_data)
492 : : {
493 : : guint i;
494 : :
495 : 5 : g_atomic_int_inc (&run_dispose_thread_ready_count);
496 : :
497 : 15 : while (g_atomic_int_get (&run_dispose_thread_ready_count) != RUN_DISPOSE_N_THREADS)
498 : 10 : g_usleep (10);
499 : :
500 : 25005 : for (i = 0; i < RUN_DISPOSE_N_ITERATIONS; i++)
501 : : {
502 : 25000 : g_atomic_int_inc (&run_dispose_weak_notify_pending);
503 : 25000 : g_object_weak_ref (run_dispose_obj, _run_dispose_weak_notify, NULL);
504 : 25000 : if (g_random_int () % 10 == 0)
505 : 2618 : g_object_run_dispose (run_dispose_obj);
506 : : }
507 : :
508 : 5 : g_object_run_dispose (run_dispose_obj);
509 : :
510 : 5 : return NULL;
511 : : }
512 : :
513 : : static void
514 : 1 : test_references_run_dispose (void)
515 : : {
516 : 1 : GQuark quark_weak_notifies = g_quark_from_static_string ("GObject-weak-notifies");
517 : : guint i;
518 : :
519 : 1 : run_dispose_obj = g_object_new (G_TYPE_OBJECT, NULL);
520 : :
521 : 6 : for (i = 0; i < RUN_DISPOSE_N_THREADS; i++)
522 : : {
523 : 5 : run_dispose_threads[i] = g_thread_new ("run-dispose", _run_dispose_thread_fcn, GINT_TO_POINTER (i));
524 : : }
525 : 6 : for (i = 0; i < RUN_DISPOSE_N_THREADS; i++)
526 : : {
527 : 5 : g_thread_join (run_dispose_threads[i]);
528 : : }
529 : :
530 : 1 : g_assert_cmpint (g_atomic_int_get (&run_dispose_weak_notify_pending), ==, 0);
531 : :
532 : 1 : if (g_atomic_int_get (&run_dispose_weak_notify_pending_nested) == 0)
533 : : {
534 : 1 : g_assert_null (g_object_get_qdata (run_dispose_obj, quark_weak_notifies));
535 : : }
536 : : else
537 : : {
538 : 0 : g_assert_nonnull (g_object_get_qdata (run_dispose_obj, quark_weak_notifies));
539 : : }
540 : :
541 : 1 : g_object_run_dispose (run_dispose_obj);
542 : :
543 : 1 : g_assert_cmpint (g_atomic_int_get (&run_dispose_weak_notify_pending), ==, 0);
544 : 1 : g_assert_cmpint (g_atomic_int_get (&run_dispose_weak_notify_pending_nested), ==, 0);
545 : 1 : g_assert_null (g_object_get_qdata (run_dispose_obj, quark_weak_notifies));
546 : :
547 : 1 : g_clear_object (&run_dispose_obj);
548 : 1 : }
549 : :
550 : : /*****************************************************************************/
551 : :
552 : : int
553 : 1 : main (int argc,
554 : : char *argv[])
555 : : {
556 : 1 : g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
557 : 1 : G_LOG_LEVEL_WARNING |
558 : : G_LOG_LEVEL_CRITICAL);
559 : :
560 : 1 : g_test_init (&argc, &argv, NULL);
561 : :
562 : 1 : g_test_add_func ("/gobject/references", test_references);
563 : 1 : g_test_add_func ("/gobject/references-many", test_references_many);
564 : 1 : g_test_add_func ("/gobject/references_two", test_references_two);
565 : 1 : g_test_add_func ("/gobject/references_run_dispose", test_references_run_dispose);
566 : :
567 : 1 : return g_test_run ();
568 : : }
|