1 | #include <glib-object.h> |
2 | |
3 | static void |
4 | test_fundamentals (void) |
5 | { |
6 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_NONE)); |
7 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_INTERFACE)); |
8 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_CHAR)); |
9 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_UCHAR)); |
10 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_BOOLEAN)); |
11 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_INT)); |
12 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_UINT)); |
13 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_LONG)); |
14 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_ULONG)); |
15 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_INT64)); |
16 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_UINT64)); |
17 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_ENUM)); |
18 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_FLAGS)); |
19 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_FLOAT)); |
20 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_DOUBLE)); |
21 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_STRING)); |
22 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_POINTER)); |
23 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_BOXED)); |
24 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_PARAM)); |
25 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_OBJECT)); |
26 | g_assert (G_TYPE_OBJECT == g_object_get_type ()); |
27 | g_assert (G_TYPE_IS_FUNDAMENTAL (G_TYPE_VARIANT)); |
28 | g_assert (G_TYPE_IS_DERIVED (G_TYPE_INITIALLY_UNOWNED)); |
29 | |
30 | g_assert (g_type_fundamental_next () == G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_USER_FIRST)); |
31 | } |
32 | |
33 | static void |
34 | test_type_qdata (void) |
35 | { |
36 | gchar *data; |
37 | |
38 | g_type_set_qdata (G_TYPE_ENUM, quark: g_quark_from_string (string: "bla" ), data: "bla" ); |
39 | data = g_type_get_qdata (G_TYPE_ENUM, quark: g_quark_from_string (string: "bla" )); |
40 | g_assert_cmpstr (data, ==, "bla" ); |
41 | } |
42 | |
43 | static void |
44 | test_type_query (void) |
45 | { |
46 | GTypeQuery query; |
47 | |
48 | g_type_query (G_TYPE_ENUM, query: &query); |
49 | g_assert_cmpint (query.type, ==, G_TYPE_ENUM); |
50 | g_assert_cmpstr (query.type_name, ==, "GEnum" ); |
51 | g_assert_cmpint (query.class_size, ==, sizeof (GEnumClass)); |
52 | g_assert_cmpint (query.instance_size, ==, 0); |
53 | } |
54 | |
55 | typedef struct _MyObject MyObject; |
56 | typedef struct _MyObjectClass MyObjectClass; |
57 | typedef struct _MyObjectClassPrivate MyObjectClassPrivate; |
58 | |
59 | struct _MyObject |
60 | { |
61 | GObject parent_instance; |
62 | |
63 | gint count; |
64 | }; |
65 | |
66 | struct _MyObjectClass |
67 | { |
68 | GObjectClass parent_class; |
69 | }; |
70 | |
71 | struct _MyObjectClassPrivate |
72 | { |
73 | gint secret_class_count; |
74 | }; |
75 | |
76 | static GType my_object_get_type (void); |
77 | G_DEFINE_TYPE_WITH_CODE (MyObject, my_object, G_TYPE_OBJECT, |
78 | g_type_add_class_private (g_define_type_id, sizeof (MyObjectClassPrivate)) ); |
79 | |
80 | static void |
81 | my_object_init (MyObject *obj) |
82 | { |
83 | obj->count = 42; |
84 | } |
85 | |
86 | static void |
87 | my_object_class_init (MyObjectClass *klass) |
88 | { |
89 | } |
90 | |
91 | static void |
92 | test_class_private (void) |
93 | { |
94 | GObject *obj; |
95 | MyObjectClass *class; |
96 | MyObjectClassPrivate *priv; |
97 | |
98 | obj = g_object_new (object_type: my_object_get_type (), NULL); |
99 | |
100 | class = g_type_class_ref (type: my_object_get_type ()); |
101 | priv = G_TYPE_CLASS_GET_PRIVATE (class, my_object_get_type (), MyObjectClassPrivate); |
102 | priv->secret_class_count = 13; |
103 | g_type_class_unref (g_class: class); |
104 | |
105 | g_object_unref (object: obj); |
106 | |
107 | g_assert_cmpint (g_type_qname (my_object_get_type ()), ==, g_quark_from_string ("MyObject" )); |
108 | } |
109 | |
110 | static void |
111 | test_clear (void) |
112 | { |
113 | GObject *o = NULL; |
114 | GObject *tmp; |
115 | |
116 | g_clear_object (&o); |
117 | g_assert (o == NULL); |
118 | |
119 | tmp = g_object_new (G_TYPE_OBJECT, NULL); |
120 | g_assert_cmpint (tmp->ref_count, ==, 1); |
121 | o = g_object_ref (tmp); |
122 | g_assert (o != NULL); |
123 | |
124 | g_assert_cmpint (tmp->ref_count, ==, 2); |
125 | g_clear_object (&o); |
126 | g_assert_cmpint (tmp->ref_count, ==, 1); |
127 | g_assert (o == NULL); |
128 | |
129 | g_object_unref (object: tmp); |
130 | } |
131 | |
132 | static void |
133 | test_clear_function (void) |
134 | { |
135 | GObject *o = NULL; |
136 | GObject *tmp; |
137 | |
138 | (g_clear_object) (object_ptr: &o); |
139 | g_assert (o == NULL); |
140 | |
141 | tmp = g_object_new (G_TYPE_OBJECT, NULL); |
142 | g_assert_cmpint (tmp->ref_count, ==, 1); |
143 | o = g_object_ref (tmp); |
144 | g_assert (o != NULL); |
145 | |
146 | g_assert_cmpint (tmp->ref_count, ==, 2); |
147 | (g_clear_object) (object_ptr: &o); |
148 | g_assert_cmpint (tmp->ref_count, ==, 1); |
149 | g_assert (o == NULL); |
150 | |
151 | g_object_unref (object: tmp); |
152 | } |
153 | |
154 | static void |
155 | test_set (void) |
156 | { |
157 | GObject *o = NULL; |
158 | GObject *tmp; |
159 | gpointer tmp_weak = NULL; |
160 | |
161 | g_assert (!g_set_object (&o, NULL)); |
162 | g_assert (o == NULL); |
163 | |
164 | tmp = g_object_new (G_TYPE_OBJECT, NULL); |
165 | tmp_weak = tmp; |
166 | g_object_add_weak_pointer (object: tmp, weak_pointer_location: &tmp_weak); |
167 | g_assert_cmpint (tmp->ref_count, ==, 1); |
168 | |
169 | g_assert (g_set_object (&o, tmp)); |
170 | g_assert (o == tmp); |
171 | g_assert_cmpint (tmp->ref_count, ==, 2); |
172 | |
173 | g_object_unref (object: tmp); |
174 | g_assert_cmpint (tmp->ref_count, ==, 1); |
175 | |
176 | /* Setting it again shouldn’t cause finalisation. */ |
177 | g_assert (!g_set_object (&o, tmp)); |
178 | g_assert (o == tmp); |
179 | g_assert_cmpint (tmp->ref_count, ==, 1); |
180 | g_assert_nonnull (tmp_weak); |
181 | |
182 | g_assert (g_set_object (&o, NULL)); |
183 | g_assert (o == NULL); |
184 | g_assert_null (tmp_weak); |
185 | } |
186 | |
187 | static void |
188 | test_set_function (void) |
189 | { |
190 | GObject *o = NULL; |
191 | GObject *tmp; |
192 | gpointer tmp_weak = NULL; |
193 | |
194 | g_assert (!(g_set_object) (&o, NULL)); |
195 | g_assert (o == NULL); |
196 | |
197 | tmp = g_object_new (G_TYPE_OBJECT, NULL); |
198 | tmp_weak = tmp; |
199 | g_object_add_weak_pointer (object: tmp, weak_pointer_location: &tmp_weak); |
200 | g_assert_cmpint (tmp->ref_count, ==, 1); |
201 | |
202 | g_assert ((g_set_object) (&o, tmp)); |
203 | g_assert (o == tmp); |
204 | g_assert_cmpint (tmp->ref_count, ==, 2); |
205 | |
206 | g_object_unref (object: tmp); |
207 | g_assert_cmpint (tmp->ref_count, ==, 1); |
208 | |
209 | /* Setting it again shouldn’t cause finalisation. */ |
210 | g_assert (!(g_set_object) (&o, tmp)); |
211 | g_assert (o == tmp); |
212 | g_assert_cmpint (tmp->ref_count, ==, 1); |
213 | g_assert_nonnull (tmp_weak); |
214 | |
215 | g_assert ((g_set_object) (&o, NULL)); |
216 | g_assert (o == NULL); |
217 | g_assert_null (tmp_weak); |
218 | } |
219 | |
220 | static void |
221 | test_set_derived_type (void) |
222 | { |
223 | GBinding *obj = NULL; |
224 | GObject *o = NULL; |
225 | GBinding *b = NULL; |
226 | |
227 | g_test_summary (summary: "Check that g_set_object() doesn’t give strict aliasing " |
228 | "warnings when used on types derived from GObject" ); |
229 | |
230 | g_assert_false (g_set_object (&o, NULL)); |
231 | g_assert_null (o); |
232 | |
233 | g_assert_false (g_set_object (&b, NULL)); |
234 | g_assert_null (b); |
235 | |
236 | obj = g_object_new (object_type: my_object_get_type (), NULL); |
237 | |
238 | g_assert_true (g_set_object (&o, G_OBJECT (obj))); |
239 | g_assert_true (o == G_OBJECT (obj)); |
240 | |
241 | g_assert_true (g_set_object (&b, obj)); |
242 | g_assert_true (b == obj); |
243 | |
244 | g_object_unref (object: obj); |
245 | g_clear_object (&b); |
246 | g_clear_object (&o); |
247 | } |
248 | |
249 | static void |
250 | toggle_cb (gpointer data, GObject *obj, gboolean is_last) |
251 | { |
252 | gboolean *b = data; |
253 | |
254 | *b = TRUE; |
255 | } |
256 | |
257 | static void |
258 | test_object_value (void) |
259 | { |
260 | GObject *v; |
261 | GObject *v2; |
262 | GValue value = G_VALUE_INIT; |
263 | gboolean toggled = FALSE; |
264 | |
265 | g_value_init (value: &value, G_TYPE_OBJECT); |
266 | |
267 | v = g_object_new (G_TYPE_OBJECT, NULL); |
268 | g_object_add_toggle_ref (object: v, notify: toggle_cb, data: &toggled); |
269 | |
270 | g_value_take_object (value: &value, v_object: v); |
271 | |
272 | v2 = g_value_get_object (value: &value); |
273 | g_assert (v2 == v); |
274 | |
275 | v2 = g_value_dup_object (value: &value); |
276 | g_assert (v2 == v); /* objects use ref/unref for copy/free */ |
277 | g_object_unref (object: v2); |
278 | |
279 | g_assert (!toggled); |
280 | g_value_unset (value: &value); |
281 | g_assert (toggled); |
282 | |
283 | /* test the deprecated variant too */ |
284 | g_value_init (value: &value, G_TYPE_OBJECT); |
285 | /* get a new reference */ |
286 | g_object_ref (v); |
287 | |
288 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
289 | g_value_set_object_take_ownership (value: &value, v_object: v); |
290 | G_GNUC_END_IGNORE_DEPRECATIONS |
291 | |
292 | toggled = FALSE; |
293 | g_value_unset (value: &value); |
294 | g_assert (toggled); |
295 | |
296 | g_object_remove_toggle_ref (object: v, notify: toggle_cb, data: &toggled); |
297 | } |
298 | |
299 | static void |
300 | test_initially_unowned (void) |
301 | { |
302 | GObject *obj; |
303 | |
304 | obj = g_object_new (G_TYPE_INITIALLY_UNOWNED, NULL); |
305 | g_assert (g_object_is_floating (obj)); |
306 | g_assert_cmpint (obj->ref_count, ==, 1); |
307 | |
308 | g_object_ref_sink (obj); |
309 | g_assert (!g_object_is_floating (obj)); |
310 | g_assert_cmpint (obj->ref_count, ==, 1); |
311 | |
312 | g_object_ref_sink (obj); |
313 | g_assert (!g_object_is_floating (obj)); |
314 | g_assert_cmpint (obj->ref_count, ==, 2); |
315 | |
316 | g_object_unref (object: obj); |
317 | g_assert_cmpint (obj->ref_count, ==, 1); |
318 | |
319 | g_object_force_floating (object: obj); |
320 | g_assert (g_object_is_floating (obj)); |
321 | g_assert_cmpint (obj->ref_count, ==, 1); |
322 | |
323 | g_object_ref_sink (obj); |
324 | g_object_unref (object: obj); |
325 | } |
326 | |
327 | static void |
328 | test_weak_pointer (void) |
329 | { |
330 | GObject *obj; |
331 | gpointer weak; |
332 | gpointer weak2; |
333 | |
334 | weak = weak2 = obj = g_object_new (G_TYPE_OBJECT, NULL); |
335 | g_assert_cmpint (obj->ref_count, ==, 1); |
336 | |
337 | g_object_add_weak_pointer (object: obj, weak_pointer_location: &weak); |
338 | g_object_add_weak_pointer (object: obj, weak_pointer_location: &weak2); |
339 | g_assert_cmpint (obj->ref_count, ==, 1); |
340 | g_assert (weak == obj); |
341 | g_assert (weak2 == obj); |
342 | |
343 | g_object_remove_weak_pointer (object: obj, weak_pointer_location: &weak2); |
344 | g_assert_cmpint (obj->ref_count, ==, 1); |
345 | g_assert (weak == obj); |
346 | g_assert (weak2 == obj); |
347 | |
348 | g_object_unref (object: obj); |
349 | g_assert (weak == NULL); |
350 | g_assert (weak2 == obj); |
351 | } |
352 | |
353 | static void |
354 | test_weak_pointer_clear (void) |
355 | { |
356 | GObject *obj; |
357 | gpointer weak = NULL; |
358 | |
359 | g_clear_weak_pointer (&weak); |
360 | g_assert_null (weak); |
361 | |
362 | weak = obj = g_object_new (G_TYPE_OBJECT, NULL); |
363 | g_assert_cmpint (obj->ref_count, ==, 1); |
364 | |
365 | g_object_add_weak_pointer (object: obj, weak_pointer_location: &weak); |
366 | g_assert_cmpint (obj->ref_count, ==, 1); |
367 | g_assert_true (weak == obj); |
368 | |
369 | g_clear_weak_pointer (&weak); |
370 | g_assert_cmpint (obj->ref_count, ==, 1); |
371 | g_assert_null (weak); |
372 | |
373 | g_object_unref (object: obj); |
374 | } |
375 | |
376 | static void |
377 | test_weak_pointer_clear_function (void) |
378 | { |
379 | GObject *obj; |
380 | gpointer weak = NULL; |
381 | |
382 | (g_clear_weak_pointer) (weak_pointer_location: &weak); |
383 | g_assert_null (weak); |
384 | |
385 | weak = obj = g_object_new (G_TYPE_OBJECT, NULL); |
386 | g_assert_cmpint (obj->ref_count, ==, 1); |
387 | |
388 | g_object_add_weak_pointer (object: obj, weak_pointer_location: &weak); |
389 | g_assert_cmpint (obj->ref_count, ==, 1); |
390 | g_assert_true (weak == obj); |
391 | |
392 | (g_clear_weak_pointer) (weak_pointer_location: &weak); |
393 | g_assert_cmpint (obj->ref_count, ==, 1); |
394 | g_assert_null (weak); |
395 | |
396 | g_object_unref (object: obj); |
397 | } |
398 | |
399 | static void |
400 | test_weak_pointer_set (void) |
401 | { |
402 | GObject *obj; |
403 | gpointer weak = NULL; |
404 | |
405 | g_assert_false (g_set_weak_pointer (&weak, NULL)); |
406 | g_assert_null (weak); |
407 | |
408 | obj = g_object_new (G_TYPE_OBJECT, NULL); |
409 | g_assert_cmpint (obj->ref_count, ==, 1); |
410 | |
411 | g_assert_true (g_set_weak_pointer (&weak, obj)); |
412 | g_assert_cmpint (obj->ref_count, ==, 1); |
413 | g_assert_true (weak == obj); |
414 | |
415 | g_assert_true (g_set_weak_pointer (&weak, NULL)); |
416 | g_assert_cmpint (obj->ref_count, ==, 1); |
417 | g_assert_null (weak); |
418 | |
419 | g_assert_true (g_set_weak_pointer (&weak, obj)); |
420 | g_assert_cmpint (obj->ref_count, ==, 1); |
421 | g_assert_true (weak == obj); |
422 | |
423 | g_object_unref (object: obj); |
424 | g_assert_null (weak); |
425 | } |
426 | |
427 | static void |
428 | test_weak_pointer_set_function (void) |
429 | { |
430 | GObject *obj; |
431 | gpointer weak = NULL; |
432 | |
433 | g_assert_false ((g_set_weak_pointer) (&weak, NULL)); |
434 | g_assert_null (weak); |
435 | |
436 | obj = g_object_new (G_TYPE_OBJECT, NULL); |
437 | g_assert_cmpint (obj->ref_count, ==, 1); |
438 | |
439 | g_assert_true ((g_set_weak_pointer) (&weak, obj)); |
440 | g_assert_cmpint (obj->ref_count, ==, 1); |
441 | g_assert_true (weak == obj); |
442 | |
443 | g_assert_true ((g_set_weak_pointer) (&weak, NULL)); |
444 | g_assert_cmpint (obj->ref_count, ==, 1); |
445 | g_assert_null (weak); |
446 | |
447 | g_assert_true ((g_set_weak_pointer) (&weak, obj)); |
448 | g_assert_cmpint (obj->ref_count, ==, 1); |
449 | g_assert_true (weak == obj); |
450 | |
451 | g_object_unref (object: obj); |
452 | g_assert_null (weak); |
453 | } |
454 | |
455 | /* See gobject/tests/threadtests.c for the threaded version */ |
456 | static void |
457 | test_weak_ref (void) |
458 | { |
459 | GObject *obj; |
460 | GObject *obj2; |
461 | GObject *tmp; |
462 | GWeakRef weak = { { GUINT_TO_POINTER (0xDEADBEEFU) } }; |
463 | GWeakRef weak2 = { { GUINT_TO_POINTER (0xDEADBEEFU) } }; |
464 | GWeakRef weak3 = { { GUINT_TO_POINTER (0xDEADBEEFU) } }; |
465 | GWeakRef *dynamic_weak = g_new (GWeakRef, 1); |
466 | |
467 | /* you can initialize to empty like this... */ |
468 | g_weak_ref_init (weak_ref: &weak2, NULL); |
469 | g_assert (g_weak_ref_get (&weak2) == NULL); |
470 | |
471 | /* ... or via an initializer */ |
472 | g_weak_ref_init (weak_ref: &weak3, NULL); |
473 | g_assert (g_weak_ref_get (&weak3) == NULL); |
474 | |
475 | obj = g_object_new (G_TYPE_OBJECT, NULL); |
476 | g_assert_cmpint (obj->ref_count, ==, 1); |
477 | |
478 | obj2 = g_object_new (G_TYPE_OBJECT, NULL); |
479 | g_assert_cmpint (obj2->ref_count, ==, 1); |
480 | |
481 | /* you can init with an object (even if uninitialized) */ |
482 | g_weak_ref_init (weak_ref: &weak, object: obj); |
483 | g_weak_ref_init (weak_ref: dynamic_weak, object: obj); |
484 | /* or set to point at an object, if initialized (maybe to 0) */ |
485 | g_weak_ref_set (weak_ref: &weak2, object: obj); |
486 | g_weak_ref_set (weak_ref: &weak3, object: obj); |
487 | /* none of this affects its refcount */ |
488 | g_assert_cmpint (obj->ref_count, ==, 1); |
489 | |
490 | /* getting the value takes a ref */ |
491 | tmp = g_weak_ref_get (weak_ref: &weak); |
492 | g_assert (tmp == obj); |
493 | g_assert_cmpint (obj->ref_count, ==, 2); |
494 | g_object_unref (object: tmp); |
495 | g_assert_cmpint (obj->ref_count, ==, 1); |
496 | |
497 | tmp = g_weak_ref_get (weak_ref: &weak2); |
498 | g_assert (tmp == obj); |
499 | g_assert_cmpint (obj->ref_count, ==, 2); |
500 | g_object_unref (object: tmp); |
501 | g_assert_cmpint (obj->ref_count, ==, 1); |
502 | |
503 | tmp = g_weak_ref_get (weak_ref: &weak3); |
504 | g_assert (tmp == obj); |
505 | g_assert_cmpint (obj->ref_count, ==, 2); |
506 | g_object_unref (object: tmp); |
507 | g_assert_cmpint (obj->ref_count, ==, 1); |
508 | |
509 | tmp = g_weak_ref_get (weak_ref: dynamic_weak); |
510 | g_assert (tmp == obj); |
511 | g_assert_cmpint (obj->ref_count, ==, 2); |
512 | g_object_unref (object: tmp); |
513 | g_assert_cmpint (obj->ref_count, ==, 1); |
514 | |
515 | /* clearing a weak ref stops tracking */ |
516 | g_weak_ref_clear (weak_ref: &weak); |
517 | |
518 | /* setting a weak ref to NULL stops tracking too */ |
519 | g_weak_ref_set (weak_ref: &weak2, NULL); |
520 | g_assert (g_weak_ref_get (&weak2) == NULL); |
521 | g_weak_ref_clear (weak_ref: &weak2); |
522 | |
523 | /* setting a weak ref to a new object stops tracking the old one */ |
524 | g_weak_ref_set (weak_ref: dynamic_weak, object: obj2); |
525 | tmp = g_weak_ref_get (weak_ref: dynamic_weak); |
526 | g_assert (tmp == obj2); |
527 | g_assert_cmpint (obj2->ref_count, ==, 2); |
528 | g_object_unref (object: tmp); |
529 | g_assert_cmpint (obj2->ref_count, ==, 1); |
530 | |
531 | g_assert_cmpint (obj->ref_count, ==, 1); |
532 | |
533 | /* free the object: weak3 is the only one left pointing there */ |
534 | g_object_unref (object: obj); |
535 | g_assert (g_weak_ref_get (&weak3) == NULL); |
536 | |
537 | /* setting a weak ref to a new object stops tracking the old one */ |
538 | g_weak_ref_set (weak_ref: dynamic_weak, object: obj2); |
539 | tmp = g_weak_ref_get (weak_ref: dynamic_weak); |
540 | g_assert (tmp == obj2); |
541 | g_assert_cmpint (obj2->ref_count, ==, 2); |
542 | g_object_unref (object: tmp); |
543 | g_assert_cmpint (obj2->ref_count, ==, 1); |
544 | |
545 | g_weak_ref_clear (weak_ref: &weak3); |
546 | |
547 | /* clear and free dynamic_weak... */ |
548 | g_weak_ref_clear (weak_ref: dynamic_weak); |
549 | |
550 | /* ... to prove that doing so stops this from being a use-after-free */ |
551 | g_object_unref (object: obj2); |
552 | g_free (mem: dynamic_weak); |
553 | } |
554 | |
555 | typedef struct |
556 | { |
557 | gboolean should_be_last; |
558 | gint count; |
559 | } Count; |
560 | |
561 | static void |
562 | toggle_notify (gpointer data, |
563 | GObject *obj, |
564 | gboolean is_last) |
565 | { |
566 | Count *c = data; |
567 | |
568 | g_assert (is_last == c->should_be_last); |
569 | |
570 | c->count++; |
571 | } |
572 | |
573 | static void |
574 | test_toggle_ref (void) |
575 | { |
576 | GObject *obj; |
577 | Count c, c2; |
578 | |
579 | obj = g_object_new (G_TYPE_OBJECT, NULL); |
580 | |
581 | g_object_add_toggle_ref (object: obj, notify: toggle_notify, data: &c); |
582 | g_object_add_toggle_ref (object: obj, notify: toggle_notify, data: &c2); |
583 | |
584 | c.should_be_last = c2.should_be_last = TRUE; |
585 | c.count = c2.count = 0; |
586 | |
587 | g_object_unref (object: obj); |
588 | |
589 | g_assert_cmpint (c.count, ==, 0); |
590 | g_assert_cmpint (c2.count, ==, 0); |
591 | |
592 | g_object_ref (obj); |
593 | |
594 | g_assert_cmpint (c.count, ==, 0); |
595 | g_assert_cmpint (c2.count, ==, 0); |
596 | |
597 | g_object_remove_toggle_ref (object: obj, notify: toggle_notify, data: &c2); |
598 | |
599 | g_object_unref (object: obj); |
600 | |
601 | g_assert_cmpint (c.count, ==, 1); |
602 | |
603 | c.should_be_last = FALSE; |
604 | |
605 | g_object_ref (obj); |
606 | |
607 | g_assert_cmpint (c.count, ==, 2); |
608 | |
609 | c.should_be_last = TRUE; |
610 | |
611 | g_object_unref (object: obj); |
612 | |
613 | g_assert_cmpint (c.count, ==, 3); |
614 | |
615 | g_object_remove_toggle_ref (object: obj, notify: toggle_notify, data: &c); |
616 | } |
617 | |
618 | static gboolean destroyed; |
619 | static gint value; |
620 | |
621 | static void |
622 | data_destroy (gpointer data) |
623 | { |
624 | g_assert_cmpint (GPOINTER_TO_INT (data), ==, value); |
625 | |
626 | destroyed = TRUE; |
627 | } |
628 | |
629 | static void |
630 | test_object_qdata (void) |
631 | { |
632 | GObject *obj; |
633 | gpointer v; |
634 | GQuark quark; |
635 | |
636 | obj = g_object_new (G_TYPE_OBJECT, NULL); |
637 | |
638 | value = 1; |
639 | destroyed = FALSE; |
640 | g_object_set_data_full (object: obj, key: "test" , GINT_TO_POINTER (1), destroy: data_destroy); |
641 | v = g_object_get_data (object: obj, key: "test" ); |
642 | g_assert_cmpint (GPOINTER_TO_INT (v), ==, 1); |
643 | g_object_set_data_full (object: obj, key: "test" , GINT_TO_POINTER (2), destroy: data_destroy); |
644 | g_assert (destroyed); |
645 | value = 2; |
646 | destroyed = FALSE; |
647 | v = g_object_steal_data (object: obj, key: "test" ); |
648 | g_assert_cmpint (GPOINTER_TO_INT (v), ==, 2); |
649 | g_assert (!destroyed); |
650 | |
651 | value = 1; |
652 | destroyed = FALSE; |
653 | quark = g_quark_from_string (string: "test" ); |
654 | g_object_set_qdata_full (object: obj, quark, GINT_TO_POINTER (1), destroy: data_destroy); |
655 | v = g_object_get_qdata (object: obj, quark); |
656 | g_assert_cmpint (GPOINTER_TO_INT (v), ==, 1); |
657 | g_object_set_qdata_full (object: obj, quark, GINT_TO_POINTER (2), destroy: data_destroy); |
658 | g_assert (destroyed); |
659 | value = 2; |
660 | destroyed = FALSE; |
661 | v = g_object_steal_qdata (object: obj, quark); |
662 | g_assert_cmpint (GPOINTER_TO_INT (v), ==, 2); |
663 | g_assert (!destroyed); |
664 | |
665 | g_object_set_qdata_full (object: obj, quark, GINT_TO_POINTER (3), destroy: data_destroy); |
666 | value = 3; |
667 | destroyed = FALSE; |
668 | g_object_unref (object: obj); |
669 | |
670 | g_assert (destroyed); |
671 | } |
672 | |
673 | typedef struct { |
674 | const gchar *value; |
675 | gint refcount; |
676 | } Value; |
677 | |
678 | static gpointer |
679 | ref_value (gpointer value, gpointer user_data) |
680 | { |
681 | Value *v = value; |
682 | Value **old_value_p = user_data; |
683 | |
684 | if (old_value_p) |
685 | *old_value_p = v; |
686 | |
687 | if (v) |
688 | v->refcount += 1; |
689 | |
690 | return value; |
691 | } |
692 | |
693 | static void |
694 | unref_value (gpointer value) |
695 | { |
696 | Value *v = value; |
697 | |
698 | v->refcount -= 1; |
699 | if (v->refcount == 0) |
700 | g_free (mem: value); |
701 | } |
702 | |
703 | static |
704 | Value * |
705 | new_value (const gchar *s) |
706 | { |
707 | Value *v; |
708 | |
709 | v = g_new (Value, 1); |
710 | v->value = s; |
711 | v->refcount = 1; |
712 | |
713 | return v; |
714 | } |
715 | |
716 | static void |
717 | test_object_qdata2 (void) |
718 | { |
719 | GObject *obj; |
720 | Value *v, *v1, *v2, *v3, *old_val; |
721 | GDestroyNotify old_destroy; |
722 | gboolean res; |
723 | |
724 | obj = g_object_new (G_TYPE_OBJECT, NULL); |
725 | |
726 | v1 = new_value (s: "bla" ); |
727 | |
728 | g_object_set_data_full (object: obj, key: "test" , data: v1, destroy: unref_value); |
729 | |
730 | v = g_object_get_data (object: obj, key: "test" ); |
731 | g_assert_cmpstr (v->value, ==, "bla" ); |
732 | g_assert_cmpint (v->refcount, ==, 1); |
733 | |
734 | v = g_object_dup_data (object: obj, key: "test" , dup_func: ref_value, user_data: &old_val); |
735 | g_assert (old_val == v1); |
736 | g_assert_cmpstr (v->value, ==, "bla" ); |
737 | g_assert_cmpint (v->refcount, ==, 2); |
738 | unref_value (value: v); |
739 | |
740 | v = g_object_dup_data (object: obj, key: "nono" , dup_func: ref_value, user_data: &old_val); |
741 | g_assert (old_val == NULL); |
742 | g_assert (v == NULL); |
743 | |
744 | v2 = new_value (s: "not" ); |
745 | |
746 | res = g_object_replace_data (object: obj, key: "test" , oldval: v1, newval: v2, destroy: unref_value, old_destroy: &old_destroy); |
747 | g_assert (res == TRUE); |
748 | g_assert (old_destroy == unref_value); |
749 | g_assert_cmpstr (v1->value, ==, "bla" ); |
750 | g_assert_cmpint (v1->refcount, ==, 1); |
751 | |
752 | v = g_object_get_data (object: obj, key: "test" ); |
753 | g_assert_cmpstr (v->value, ==, "not" ); |
754 | g_assert_cmpint (v->refcount, ==, 1); |
755 | |
756 | v3 = new_value (s: "xyz" ); |
757 | res = g_object_replace_data (object: obj, key: "test" , oldval: v1, newval: v3, destroy: unref_value, old_destroy: &old_destroy); |
758 | g_assert (res == FALSE); |
759 | g_assert_cmpstr (v2->value, ==, "not" ); |
760 | g_assert_cmpint (v2->refcount, ==, 1); |
761 | |
762 | unref_value (value: v1); |
763 | |
764 | res = g_object_replace_data (object: obj, key: "test" , NULL, newval: v3, destroy: unref_value, old_destroy: &old_destroy); |
765 | g_assert (res == FALSE); |
766 | g_assert_cmpstr (v2->value, ==, "not" ); |
767 | g_assert_cmpint (v2->refcount, ==, 1); |
768 | |
769 | res = g_object_replace_data (object: obj, key: "test" , oldval: v2, NULL, destroy: unref_value, old_destroy: &old_destroy); |
770 | g_assert (res == TRUE); |
771 | g_assert (old_destroy == unref_value); |
772 | g_assert_cmpstr (v2->value, ==, "not" ); |
773 | g_assert_cmpint (v2->refcount, ==, 1); |
774 | |
775 | unref_value (value: v2); |
776 | |
777 | v = g_object_get_data (object: obj, key: "test" ); |
778 | g_assert (v == NULL); |
779 | |
780 | res = g_object_replace_data (object: obj, key: "test" , NULL, newval: v3, destroy: unref_value, old_destroy: &old_destroy); |
781 | g_assert (res == TRUE); |
782 | |
783 | v = g_object_get_data (object: obj, key: "test" ); |
784 | g_assert (v == v3); |
785 | |
786 | ref_value (value: v3, NULL); |
787 | g_assert_cmpint (v3->refcount, ==, 2); |
788 | g_object_unref (object: obj); |
789 | g_assert_cmpint (v3->refcount, ==, 1); |
790 | unref_value (value: v3); |
791 | } |
792 | |
793 | int |
794 | main (int argc, char **argv) |
795 | { |
796 | g_test_init (argc: &argc, argv: &argv, NULL); |
797 | |
798 | g_test_add_func (testpath: "/type/fundamentals" , test_func: test_fundamentals); |
799 | g_test_add_func (testpath: "/type/qdata" , test_func: test_type_qdata); |
800 | g_test_add_func (testpath: "/type/query" , test_func: test_type_query); |
801 | g_test_add_func (testpath: "/type/class-private" , test_func: test_class_private); |
802 | g_test_add_func (testpath: "/object/clear" , test_func: test_clear); |
803 | g_test_add_func (testpath: "/object/clear-function" , test_func: test_clear_function); |
804 | g_test_add_func (testpath: "/object/set" , test_func: test_set); |
805 | g_test_add_func (testpath: "/object/set-function" , test_func: test_set_function); |
806 | g_test_add_func (testpath: "/object/set/derived-type" , test_func: test_set_derived_type); |
807 | g_test_add_func (testpath: "/object/value" , test_func: test_object_value); |
808 | g_test_add_func (testpath: "/object/initially-unowned" , test_func: test_initially_unowned); |
809 | g_test_add_func (testpath: "/object/weak-pointer" , test_func: test_weak_pointer); |
810 | g_test_add_func (testpath: "/object/weak-pointer/clear" , test_func: test_weak_pointer_clear); |
811 | g_test_add_func (testpath: "/object/weak-pointer/clear-function" , test_func: test_weak_pointer_clear_function); |
812 | g_test_add_func (testpath: "/object/weak-pointer/set" , test_func: test_weak_pointer_set); |
813 | g_test_add_func (testpath: "/object/weak-pointer/set-function" , test_func: test_weak_pointer_set_function); |
814 | g_test_add_func (testpath: "/object/weak-ref" , test_func: test_weak_ref); |
815 | g_test_add_func (testpath: "/object/toggle-ref" , test_func: test_toggle_ref); |
816 | g_test_add_func (testpath: "/object/qdata" , test_func: test_object_qdata); |
817 | g_test_add_func (testpath: "/object/qdata2" , test_func: test_object_qdata2); |
818 | |
819 | return g_test_run (); |
820 | } |
821 | |