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 G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
52
53 static void
54 test_object_finalize (GObject *object)
55 {
56 object_destroyed = TRUE;
57
58 G_OBJECT_CLASS (test_object_parent_class)->finalize (object);
59 }
60
61 static void
62 test_object_class_init (TestObjectClass *class)
63 {
64 GObjectClass *object_class = G_OBJECT_CLASS (class);
65
66 object_class->finalize = test_object_finalize;
67 }
68
69 static void
70 test_object_init (TestObject *test_object)
71 {
72 }
73
74 static void
75 clear_flags (void)
76 {
77 object_destroyed = FALSE;
78 weak_ref1_notified = FALSE;
79 weak_ref2_notified = FALSE;
80 toggle_ref1_weakened = FALSE;
81 toggle_ref1_strengthened = FALSE;
82 toggle_ref2_weakened = FALSE;
83 toggle_ref2_strengthened = FALSE;
84 toggle_ref3_weakened = FALSE;
85 toggle_ref3_strengthened = FALSE;
86 }
87
88 static void
89 weak_ref1 (gpointer data,
90 GObject *object)
91 {
92 g_assert_true (object == global_object);
93 g_assert_cmpint (GPOINTER_TO_INT (data), ==, 42);
94
95 weak_ref1_notified = TRUE;
96 }
97
98 static void
99 weak_ref2 (gpointer data,
100 GObject *object)
101 {
102 g_assert_true (object == global_object);
103 g_assert_cmpint (GPOINTER_TO_INT (data), ==, 24);
104
105 weak_ref2_notified = TRUE;
106 }
107
108 static void
109 toggle_ref1 (gpointer data,
110 GObject *object,
111 gboolean is_last_ref)
112 {
113 g_assert_true (object == global_object);
114 g_assert_cmpint (GPOINTER_TO_INT (data), ==, 42);
115
116 if (is_last_ref)
117 toggle_ref1_weakened = TRUE;
118 else
119 toggle_ref1_strengthened = TRUE;
120 }
121
122 static void
123 toggle_ref2 (gpointer data,
124 GObject *object,
125 gboolean is_last_ref)
126 {
127 g_assert_true (object == global_object);
128 g_assert_cmpint (GPOINTER_TO_INT (data), ==, 24);
129
130 if (is_last_ref)
131 toggle_ref2_weakened = TRUE;
132 else
133 toggle_ref2_strengthened = TRUE;
134 }
135
136 static void
137 toggle_ref3 (gpointer data,
138 GObject *object,
139 gboolean is_last_ref)
140 {
141 g_assert_true (object == global_object);
142 g_assert_cmpint (GPOINTER_TO_INT (data), ==, 34);
143
144 if (is_last_ref)
145 {
146 toggle_ref3_weakened = TRUE;
147 g_object_remove_toggle_ref (object, toggle_ref3, GUINT_TO_POINTER (34));
148 }
149 else
150 toggle_ref3_strengthened = TRUE;
151 }
152
153 static void
154 test_references (void)
155 {
156 GObject *object;
157
158 /* Test basic weak reference operation */
159 global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
160
161 g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
162
163 clear_flags ();
164 g_object_unref (object);
165 g_assert_true (weak_ref1_notified);
166 g_assert_true (object_destroyed);
167
168 /* Test two weak references at once
169 */
170 global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
171
172 g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
173 g_object_weak_ref (object, weak_ref2, GUINT_TO_POINTER (24));
174
175 clear_flags ();
176 g_object_unref (object);
177 g_assert_true (weak_ref1_notified);
178 g_assert_true (weak_ref2_notified);
179 g_assert_true (object_destroyed);
180
181 /* Test remove weak references */
182 global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
183
184 g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
185 g_object_weak_ref (object, weak_ref2, GUINT_TO_POINTER (24));
186 g_object_weak_unref (object, weak_ref1, GUINT_TO_POINTER (42));
187
188 clear_flags ();
189 g_object_unref (object);
190 g_assert_false (weak_ref1_notified);
191 g_assert_true (weak_ref2_notified);
192 g_assert_true (object_destroyed);
193
194 /* Test basic toggle reference operation */
195 global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
196
197 g_object_add_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
198
199 clear_flags ();
200 g_object_unref (object);
201 g_assert_true (toggle_ref1_weakened);
202 g_assert_false (toggle_ref1_strengthened);
203 g_assert_false (object_destroyed);
204
205 clear_flags ();
206 g_object_ref (object);
207 g_assert_false (toggle_ref1_weakened);
208 g_assert_true (toggle_ref1_strengthened);
209 g_assert_false (object_destroyed);
210
211 g_object_unref (object);
212
213 clear_flags ();
214 g_object_remove_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
215 g_assert_false (toggle_ref1_weakened);
216 g_assert_false (toggle_ref1_strengthened);
217 g_assert_true (object_destroyed);
218
219 global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
220
221 /* Test two toggle references at once */
222 g_object_add_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
223 g_object_add_toggle_ref (object, toggle_ref2, GUINT_TO_POINTER (24));
224
225 clear_flags ();
226 g_object_unref (object);
227 g_assert_false (toggle_ref1_weakened);
228 g_assert_false (toggle_ref1_strengthened);
229 g_assert_false (toggle_ref2_weakened);
230 g_assert_false (toggle_ref2_strengthened);
231 g_assert_false (object_destroyed);
232
233 clear_flags ();
234 g_object_remove_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
235 g_assert_false (toggle_ref1_weakened);
236 g_assert_false (toggle_ref1_strengthened);
237 g_assert_true (toggle_ref2_weakened);
238 g_assert_false (toggle_ref2_strengthened);
239 g_assert_false (object_destroyed);
240
241 clear_flags ();
242 /* Check that removing a toggle ref with %NULL data works fine. */
243 g_object_remove_toggle_ref (object, toggle_ref2, NULL);
244 g_assert_false (toggle_ref1_weakened);
245 g_assert_false (toggle_ref1_strengthened);
246 g_assert_false (toggle_ref2_weakened);
247 g_assert_false (toggle_ref2_strengthened);
248 g_assert_true (object_destroyed);
249
250 /* Test a toggle reference that removes itself */
251 global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
252
253 g_object_add_toggle_ref (object, toggle_ref3, GUINT_TO_POINTER (34));
254
255 clear_flags ();
256 g_object_unref (object);
257 g_assert_true (toggle_ref3_weakened);
258 g_assert_false (toggle_ref3_strengthened);
259 g_assert_true (object_destroyed);
260 }
261
262 int
263 main (int argc,
264 char *argv[])
265 {
266 g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
267 G_LOG_LEVEL_WARNING |
268 G_LOG_LEVEL_CRITICAL);
269
270 g_test_init (&argc, &argv, NULL);
271
272 g_test_add_func ("/gobject/references", test_references);
273
274 return g_test_run ();
275 }