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 : 8 : G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
52 : :
53 : : static void
54 : 6 : test_object_finalize (GObject *object)
55 : : {
56 : 6 : object_destroyed = TRUE;
57 : :
58 : 6 : G_OBJECT_CLASS (test_object_parent_class)->finalize (object);
59 : 6 : }
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 : 6 : test_object_init (TestObject *test_object)
71 : : {
72 : 6 : }
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 : : int
286 : 1 : main (int argc,
287 : : char *argv[])
288 : : {
289 : 1 : g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
290 : 1 : G_LOG_LEVEL_WARNING |
291 : : G_LOG_LEVEL_CRITICAL);
292 : :
293 : 1 : g_test_init (&argc, &argv, NULL);
294 : :
295 : 1 : g_test_add_func ("/gobject/references", test_references);
296 : :
297 : 1 : return g_test_run ();
298 : : }
|