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