Branch data Line data Source code
1 : : /* GObject - GLib Type, Object, Parameter and Signal Library
2 : : * override.c: Closure override test program
3 : : * Copyright (C) 2001, James Henstridge
4 : : * Copyright (C) 2003, Red Hat, Inc.
5 : : *
6 : : * SPDX-License-Identifier: LGPL-2.1-or-later
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Lesser General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2.1 of the License, or (at your option) any later version.
12 : : *
13 : : * This library is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : * Lesser General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU Lesser General
19 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 : : */
21 : :
22 : : #include <glib.h>
23 : : #include <glib-object.h>
24 : :
25 : : #include "testcommon.h"
26 : :
27 : : static guint foo_signal_id = 0;
28 : : static guint bar_signal_id = 0;
29 : : static guint baz_signal_id = 0;
30 : :
31 : : static GType test_i_get_type (void);
32 : : static GType test_a_get_type (void);
33 : : static GType test_b_get_type (void);
34 : : static GType test_c_get_type (void);
35 : :
36 : : static void record (const gchar *str);
37 : :
38 : : #define TEST_TYPE_I (test_i_get_type ())
39 : :
40 : : typedef struct _TestI TestI;
41 : : typedef struct _TestIClass TestIClass;
42 : :
43 : : struct _TestIClass
44 : : {
45 : : GTypeInterface base_iface;
46 : : };
47 : :
48 : : static void
49 : 3 : test_i_foo (TestI *self)
50 : : {
51 : 3 : record ("TestI::foo");
52 : 3 : }
53 : :
54 : : static void
55 : 1 : test_i_default_init (gpointer g_class)
56 : : {
57 : 1 : foo_signal_id = g_signal_newv ("foo",
58 : : TEST_TYPE_I,
59 : : G_SIGNAL_RUN_LAST,
60 : : g_cclosure_new(G_CALLBACK(test_i_foo),
61 : : NULL, NULL),
62 : : NULL, NULL,
63 : : g_cclosure_marshal_VOID__VOID,
64 : : G_TYPE_NONE, 0, NULL);
65 : 1 : }
66 : :
67 : 2 : static DEFINE_IFACE (TestI, test_i, NULL, test_i_default_init)
68 : :
69 : : #define TEST_TYPE_A (test_a_get_type())
70 : :
71 : : typedef struct _TestA TestA;
72 : : typedef struct _TestAClass TestAClass;
73 : :
74 : : struct _TestA {
75 : : GObject parent;
76 : : };
77 : : struct _TestAClass {
78 : : GObjectClass parent_class;
79 : :
80 : : void (* bar) (TestA *self);
81 : : };
82 : :
83 : : static void
84 : 3 : test_a_foo (TestI *self)
85 : : {
86 : 3 : GValue args[1] = { G_VALUE_INIT };
87 : :
88 : 3 : record ("TestA::foo");
89 : :
90 : 3 : g_value_init (&args[0], TEST_TYPE_A);
91 : 3 : g_value_set_object (&args[0], self);
92 : :
93 : 3 : g_assert_cmpint (g_signal_get_invocation_hint (self)->signal_id,
94 : : ==,
95 : : foo_signal_id);
96 : 3 : g_signal_chain_from_overridden (args, NULL);
97 : :
98 : 3 : g_value_unset (&args[0]);
99 : 3 : }
100 : :
101 : : static void
102 : 3 : test_a_bar (TestA *self)
103 : : {
104 : 3 : record ("TestA::bar");
105 : 3 : }
106 : :
107 : : static gchar *
108 : 3 : test_a_baz (TestA *self,
109 : : GObject *object,
110 : : gpointer pointer)
111 : : {
112 : 3 : record ("TestA::baz");
113 : :
114 : 3 : g_assert_true (object == G_OBJECT (self));
115 : 3 : g_assert_cmpint (GPOINTER_TO_INT (pointer), ==, 23);
116 : :
117 : 3 : return g_strdup ("TestA::baz");
118 : : }
119 : :
120 : : static void
121 : 1 : test_a_class_init (TestAClass *class)
122 : : {
123 : 1 : class->bar = test_a_bar;
124 : :
125 : 1 : bar_signal_id = g_signal_new ("bar",
126 : : TEST_TYPE_A,
127 : : G_SIGNAL_RUN_LAST,
128 : : G_STRUCT_OFFSET (TestAClass, bar),
129 : : NULL, NULL,
130 : : g_cclosure_marshal_VOID__VOID,
131 : : G_TYPE_NONE, 0, NULL);
132 : :
133 : 1 : baz_signal_id =
134 : 1 : g_signal_new_class_handler ("baz",
135 : : TEST_TYPE_A,
136 : : G_SIGNAL_RUN_LAST,
137 : : G_CALLBACK (test_a_baz),
138 : : NULL, NULL,
139 : : g_cclosure_marshal_STRING__OBJECT_POINTER,
140 : : G_TYPE_STRING, 2,
141 : : G_TYPE_OBJECT,
142 : : G_TYPE_POINTER);
143 : 1 : }
144 : :
145 : : static void
146 : 1 : test_a_interface_init (TestIClass *iface)
147 : : {
148 : 1 : g_signal_override_class_closure (foo_signal_id,
149 : : TEST_TYPE_A,
150 : : g_cclosure_new (G_CALLBACK (test_a_foo),
151 : : NULL, NULL));
152 : 1 : }
153 : :
154 : 16 : static DEFINE_TYPE_FULL (TestA, test_a,
155 : : test_a_class_init, NULL, NULL,
156 : : G_TYPE_OBJECT,
157 : : INTERFACE (test_a_interface_init, TEST_TYPE_I))
158 : :
159 : : #define TEST_TYPE_B (test_b_get_type())
160 : :
161 : : typedef struct _TestB TestB;
162 : : typedef struct _TestBClass TestBClass;
163 : :
164 : : struct _TestB {
165 : : TestA parent;
166 : : };
167 : : struct _TestBClass {
168 : : TestAClass parent_class;
169 : : };
170 : :
171 : : static void
172 : 2 : test_b_foo (TestI *self)
173 : : {
174 : 2 : GValue args[1] = { G_VALUE_INIT };
175 : :
176 : 2 : record ("TestB::foo");
177 : :
178 : 2 : g_value_init (&args[0], TEST_TYPE_A);
179 : 2 : g_value_set_object (&args[0], self);
180 : :
181 : 2 : g_assert_cmpint (g_signal_get_invocation_hint (self)->signal_id,
182 : : ==,
183 : : foo_signal_id);
184 : 2 : g_signal_chain_from_overridden (args, NULL);
185 : :
186 : 2 : g_value_unset (&args[0]);
187 : 2 : }
188 : :
189 : : static void
190 : 2 : test_b_bar (TestA *self)
191 : : {
192 : 2 : GValue args[1] = { G_VALUE_INIT };
193 : :
194 : 2 : record ("TestB::bar");
195 : :
196 : 2 : g_value_init (&args[0], TEST_TYPE_A);
197 : 2 : g_value_set_object (&args[0], self);
198 : :
199 : 2 : g_assert_cmpint (g_signal_get_invocation_hint (self)->signal_id,
200 : : ==,
201 : : bar_signal_id);
202 : 2 : g_signal_chain_from_overridden (args, NULL);
203 : :
204 : 2 : g_value_unset (&args[0]);
205 : 2 : }
206 : :
207 : : static gchar *
208 : 2 : test_b_baz (TestA *self,
209 : : GObject *object,
210 : : gpointer pointer)
211 : : {
212 : 2 : gchar *retval = NULL;
213 : :
214 : 2 : record ("TestB::baz");
215 : :
216 : 2 : g_assert_true (object == G_OBJECT (self));
217 : 2 : g_assert_cmpint (GPOINTER_TO_INT (pointer), ==, 23);
218 : :
219 : 2 : g_signal_chain_from_overridden_handler (self, object, pointer, &retval);
220 : :
221 : 2 : if (retval)
222 : : {
223 : 2 : gchar *tmp = g_strconcat (retval , ",TestB::baz", NULL);
224 : 2 : g_free (retval);
225 : 2 : retval = tmp;
226 : : }
227 : :
228 : 2 : return retval;
229 : : }
230 : :
231 : : static void
232 : 1 : test_b_class_init (TestBClass *class)
233 : : {
234 : 1 : g_signal_override_class_closure (foo_signal_id,
235 : : TEST_TYPE_B,
236 : : g_cclosure_new (G_CALLBACK (test_b_foo),
237 : : NULL, NULL));
238 : 1 : g_signal_override_class_closure (bar_signal_id,
239 : : TEST_TYPE_B,
240 : : g_cclosure_new (G_CALLBACK (test_b_bar),
241 : : NULL, NULL));
242 : 1 : g_signal_override_class_handler ("baz",
243 : : TEST_TYPE_B,
244 : : G_CALLBACK (test_b_baz));
245 : 1 : }
246 : :
247 : 7 : static DEFINE_TYPE (TestB, test_b,
248 : : test_b_class_init, NULL, NULL,
249 : : TEST_TYPE_A)
250 : :
251 : : #define TEST_TYPE_C (test_c_get_type())
252 : :
253 : : typedef struct _TestC TestC;
254 : : typedef struct _TestCClass TestCClass;
255 : :
256 : : struct _TestC {
257 : : TestB parent;
258 : : };
259 : : struct _TestCClass {
260 : : TestBClass parent_class;
261 : : };
262 : :
263 : : static void
264 : 1 : test_c_foo (TestI *self)
265 : : {
266 : 1 : GValue args[1] = { G_VALUE_INIT };
267 : :
268 : 1 : record ("TestC::foo");
269 : :
270 : 1 : g_value_init (&args[0], TEST_TYPE_A);
271 : 1 : g_value_set_object (&args[0], self);
272 : :
273 : 1 : g_assert_cmpint (g_signal_get_invocation_hint (self)->signal_id,
274 : : ==,
275 : : foo_signal_id);
276 : 1 : g_signal_chain_from_overridden (args, NULL);
277 : :
278 : 1 : g_value_unset (&args[0]);
279 : 1 : }
280 : :
281 : : static void
282 : 1 : test_c_bar (TestA *self)
283 : : {
284 : 1 : GValue args[1] = { G_VALUE_INIT };
285 : :
286 : 1 : record ("TestC::bar");
287 : :
288 : 1 : g_value_init (&args[0], TEST_TYPE_A);
289 : 1 : g_value_set_object (&args[0], self);
290 : :
291 : 1 : g_assert_cmpint (g_signal_get_invocation_hint (self)->signal_id,
292 : : ==,
293 : : bar_signal_id);
294 : 1 : g_signal_chain_from_overridden (args, NULL);
295 : :
296 : 1 : g_value_unset (&args[0]);
297 : 1 : }
298 : :
299 : : static gchar *
300 : 1 : test_c_baz (TestA *self,
301 : : GObject *object,
302 : : gpointer pointer)
303 : : {
304 : 1 : gchar *retval = NULL;
305 : :
306 : 1 : record ("TestC::baz");
307 : :
308 : 1 : g_assert_true (object == G_OBJECT (self));
309 : 1 : g_assert_cmpint (GPOINTER_TO_INT (pointer), ==, 23);
310 : :
311 : 1 : g_signal_chain_from_overridden_handler (self, object, pointer, &retval);
312 : :
313 : 1 : if (retval)
314 : : {
315 : 1 : gchar *tmp = g_strconcat (retval , ",TestC::baz", NULL);
316 : 1 : g_free (retval);
317 : 1 : retval = tmp;
318 : : }
319 : :
320 : 1 : return retval;
321 : : }
322 : :
323 : : static void
324 : 1 : test_c_class_init (TestBClass *class)
325 : : {
326 : 1 : g_signal_override_class_closure (foo_signal_id,
327 : : TEST_TYPE_C,
328 : : g_cclosure_new (G_CALLBACK (test_c_foo),
329 : : NULL, NULL));
330 : 1 : g_signal_override_class_closure (bar_signal_id,
331 : : TEST_TYPE_C,
332 : : g_cclosure_new (G_CALLBACK (test_c_bar),
333 : : NULL, NULL));
334 : 1 : g_signal_override_class_handler ("baz",
335 : : TEST_TYPE_C,
336 : : G_CALLBACK (test_c_baz));
337 : 1 : }
338 : :
339 : :
340 : 6 : static DEFINE_TYPE (TestC, test_c,
341 : : test_c_class_init, NULL, NULL,
342 : : TEST_TYPE_B)
343 : :
344 : : static GString *test_string = NULL;
345 : :
346 : : static void
347 : 21 : record (const gchar *str)
348 : : {
349 : 21 : if (test_string->len)
350 : 12 : g_string_append_c (test_string, ',');
351 : 21 : g_string_append (test_string, str);
352 : 21 : }
353 : :
354 : : static void
355 : 9 : test (GType type,
356 : : const gchar *signal,
357 : : const gchar *expected,
358 : : const gchar *expected_retval)
359 : : {
360 : 9 : GObject *self = g_object_new (type, NULL);
361 : :
362 : 9 : test_string = g_string_new (NULL);
363 : :
364 : 9 : if (strcmp (signal, "baz"))
365 : : {
366 : 6 : g_signal_emit_by_name (self, signal);
367 : : }
368 : : else
369 : : {
370 : : gchar *ret;
371 : :
372 : 3 : g_signal_emit_by_name (self, signal, self, GINT_TO_POINTER (23), &ret);
373 : 3 : g_assert_cmpstr (ret, ==, expected_retval);
374 : :
375 : 3 : g_free (ret);
376 : : }
377 : :
378 : 9 : g_test_message ("*** emitting %s on a %s instance\n"
379 : : " Expecting: %s\n"
380 : : " Got: %s",
381 : : signal, g_type_name (type),
382 : : expected,
383 : 9 : test_string->str);
384 : :
385 : 9 : g_assert_cmpstr (test_string->str, ==, expected);
386 : :
387 : 9 : g_string_free (test_string, TRUE);
388 : 9 : g_object_unref (self);
389 : 9 : }
390 : :
391 : : static void
392 : 1 : test_override (void)
393 : : {
394 : 1 : test (TEST_TYPE_A, "foo", "TestA::foo,TestI::foo", NULL);
395 : 1 : test (TEST_TYPE_A, "bar", "TestA::bar", NULL);
396 : 1 : test (TEST_TYPE_A, "baz", "TestA::baz", "TestA::baz");
397 : :
398 : 1 : test (TEST_TYPE_B, "foo", "TestB::foo,TestA::foo,TestI::foo", NULL);
399 : 1 : test (TEST_TYPE_B, "bar", "TestB::bar,TestA::bar", NULL);
400 : 1 : test (TEST_TYPE_B, "baz", "TestB::baz,TestA::baz", "TestA::baz,TestB::baz");
401 : :
402 : 1 : test (TEST_TYPE_C, "foo", "TestC::foo,TestB::foo,TestA::foo,TestI::foo", NULL);
403 : 1 : test (TEST_TYPE_C, "bar", "TestC::bar,TestB::bar,TestA::bar", NULL);
404 : 1 : test (TEST_TYPE_C, "baz", "TestC::baz,TestB::baz,TestA::baz", "TestA::baz,TestB::baz,TestC::baz");
405 : 1 : }
406 : :
407 : : int
408 : 1 : main (int argc,
409 : : char **argv)
410 : : {
411 : 1 : g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
412 : 1 : G_LOG_LEVEL_WARNING |
413 : : G_LOG_LEVEL_CRITICAL);
414 : :
415 : 1 : g_test_init (&argc, &argv, NULL);
416 : :
417 : 1 : g_test_add_func ("/gobject/override", test_override);
418 : :
419 : 1 : return g_test_run ();
420 : : }
|