1/* GObject - GLib Type, Object, Parameter and Signal Library
2 * Copyright (C) 2005 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General
15 * Public License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20#undef	G_LOG_DOMAIN
21#define	G_LOG_DOMAIN "TestReferences"
22
23#undef G_DISABLE_ASSERT
24#undef G_DISABLE_CHECKS
25#undef G_DISABLE_CAST_CHECKS
26
27#include	<glib-object.h>
28
29/* This test tests weak and toggle references
30 */
31
32static GObject *global_object;
33
34static gboolean object_destroyed;
35static gboolean weak_ref1_notified;
36static gboolean weak_ref2_notified;
37static gboolean toggle_ref1_weakened;
38static gboolean toggle_ref1_strengthened;
39static gboolean toggle_ref2_weakened;
40static gboolean toggle_ref2_strengthened;
41static gboolean toggle_ref3_weakened;
42static gboolean toggle_ref3_strengthened;
43
44/*
45 * TestObject, a parent class for TestObject
46 */
47#define TEST_TYPE_OBJECT          (test_object_get_type ())
48typedef struct _TestObject        TestObject;
49typedef struct _TestObjectClass   TestObjectClass;
50
51struct _TestObject
52{
53  GObject parent_instance;
54};
55struct _TestObjectClass
56{
57  GObjectClass parent_class;
58};
59
60G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT);
61
62static void
63test_object_finalize (GObject *object)
64{
65  object_destroyed = TRUE;
66
67  G_OBJECT_CLASS (test_object_parent_class)->finalize (object);
68}
69
70static void
71test_object_class_init (TestObjectClass *class)
72{
73  GObjectClass *object_class = G_OBJECT_CLASS (class);
74
75  object_class->finalize = test_object_finalize;
76}
77
78static void
79test_object_init (TestObject *test_object)
80{
81}
82
83static void
84clear_flags (void)
85{
86  object_destroyed = FALSE;
87  weak_ref1_notified = FALSE;
88  weak_ref2_notified = FALSE;
89  toggle_ref1_weakened = FALSE;
90  toggle_ref1_strengthened = FALSE;
91  toggle_ref2_weakened = FALSE;
92  toggle_ref2_strengthened = FALSE;
93  toggle_ref3_weakened = FALSE;
94  toggle_ref3_strengthened = FALSE;
95}
96
97static void
98weak_ref1 (gpointer data,
99	   GObject *object)
100{
101  g_assert (object == global_object);
102  g_assert (data == GUINT_TO_POINTER (42));
103
104  weak_ref1_notified = TRUE;
105}
106
107static void
108weak_ref2 (gpointer data,
109	   GObject *object)
110{
111  g_assert (object == global_object);
112  g_assert (data == GUINT_TO_POINTER (24));
113
114  weak_ref2_notified = TRUE;
115}
116
117static void
118toggle_ref1 (gpointer data,
119	     GObject *object,
120	     gboolean is_last_ref)
121{
122  g_assert (object == global_object);
123  g_assert (data == GUINT_TO_POINTER (42));
124
125  if (is_last_ref)
126    toggle_ref1_weakened = TRUE;
127  else
128    toggle_ref1_strengthened = TRUE;
129}
130
131static void
132toggle_ref2 (gpointer data,
133	     GObject *object,
134	     gboolean is_last_ref)
135{
136  g_assert (object == global_object);
137  g_assert (data == GUINT_TO_POINTER (24));
138
139  if (is_last_ref)
140    toggle_ref2_weakened = TRUE;
141  else
142    toggle_ref2_strengthened = TRUE;
143}
144
145static void
146toggle_ref3 (gpointer data,
147	     GObject *object,
148	     gboolean is_last_ref)
149{
150  g_assert (object == global_object);
151  g_assert (data == GUINT_TO_POINTER (34));
152
153  if (is_last_ref)
154    {
155      toggle_ref3_weakened = TRUE;
156      g_object_remove_toggle_ref (object, toggle_ref3, GUINT_TO_POINTER (34));
157    }
158  else
159    toggle_ref3_strengthened = TRUE;
160}
161
162int
163main (int   argc,
164      char *argv[])
165{
166  GObject *object;
167
168  g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
169			  G_LOG_LEVEL_WARNING |
170			  G_LOG_LEVEL_CRITICAL);
171  g_type_init ();
172
173  /* Test basic weak reference operation
174   */
175  global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
176
177  g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
178
179  clear_flags ();
180  g_object_unref (object);
181  g_assert (weak_ref1_notified == TRUE);
182  g_assert (object_destroyed == TRUE);
183
184  /* Test two weak references at once
185   */
186  global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
187
188  g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
189  g_object_weak_ref (object, weak_ref2, GUINT_TO_POINTER (24));
190
191  clear_flags ();
192  g_object_unref (object);
193  g_assert (weak_ref1_notified == TRUE);
194  g_assert (weak_ref2_notified == TRUE);
195  g_assert (object_destroyed == TRUE);
196
197  /* Test remove weak references
198   */
199  global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
200
201  g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
202  g_object_weak_ref (object, weak_ref2, GUINT_TO_POINTER (24));
203  g_object_weak_unref (object, weak_ref1, GUINT_TO_POINTER (42));
204
205  clear_flags ();
206  g_object_unref (object);
207  g_assert (weak_ref1_notified == FALSE);
208  g_assert (weak_ref2_notified == TRUE);
209  g_assert (object_destroyed == TRUE);
210
211  /* Test basic toggle reference operation
212   */
213  global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
214
215  g_object_add_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
216
217  clear_flags ();
218  g_object_unref (object);
219  g_assert (toggle_ref1_weakened == TRUE);
220  g_assert (toggle_ref1_strengthened == FALSE);
221  g_assert (object_destroyed == FALSE);
222
223  clear_flags ();
224  g_object_ref (object);
225  g_assert (toggle_ref1_weakened == FALSE);
226  g_assert (toggle_ref1_strengthened == TRUE);
227  g_assert (object_destroyed == FALSE);
228
229  g_object_unref (object);
230
231  clear_flags ();
232  g_object_remove_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
233  g_assert (toggle_ref1_weakened == FALSE);
234  g_assert (toggle_ref1_strengthened == FALSE);
235  g_assert (object_destroyed == TRUE);
236
237  global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
238
239  /* Test two toggle references at once
240   */
241  g_object_add_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
242  g_object_add_toggle_ref (object, toggle_ref2, GUINT_TO_POINTER (24));
243
244  clear_flags ();
245  g_object_unref (object);
246  g_assert (toggle_ref1_weakened == FALSE);
247  g_assert (toggle_ref1_strengthened == FALSE);
248  g_assert (toggle_ref2_weakened == FALSE);
249  g_assert (toggle_ref2_strengthened == FALSE);
250  g_assert (object_destroyed == FALSE);
251
252  clear_flags ();
253  g_object_remove_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
254  g_assert (toggle_ref1_weakened == FALSE);
255  g_assert (toggle_ref1_strengthened == FALSE);
256  g_assert (toggle_ref2_weakened == TRUE);
257  g_assert (toggle_ref2_strengthened == FALSE);
258  g_assert (object_destroyed == FALSE);
259
260  clear_flags ();
261  g_object_remove_toggle_ref (object, toggle_ref2, GUINT_TO_POINTER (24));
262  g_assert (toggle_ref1_weakened == FALSE);
263  g_assert (toggle_ref1_strengthened == FALSE);
264  g_assert (toggle_ref2_weakened == FALSE);
265  g_assert (toggle_ref2_strengthened == FALSE);
266  g_assert (object_destroyed == TRUE);
267
268  /* Test a toggle reference that removes itself
269   */
270  global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
271
272  g_object_add_toggle_ref (object, toggle_ref3, GUINT_TO_POINTER (34));
273
274  clear_flags ();
275  g_object_unref (object);
276  g_assert (toggle_ref3_weakened == TRUE);
277  g_assert (toggle_ref3_strengthened == FALSE);
278  g_assert (object_destroyed == TRUE);
279
280  return 0;
281}
282